summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/v60/v60.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/v60/v60.cpp')
-rw-r--r--src/devices/cpu/v60/v60.cpp619
1 files changed, 619 insertions, 0 deletions
diff --git a/src/devices/cpu/v60/v60.cpp b/src/devices/cpu/v60/v60.cpp
new file mode 100644
index 00000000000..2a770739e25
--- /dev/null
+++ b/src/devices/cpu/v60/v60.cpp
@@ -0,0 +1,619 @@
+// license:BSD-3-Clause
+// copyright-holders:Farfetch'd, R. Belmont
+// V60.C
+// Undiscover the beast!
+// Main hacking and coding by Farfetch'd
+// Portability fixes by R. Belmont
+//
+// Emulation for the NEC V60 (uPD70615) and V70 (uPD70632) CPUs
+//
+
+/*
+Taken from the NEC Semiconductor Selection Guide Guide Book (Oct. 1995):
+
+uPD70615 (V60)
+Features:
+- Virtual memory (paging method)
+- Level protection architecture - 4-level hierarchical protection function
+ for system multi-programming.
+- Abundant general registers - Thirty two 32-bit general registers for
+ optimizing compiler
+- Refined instruction set - 2-address method: Arbitrary addressing mode
+ can be used independently for source operand and destination operand.
+- Abundant address modes and data types - Auto increment/decrement mode
+ for string process, and memory indirect addressing for pointer operation
+- High cost-to performance chip
+- No multiprocessor system - no FRM function for increasing system
+ reliability using two or more processors.
+- No V20/V30 simulation mode
+Address bus: 24 bits
+Data bus: 16 bits
+Memory space: 4G bytes
+Operating frequency: 16 MHz
+Package: 120-pin QFP
+
+uPD70616 (V60)
+Features:
+- Virtual memory (paging method)
+- Level protection architecture - 4-level hierarchical protection function
+ for system multi-programming.
+- Abundant general registers - Thirty two 32-bit general registers for
+ optimizing compiler
+- Refined instruction set - 2-address method: Arbitrary addressing mode
+ can be used independently for source operand and destination operand.
+- Abundant address modes and data types - Auto increment/decrement mode
+ for string process, and memory indirect addressing for pointer operation
+- Multiprocessor system - FRM function for increasing system reliability
+ using two or more processors.
+- V20/V30 simulation mode
+Address bus: 24 bits
+Data bus: 16 bits
+Memory space: 4G bytes
+Operating frequency: 16 MHz
+Package: 68-pin PGA
+
+uPD70632 (V70)
+Features:
+- Virtual memory (paging method)
+- Level protection architecture - 4-level hierarchical protection function
+ for system multi-programming.
+- Abundant general registers - Thirty two 32-bit general registers for
+ optimizing compiler
+- Refined instruction set - 2-address method: Arbitrary addressing mode
+ can be used independently for source operand and destination operand.
+- Abundant address modes and data types - Auto increment/decrement mode
+ for string process, and memory indirect addressing for pointer operation
+- Multiprocessor system - FRM function for increasing system reliability
+ using two or more processors.
+- V20/V30 simulation mode
+Address bus: 32 bits
+Data bus: 32 bits
+Memory space: 4G bytes
+Operating frequency: 20 MHz
+Package: 132-pin PGA, 200-pin QFP
+*/
+
+#include "emu.h"
+#include "debugger.h"
+#include "v60.h"
+
+const device_type V60 = &device_creator<v60_device>;
+const device_type V70 = &device_creator<v70_device>;
+
+
+v60_device::v60_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, V60, "V60", tag, owner, clock, "v60", __FILE__)
+ , m_program_config("program", ENDIANNESS_LITTLE, 16, 24, 0)
+ , m_io_config("io", ENDIANNESS_LITTLE, 16, 24, 0)
+ , m_fetch_xor(BYTE_XOR_LE(0))
+ , m_start_pc(0xfffff0)
+{
+ // Set m_PIR (Processor ID) for NEC m_ LSB is reserved to NEC,
+ // so I don't know what it contains.
+ m_reg[45] = 0x00006000;
+}
+
+
+v60_device::v60_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
+ : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source)
+ , m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0)
+ , m_io_config("io", ENDIANNESS_LITTLE, 16, 24, 0)
+ , m_fetch_xor(BYTE4_XOR_LE(0))
+ , m_start_pc(0xfffffff0)
+{
+ // Set m_PIR (Processor ID) for NEC v70. LSB is reserved to NEC,
+ // so I don't know what it contains.
+ m_reg[45] = 0x00007000;
+}
+
+v70_device::v70_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : v60_device(mconfig, V70, "V70", tag, owner, clock, "v70", __FILE__)
+{
+}
+
+
+offs_t v60_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( v60 );
+ return CPU_DISASSEMBLE_NAME(v60)(this, buffer, pc, oprom, opram, options);
+}
+
+
+offs_t v70_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options)
+{
+ extern CPU_DISASSEMBLE( v70 );
+ return CPU_DISASSEMBLE_NAME(v70)(this, buffer, pc, oprom, opram, options);
+}
+
+
+// memory accessors
+#if defined(LSB_FIRST) && !defined(ALIGN_INTS)
+#define OpRead8(a) (m_direct->read_byte(a))
+#define OpRead16(a) (m_direct->read_word(a))
+#define OpRead32(a) (m_direct->read_dword(a))
+#else
+#define OpRead8(a) (m_direct->read_byte((a), m_fetch_xor))
+#define OpRead16(a) ((m_direct->read_byte(((a)+0), m_fetch_xor) << 0) | \
+ (m_direct->read_byte(((a)+1), m_fetch_xor) << 8))
+#define OpRead32(a) ((m_direct->read_byte(((a)+0), m_fetch_xor) << 0) | \
+ (m_direct->read_byte(((a)+1), m_fetch_xor) << 8) | \
+ (m_direct->read_byte(((a)+2), m_fetch_xor) << 16) | \
+ (m_direct->read_byte(((a)+3), m_fetch_xor) << 24))
+#endif
+
+
+// macros stolen from MAME for flags calc
+// note that these types are in x86 naming:
+// byte = 8 bit, word = 16 bit, long = 32 bit
+
+// parameter x = result, y = source 1, z = source 2
+
+#define SetOFL_Add(x, y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80000000) ? 1: 0)
+#define SetOFW_Add(x, y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x8000) ? 1 : 0)
+#define SetOFB_Add(x, y,z) (_OV = (((x) ^ (y)) & ((x) ^ (z)) & 0x80) ? 1 : 0)
+
+#define SetOFL_Sub(x, y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80000000) ? 1 : 0)
+#define SetOFW_Sub(x, y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x8000) ? 1 : 0)
+#define SetOFB_Sub(x, y,z) (_OV = (((z) ^ (y)) & ((z) ^ (x)) & 0x80) ? 1 : 0)
+
+#define SetCFB(x) {_CY = ((x) & 0x100) ? 1 : 0; }
+#define SetCFW(x) {_CY = ((x) & 0x10000) ? 1 : 0; }
+#define SetCFL(x) {_CY = ((x) & (((UINT64)1) << 32)) ? 1 : 0; }
+
+#define SetSF(x) (_S = (x))
+#define SetZF(x) (_Z = (x))
+
+#define SetSZPF_Byte(x) {_Z = ((UINT8)(x) == 0); _S = ((x)&0x80) ? 1 : 0; }
+#define SetSZPF_Word(x) {_Z = ((UINT16)(x) == 0); _S = ((x)&0x8000) ? 1 : 0; }
+#define SetSZPF_Long(x) {_Z = ((UINT32)(x) == 0); _S = ((x)&0x80000000) ? 1 : 0; }
+
+#define ORB(dst, src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
+#define ORW(dst, src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
+#define ORL(dst, src) { (dst) |= (src); _CY = _OV = 0; SetSZPF_Long(dst); }
+
+#define ANDB(dst, src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
+#define ANDW(dst, src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
+#define ANDL(dst, src) { (dst) &= (src); _CY = _OV = 0; SetSZPF_Long(dst); }
+
+#define XORB(dst, src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Byte(dst); }
+#define XORW(dst, src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Word(dst); }
+#define XORL(dst, src) { (dst) ^= (src); _CY = _OV = 0; SetSZPF_Long(dst); }
+
+#define SUBB(dst, src) { unsigned res = (dst) - (src); SetCFB(res); SetOFB_Sub(res, src, dst); SetSZPF_Byte(res); dst = (UINT8)res; }
+#define SUBW(dst, src) { unsigned res = (dst) - (src); SetCFW(res); SetOFW_Sub(res, src, dst); SetSZPF_Word(res); dst = (UINT16)res; }
+#define SUBL(dst, src) { UINT64 res = (UINT64)(dst) - (INT64)(src); SetCFL(res); SetOFL_Sub(res, src, dst); SetSZPF_Long(res); dst = (UINT32)res; }
+
+#define ADDB(dst, src) { unsigned res = (dst) + (src); SetCFB(res); SetOFB_Add(res, src, dst); SetSZPF_Byte(res); dst = (UINT8)res; }
+#define ADDW(dst, src) { unsigned res = (dst) + (src); SetCFW(res); SetOFW_Add(res, src, dst); SetSZPF_Word(res); dst = (UINT16)res; }
+#define ADDL(dst, src) { UINT64 res = (UINT64)(dst) + (UINT64)(src); SetCFL(res); SetOFL_Add(res, src, dst); SetSZPF_Long(res); dst = (UINT32)res; }
+
+#define SETREG8(a, b) (a) = ((a) & ~0xff) | ((b) & 0xff)
+#define SETREG16(a, b) (a) = ((a) & ~0xffff) | ((b) & 0xffff)
+
+
+/*
+ * Prevent warnings on NetBSD. All identifiers beginning with an underscore
+ * followed by an uppercase letter are reserved by the C standard (ISO / IEC
+ * 9899:1999, 7.1.3) to be used by the implementation. It'd be best to rename
+ * all such instances, but this is less intrusive and error-prone.
+ */
+#undef _S
+
+#define _CY m_flags.CY
+#define _OV m_flags.OV
+#define _S m_flags.S
+#define _Z m_flags.Z
+
+
+// Defines of all v60 register...
+#define R0 m_reg[0]
+#define R1 m_reg[1]
+#define R2 m_reg[2]
+#define R3 m_reg[3]
+#define R4 m_reg[4]
+#define R5 m_reg[5]
+#define R6 m_reg[6]
+#define R7 m_reg[7]
+#define R8 m_reg[8]
+#define R9 m_reg[9]
+#define R10 m_reg[10]
+#define R11 m_reg[11]
+#define R12 m_reg[12]
+#define R13 m_reg[13]
+#define R14 m_reg[14]
+#define R15 m_reg[15]
+#define R16 m_reg[16]
+#define R17 m_reg[17]
+#define R18 m_reg[18]
+#define R19 m_reg[19]
+#define R20 m_reg[20]
+#define R21 m_reg[21]
+#define R22 m_reg[22]
+#define R23 m_reg[23]
+#define R24 m_reg[24]
+#define R25 m_reg[25]
+#define R26 m_reg[26]
+#define R27 m_reg[27]
+#define R28 m_reg[28]
+#define AP m_reg[29]
+#define FP m_reg[30]
+#define SP m_reg[31]
+
+#define PC m_reg[32]
+#define PSW m_reg[33]
+
+// Privileged registers
+#define ISP m_reg[36]
+#define L0SP m_reg[37]
+#define L1SP m_reg[38]
+#define L2SP m_reg[39]
+#define L3SP m_reg[40]
+#define SBR m_reg[41]
+#define TR m_reg[42]
+#define SYCW m_reg[43]
+#define TKCW m_reg[44]
+#define PIR m_reg[45]
+//10-14 reserved
+#define PSW2 m_reg[51]
+#define ATBR0 m_reg[52]
+#define ATLR0 m_reg[53]
+#define ATBR1 m_reg[54]
+#define ATLR1 m_reg[55]
+#define ATBR2 m_reg[56]
+#define ATLR2 m_reg[57]
+#define ATBR3 m_reg[58]
+#define ATLR3 m_reg[59]
+#define TRMODE m_reg[60]
+#define ADTR0 m_reg[61]
+#define ADTR1 m_reg[62]
+#define ADTMR0 m_reg[63]
+#define ADTMR1 m_reg[64]
+//29-31 reserved
+
+// Defines...
+#define NORMALIZEFLAGS() \
+{ \
+ _S = _S ? 1 : 0; \
+ _OV = _OV ? 1 : 0; \
+ _Z = _Z ? 1 : 0; \
+ _CY = _CY ? 1 : 0; \
+}
+
+
+void v60_device::v60SaveStack()
+{
+ if (PSW & 0x10000000)
+ ISP = SP;
+ else
+ m_reg[37 + ((PSW >> 24) & 3)] = SP;
+}
+
+void v60_device::v60ReloadStack()
+{
+ if (PSW & 0x10000000)
+ SP = ISP;
+ else
+ SP = m_reg[37 + ((PSW >> 24) & 3)];
+}
+
+UINT32 v60_device::v60ReadPSW()
+{
+ PSW &= 0xfffffff0;
+ PSW |= (_Z?1:0) | (_S?2:0) | (_OV?4:0) | (_CY?8:0);
+ return PSW;
+}
+
+void v60_device::v60WritePSW(UINT32 newval)
+{
+ /* determine if we need to save / restore the stacks */
+ int updateStack = 0;
+
+ /* if the interrupt state is changing, we definitely need to update */
+ if ((newval ^ PSW) & 0x10000000)
+ updateStack = 1;
+
+ /* if we are not in interrupt mode and the level is changing, we also must update */
+ else if (!(PSW & 0x10000000) && ((newval ^ PSW) & 0x03000000))
+ updateStack = 1;
+
+ /* save the previous stack value */
+ if (updateStack)
+ v60SaveStack();
+
+ /* set the new value and update the flags */
+ PSW = newval;
+ _Z = (UINT8)(PSW & 1);
+ _S = (UINT8)(PSW & 2);
+ _OV = (UINT8)(PSW & 4);
+ _CY = (UINT8)(PSW & 8);
+
+ /* fetch the new stack value */
+ if (updateStack)
+ v60ReloadStack();
+}
+
+
+UINT32 v60_device::v60_update_psw_for_exception(int is_interrupt, int target_level)
+{
+ UINT32 oldPSW = v60ReadPSW();
+ UINT32 newPSW = oldPSW;
+
+ // Change to interrupt context
+ newPSW &= ~(3 << 24); // PSW.EL = 0
+ newPSW |= target_level << 24; // set target level
+ newPSW &= ~(1 << 18); // PSW.IE = 0
+ newPSW &= ~(1 << 16); // PSW.TE = 0
+ newPSW &= ~(1 << 27); // PSW.TP = 0
+ newPSW &= ~(1 << 17); // PSW.AE = 0
+ newPSW &= ~(1 << 29); // PSW.EM = 0
+ if (is_interrupt)
+ newPSW |= (1 << 28);// PSW.IS = 1
+ newPSW |= (1 << 31); // PSW.ASA = 1
+ v60WritePSW(newPSW);
+
+ return oldPSW;
+}
+
+
+#define GETINTVECT(nint) m_program->read_dword((SBR & ~0xfff) + (nint) * 4)
+#define EXCEPTION_CODE_AND_SIZE(code, size) (((code) << 16) | (size))
+
+
+// Addressing mode decoding functions
+#include "am.inc"
+
+// Opcode functions
+#include "op12.inc"
+#include "op2.inc"
+#include "op3.inc"
+#include "op4.inc"
+#include "op5.inc"
+#include "op6.inc"
+#include "op7a.inc"
+
+UINT32 v60_device::opUNHANDLED()
+{
+ fatalerror("Unhandled OpCode found : %02x at %08x\n", OpRead16(PC), PC);
+ //return 0; /* never reached, fatalerror won't return */
+}
+
+// Opcode jump table
+#include "optable.inc"
+
+void v60_device::device_start()
+{
+ m_stall_io = 0;
+ m_irq_line = CLEAR_LINE;
+ m_nmi_line = CLEAR_LINE;
+
+ for ( int i = 0; i < 68; i++ )
+ {
+ // Don't set SP (31), PCi (32), PSW (33), SBR (41), SYCW (43), TKCW (44), PIR (45), PSW2 (51)
+ if ( i != 31 && i != 32 && i != 33 && i != 41 && i != 43 && i != 44 && i != 45 && i != 51 )
+ {
+ m_reg[i] = 0;
+ }
+ }
+
+ m_flags.CY = 0;
+ m_flags.OV = 0;
+ m_flags.S = 0;
+ m_flags.Z = 0;
+
+ m_op1 = 0;
+ m_op2 = 0;
+ m_flag1 = 0;
+ m_flag2 = 0;
+ m_instflags = 0;
+ m_lenop1 = 0;
+ m_lenop2 = 0;
+ m_subop = 0;
+ m_bamoffset1 = 0;
+ m_bamoffset2 = 0;
+ m_amflag = 0;
+ m_amout = 0;
+ m_bamoffset = 0;
+ m_amlength1 = 0;
+ m_amlength2 = 0;
+ m_modadd = 0;
+ m_modm = 0;
+ m_modval = 0;
+ m_modval2 = 0;
+ m_modwritevalb = 0;
+ m_modwritevalh = 0;
+ m_modwritevalw = 0;
+ m_moddim = 0;
+
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+ m_io = &space(AS_IO);
+
+ save_item(NAME(m_reg));
+ save_item(NAME(m_irq_line));
+ save_item(NAME(m_nmi_line));
+ save_item(NAME(m_PPC));
+ save_item(NAME(_CY));
+ save_item(NAME(_OV));
+ save_item(NAME(_S));
+ save_item(NAME(_Z));
+
+ state_add( V60_R0, "R0", R0).formatstr("%08X");
+ state_add( V60_R1, "R1", R1).formatstr("%08X");
+ state_add( V60_R2, "R2", R2).formatstr("%08X");
+ state_add( V60_R3, "R3", R3).formatstr("%08X");
+ state_add( V60_R4, "R4", R4).formatstr("%08X");
+ state_add( V60_R5, "R5", R5).formatstr("%08X");
+ state_add( V60_R6, "R6", R6).formatstr("%08X");
+ state_add( V60_R7, "R7", R7).formatstr("%08X");
+ state_add( V60_R8, "R8", R8).formatstr("%08X");
+ state_add( V60_R9, "R9", R9).formatstr("%08X");
+ state_add( V60_R10, "R10", R10).formatstr("%08X");
+ state_add( V60_R11, "R11", R11).formatstr("%08X");
+ state_add( V60_R12, "R12", R12).formatstr("%08X");
+ state_add( V60_R13, "R13", R13).formatstr("%08X");
+ state_add( V60_R14, "R14", R14).formatstr("%08X");
+ state_add( V60_R15, "R15", R15).formatstr("%08X");
+ state_add( V60_R16, "R16", R16).formatstr("%08X");
+ state_add( V60_R17, "R17", R17).formatstr("%08X");
+ state_add( V60_R18, "R18", R18).formatstr("%08X");
+ state_add( V60_R19, "R19", R19).formatstr("%08X");
+ state_add( V60_R20, "R20", R20).formatstr("%08X");
+ state_add( V60_R21, "R21", R21).formatstr("%08X");
+ state_add( V60_R22, "R22", R22).formatstr("%08X");
+ state_add( V60_R23, "R23", R23).formatstr("%08X");
+ state_add( V60_R24, "R24", R24).formatstr("%08X");
+ state_add( V60_R25, "R25", R25).formatstr("%08X");
+ state_add( V60_R26, "R26", R26).formatstr("%08X");
+ state_add( V60_R27, "R27", R27).formatstr("%08X");
+ state_add( V60_R28, "R28", R28).formatstr("%08X");
+ state_add( V60_AP, "AP", AP).formatstr("%08X");
+ state_add( V60_FP, "FP", FP).formatstr("%08X");
+ state_add( V60_SP, "SP", SP).formatstr("%08X");
+ state_add( V60_PC, "PC", PC).formatstr("%08X");
+ state_add( V60_PSW, "PSW", m_debugger_temp).callimport().callexport().formatstr("%08X");
+ state_add( V60_ISP, "ISP", ISP).formatstr("%08X");
+ state_add( V60_L0SP, "L0SP", L0SP).formatstr("%08X");
+ state_add( V60_L1SP, "L1SP", L1SP).formatstr("%08X");
+ state_add( V60_L2SP, "L2SP", L2SP).formatstr("%08X");
+ state_add( V60_L3SP, "L3SP", L3SP).formatstr("%08X");
+ state_add( V60_SBR, "SBR", SBR).formatstr("%08X");
+ state_add( V60_TR, "TR", TR).formatstr("%08X");
+ state_add( V60_SYCW, "SYCW", SYCW).formatstr("%08X");
+ state_add( V60_TKCW, "TKCW", TKCW).formatstr("%08X");
+ state_add( V60_PIR, "PIR", PIR).formatstr("%08X");
+ state_add( V60_PSW2, "PSW2", PSW2).formatstr("%08X");
+ state_add( V60_ATBR0, "ATBR0", ATBR0).formatstr("%08X");
+ state_add( V60_ATLR0, "ATLR0", ATLR0).formatstr("%08X");
+ state_add( V60_ATBR1, "ATBR1", ATBR1).formatstr("%08X");
+ state_add( V60_ATLR1, "ATLR1", ATLR1).formatstr("%08X");
+ state_add( V60_ATBR2, "ATBR2", ATBR2).formatstr("%08X");
+ state_add( V60_ATLR2, "ATLR2", ATLR2).formatstr("%08X");
+ state_add( V60_ATBR3, "ATBR3", ATBR3).formatstr("%08X");
+ state_add( V60_ATLR3, "ATLR3", ATLR3).formatstr("%08X");
+ state_add( V60_TRMODE, "TRMODE", TRMODE).formatstr("%08X");
+ state_add( V60_ADTR0, "ADTR0", ADTR0).formatstr("%08X");
+ state_add( V60_ADTR1, "ADTR1", ADTR1).formatstr("%08X");
+ state_add( V60_ADTMR0, "ADTMR0", ADTMR0).formatstr("%08X");
+ state_add( V60_ADTMR1, "ADTMR1", ADTMR1).formatstr("%08X");
+
+ state_add( STATE_GENPC, "GENPC", PC).noshow();
+ state_add( STATE_GENPCBASE, "GENPCBASE", m_PPC ).noshow();
+ state_add( STATE_GENSP, "GENSP", SP ).noshow();
+ state_add( STATE_GENFLAGS, "GENFLAGS", m_debugger_temp).noshow();
+
+ m_icountptr = &m_icount;
+}
+
+
+void v60_device::state_export(const device_state_entry &entry)
+{
+ switch (entry.index())
+ {
+ case V60_PSW:
+ m_debugger_temp = v60ReadPSW();
+ break;
+ }
+}
+
+
+void v60_device::state_import(const device_state_entry &entry)
+{
+ switch (entry.index())
+ {
+ case V60_PSW:
+ v60WritePSW( m_debugger_temp );
+ break;
+ }
+}
+
+
+void v60_device::device_reset()
+{
+ PSW = 0x10000000;
+ PC = m_start_pc;
+ SBR = 0x00000000;
+ SYCW = 0x00000070;
+ TKCW = 0x0000e000;
+ PSW2 = 0x0000f002;
+
+ _CY = 0;
+ _OV = 0;
+ _S = 0;
+ _Z = 0;
+}
+
+
+void v60_device::stall()
+{
+ m_stall_io = 1;
+}
+
+
+void v60_device::v60_do_irq(int vector)
+{
+ UINT32 oldPSW = v60_update_psw_for_exception(1, 0);
+
+ // Push PC and PSW onto the stack
+ SP-=4;
+ m_program->write_dword_unaligned(SP, oldPSW);
+ SP-=4;
+ m_program->write_dword_unaligned(SP, PC);
+
+ // Jump to vector for user interrupt
+ PC = GETINTVECT(vector);
+}
+
+void v60_device::v60_try_irq()
+{
+ if(m_irq_line == CLEAR_LINE)
+ return;
+ if((PSW & (1 << 18)) != 0) {
+ int vector;
+ if(m_irq_line != ASSERT_LINE)
+ m_irq_line = CLEAR_LINE;
+
+ vector = standard_irq_callback(0);
+
+ v60_do_irq(vector + 0x40);
+ }
+}
+
+void v60_device::execute_set_input(int irqline, int state)
+{
+ if(irqline == INPUT_LINE_NMI) {
+ switch(state) {
+ case ASSERT_LINE:
+ if(m_nmi_line == CLEAR_LINE) {
+ m_nmi_line = ASSERT_LINE;
+ v60_do_irq(2);
+ }
+ break;
+ case CLEAR_LINE:
+ m_nmi_line = CLEAR_LINE;
+ break;
+ }
+ } else {
+ m_irq_line = state;
+ v60_try_irq();
+ }
+}
+
+// Actual cycles / instruction is unknown
+
+void v60_device::execute_run()
+{
+ if (m_irq_line != CLEAR_LINE)
+ v60_try_irq();
+
+ while (m_icount > 0)
+ {
+ UINT32 inc;
+ m_PPC = PC;
+ debugger_instruction_hook(this, PC);
+ m_icount -= 8; /* fix me -- this is just an average */
+ inc = (this->*s_OpCodeTable[OpRead8(PC)])();
+ PC += inc;
+ if (m_irq_line != CLEAR_LINE)
+ v60_try_irq();
+ }
+}