// license:BSD-3-Clause // copyright-holders:Juergen Buchmueller,Ernesto Corvi /***************************************************************************** * * z8000.c * Portable Z8000(2) emulator * Z8000 MAME interface * * TODO: * - make the z8001 opcodes to be dynamic (i.e. to take segmented mode flag into account and use the non-segmented mode) * - dissassembler doesn't work at all with the z8001 * *****************************************************************************/ #include "emu.h" #include "debugger.h" #include "debug/debugcon.h" #include "z8000.h" #define VERBOSE 0 #define LOG(x) do { if (VERBOSE) logerror x; } while (0) extern int z8k_segm; extern int z8k_segm_mode; #include "z8000cpu.h" const device_type Z8001 = &device_creator; const device_type Z8002 = &device_creator; z8002_device::z8002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, Z8002, "Z8002", tag, owner, clock, "z8002", __FILE__) , z80_daisy_chain_interface(mconfig, *this) , m_program_config("program", ENDIANNESS_BIG, 16, 16, 0) , m_io_config("io", ENDIANNESS_BIG, 8, 16, 0) , m_mo_out(*this), m_ppc(0), m_pc(0), m_psapseg(0), m_psapoff(0), m_fcw(0), m_refresh(0), m_nspseg(0), m_nspoff(0), m_irq_req(0), m_irq_vec(0), m_op_valid(0), m_nmi_state(0), m_mi(0), m_program(nullptr), m_data(nullptr), m_direct(nullptr), m_io(nullptr), m_icount(0) , m_vector_mult(1) { } z8002_device::z8002_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source) : cpu_device(mconfig, type, name, tag, owner, clock, shortname, source) , z80_daisy_chain_interface(mconfig, *this) , m_program_config("program", ENDIANNESS_BIG, 16, 20, 0) , m_io_config("io", ENDIANNESS_BIG, 16, 16, 0) , m_mo_out(*this), m_ppc(0), m_pc(0), m_psapseg(0), m_psapoff(0), m_fcw(0), m_refresh(0), m_nspseg(0), m_nspoff(0), m_irq_req(0), m_irq_vec(0), m_op_valid(0), m_nmi_state(0), m_mi(0), m_program(nullptr), m_data(nullptr), m_direct(nullptr), m_io(nullptr), m_icount(0) , m_vector_mult(2) { } z8001_device::z8001_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : z8002_device(mconfig, Z8001, "Zilog Z8001", tag, owner, clock, "z8001", __FILE__) , m_data_config("data", ENDIANNESS_BIG, 16, 20, 0) { } offs_t z8002_device::disasm_disassemble(char *buffer, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) { extern CPU_DISASSEMBLE( z8000 ); return CPU_DISASSEMBLE_NAME(z8000)(this, buffer, pc, oprom, opram, options); } /* opcode execution table */ Z8000_exec *z8000_exec = nullptr; /* zero, sign and parity flags for logical byte operations */ static uint8_t z8000_zsp[256]; int z8002_device::segmented_mode() { return 0; } int z8001_device::segmented_mode() { return (m_fcw & F_SEG) ? 1 : 0; } uint32_t z8002_device::addr_add(uint32_t addr, uint32_t addend) { return (addr & 0xffff0000) | ((addr + addend) & 0xffff); } uint32_t z8002_device::addr_sub(uint32_t addr, uint32_t subtrahend) { return (addr & 0xffff0000) | ((addr - subtrahend) & 0xffff); } /* conversion table for Z8000 DAB opcode */ #include "z8000dab.h" uint16_t z8002_device::RDOP() { uint16_t res = m_program->read_word(m_pc); m_pc += 2; return res; } uint32_t z8002_device::get_operand(int opnum) { int i; for (i = 0; i < opnum; i++) { assert (m_op_valid & (1 << i)); } if (! (m_op_valid & (1 << opnum))) { m_op[opnum] = m_program->read_word(m_pc); m_pc += 2; m_op_valid |= (1 << opnum); } return m_op[opnum]; } uint32_t z8002_device::get_addr_operand(int opnum) { int i; for (i = 0; i < opnum; i++) { assert (m_op_valid & (1 << i)); } if (! (m_op_valid & (1 << opnum))) { uint32_t seg = m_program->read_word(m_pc); m_pc += 2; if (segmented_mode()) { if (seg & 0x8000) { m_op[opnum] = ((seg & 0x7f00) << 8) | m_program->read_word(m_pc); m_pc += 2; } else m_op[opnum] = ((seg & 0x7f00) << 8) | (seg & 0xff); } else m_op[opnum] = seg; m_op_valid |= (1 << opnum); } return m_op[opnum]; } uint32_t z8002_device::get_raw_addr_operand(int opnum) { int i; for (i = 0; i < opnum; i++) { assert (m_op_valid & (1 << i)); } if (! (m_op_valid & (1 << opnum))) { uint32_t seg = m_program->read_word(m_pc); m_pc += 2; if (segmented_mode()) { if (seg & 0x8000) { m_op[opnum] = (seg << 16) | m_program->read_word(m_pc); m_pc += 2; } else m_op[opnum] = (seg << 16) | (seg & 0xff); } else m_op[opnum] = seg; m_op_valid |= (1 << opnum); } return m_op[opnum]; } uint32_t z8002_device::adjust_addr_for_nonseg_mode(uint32_t addr) { return addr; } uint32_t z8001_device::adjust_addr_for_nonseg_mode(uint32_t addr) { if (!(m_fcw & F_SEG)) { return (addr & 0xffff) | (m_pc & 0x7f0000); } else { return addr; } } uint8_t z8002_device::RDMEM_B(address_spacenum spacenum, uint32_t addr) { addr = adjust_addr_for_nonseg_mode(addr); if (spacenum == AS_PROGRAM) return m_program->read_byte(addr); else return m_data->read_byte(addr); } uint16_t z8002_device::RDMEM_W(address_spacenum spacenum, uint32_t addr) { addr = adjust_addr_for_nonseg_mode(addr); addr &= ~1; /* hack for m20 driver: BIOS accesses 0x7f0000 and expects a segmentation violation */ if (addr >= 0x7f0000) { m_irq_req = Z8000_SEGTRAP; return 0xffff; } if (spacenum == AS_PROGRAM) return m_program->read_word(addr); else return m_data->read_word(addr); } uint32_t z8002_device::RDMEM_L(address_spacenum spacenum, uint32_t addr) { uint32_t result; addr = adjust_addr_for_nonseg_mode(addr); addr &= ~1; if (spacenum == AS_PROGRAM) { result = m_program->read_word(addr) << 16; return result + m_program->read_word(addr_add(addr, 2)); } else { result = m_data->read_word(addr) << 16; return result + m_data->read_word(addr_add(addr, 2)); } } void z8002_device::WRMEM_B(address_spacenum spacenum, uint32_t addr, uint8_t value) { addr = adjust_addr_for_nonseg_mode(addr); if (spacenum == AS_PROGRAM) m_program->write_byte(addr, value); else m_data->write_byte(addr, value); } void z8002_device::WRMEM_W(address_spacenum spacenum, uint32_t addr, uint16_t value) { addr = adjust_addr_for_nonseg_mode(addr); addr &= ~1; if (spacenum == AS_PROGRAM) m_program->write_word(addr, value); else m_data->write_word(addr, value); } void z8002_device::WRMEM_L(address_spacenum spacenum, uint32_t addr, uint32_t value) { addr = adjust_addr_for_nonseg_mode(addr); addr &= ~1; if (spacenum == AS_PROGRAM) { m_program->write_word(addr, value >> 16); m_program->write_word(addr_add(addr, 2), value & 0xffff); } else { m_data->write_word(addr, value >> 16); m_data->write_word(addr_add(addr, 2), value & 0xffff); } } uint8_t z8002_device::RDPORT_B(int mode, uint16_t addr) { if(mode == 0) { return m_io->read_byte(addr); } else { /* how to handle MMU reads? for now just do it */ return m_io->read_byte(addr); } } uint16_t z8002_device::RDPORT_W(int mode, uint16_t addr) { if(mode == 0) { return m_io->read_byte((uint16_t)(addr)) + (m_io->read_byte((uint16_t)(addr+1)) << 8); } else { /* how to handle MMU reads? */ return 0x0000; } } uint16_t z8001_device::RDPORT_W(int mode, uint16_t addr) { if(mode == 0) { return m_io->read_word_unaligned((uint16_t)addr); } else { /* how to handle MMU reads? */ return 0x0000; } } void z8002_device::WRPORT_B(int mode, uint16_t addr, uint8_t value) { if(mode == 0) { m_io->write_byte(addr,value); } else { /* how to handle MMU writes? for now just do it */ m_io->write_byte(addr,value); } } void z8002_device::WRPORT_W(int mode, uint16_t addr, uint16_t value) { if(mode == 0) { m_io->write_byte((uint16_t)(addr),value & 0xff); m_io->write_byte((uint16_t)(addr+1),(value >> 8) & 0xff); } else { /* how to handle MMU writes? */ } } void z8001_device::WRPORT_W(int mode, uint16_t addr, uint16_t value) { if(mode == 0) { m_io->write_word_unaligned((uint16_t)addr, value); } else { /* how to handle MMU writes? */ } } void z8002_device::cycles(int cycles) { m_icount -= cycles; } #include "z8000ops.hxx" #include "z8000tbl.hxx" void z8002_device::set_irq(int type) { switch ((type >> 8) & 255) { case Z8000_EPU >> 8: m_irq_req = type; break; case Z8000_TRAP >> 8: m_irq_req = type; break; case Z8000_NMI >> 8: m_irq_req = type; break; case Z8000_SEGTRAP >> 8: m_irq_req = type; break; case Z8000_NVI >> 8: m_irq_req = type; break; case Z8000_VI >> 8: m_irq_req = type; break; case Z8000_SYSCALL >> 8: LOG(("Z8K '%s' SYSCALL $%02x\n", tag(), type & 0xff)); m_irq_req = type; break; default: logerror("Z8000 invalid Cause_Interrupt %04x\n", type); return; } /* set interrupt request flag, reset HALT flag */ m_irq_req = type & ~Z8000_HALT; } void z8002_device::PUSH_PC() { PUSHW(SP, m_pc); /* save current pc */ } void z8001_device::PUSH_PC() { PUSHL(SP, make_segmented_addr(m_pc)); /* save current pc */ } uint32_t z8002_device::GET_PC(uint32_t VEC) { return RDMEM_W(AS_PROGRAM, VEC + 2); } uint32_t z8001_device::GET_PC(uint32_t VEC) { return segmented_addr(RDMEM_L(AS_PROGRAM, VEC + 4)); } uint16_t z8002_device::GET_FCW(uint32_t VEC) { return RDMEM_W(AS_PROGRAM, VEC); } uint16_t z8001_device::GET_FCW(uint32_t VEC) { return RDMEM_W(AS_PROGRAM, VEC + 2); } uint32_t z8002_device::F_SEG_Z8001() { return 0; } uint32_t z8001_device::F_SEG_Z8001() { return F_SEG; } uint32_t z8002_device::PSA_ADDR() { return m_psapoff; } uint32_t z8001_device::PSA_ADDR() { return segmented_addr((m_psapseg << 16) | m_psapoff); } void z8002_device::Interrupt() { uint16_t fcw = m_fcw; if (m_irq_req & Z8000_NVI) { int type = standard_irq_callback(0); set_irq(type | Z8000_NVI); } if (m_irq_req & Z8000_VI) { int type = standard_irq_callback(1); set_irq(type | Z8000_VI); } /* trap ? */ if (m_irq_req & Z8000_EPU) { CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ PUSH_PC(); PUSHW(SP, fcw); /* save current m_fcw */ PUSHW(SP, RDMEM_W(AS_PROGRAM, m_ppc)); /* for internal traps, the 1st word of the instruction is pushed */ m_irq_req &= ~Z8000_EPU; CHANGE_FCW(GET_FCW(EPU)); m_pc = GET_PC(EPU); LOG(("Z8K '%s' ext instr trap $%04x\n", tag(), m_pc)); } else if (m_irq_req & Z8000_TRAP) { CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ PUSH_PC(); PUSHW(SP, fcw); /* save current m_fcw */ PUSHW(SP, RDMEM_W(AS_PROGRAM, m_ppc)); /* for internal traps, the 1st word of the instruction is pushed */ m_irq_req &= ~Z8000_TRAP; CHANGE_FCW(GET_FCW(TRAP)); m_pc = GET_PC(TRAP); LOG(("Z8K '%s' priv instr trap $%04x\n", tag(), m_pc)); } else if (m_irq_req & Z8000_SYSCALL) { CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ PUSH_PC(); PUSHW(SP, fcw); /* save current m_fcw */ PUSHW(SP, RDMEM_W(AS_PROGRAM, m_ppc)); /* for internal traps, the 1st word of the instruction is pushed */ m_irq_req &= ~Z8000_SYSCALL; CHANGE_FCW(GET_FCW(SYSCALL)); m_pc = GET_PC(SYSCALL); LOG(("Z8K '%s' syscall $%04x\n", tag(), m_pc)); } else if (m_irq_req & Z8000_SEGTRAP) { CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ PUSH_PC(); PUSHW(SP, fcw); /* save current m_fcw */ PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ m_irq_req &= ~Z8000_SEGTRAP; CHANGE_FCW(GET_FCW(SEGTRAP)); m_pc = GET_PC(SEGTRAP); LOG(("Z8K '%s' segtrap $%04x\n", tag(), m_pc)); } else if (m_irq_req & Z8000_NMI) { CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ PUSH_PC(); PUSHW(SP, fcw); /* save current m_fcw */ PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ m_pc = RDMEM_W(AS_PROGRAM, NMI); m_irq_req &= ~Z8000_NMI; CHANGE_FCW(GET_FCW(NMI)); m_pc = GET_PC(NMI); LOG(("Z8K '%s' NMI $%04x\n", tag(), m_pc)); } else if ((m_irq_req & Z8000_NVI) && (m_fcw & F_NVIE)) { CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ PUSH_PC(); PUSHW(SP, fcw); /* save current m_fcw */ PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ m_pc = GET_PC(NVI); m_irq_req &= ~Z8000_NVI; CHANGE_FCW(GET_FCW(NVI)); LOG(("Z8K '%s' NVI $%04x\n", tag(), m_pc)); } else if ((m_irq_req & Z8000_VI) && (m_fcw & F_VIE)) { CHANGE_FCW(fcw | F_S_N | F_SEG_Z8001());/* switch to segmented (on Z8001) system mode */ PUSH_PC(); PUSHW(SP, fcw); /* save current m_fcw */ PUSHW(SP, m_irq_req); /* save interrupt/trap type tag */ m_pc = read_irq_vector(); m_irq_req &= ~Z8000_VI; CHANGE_FCW(GET_FCW(VI)); LOG(("Z8K '%s' VI [$%04x/$%04x] fcw $%04x, pc $%04x\n", tag(), m_irq_vec, VEC00 + ( m_vector_mult * 2 ) * (m_irq_req & 0xff), m_fcw, m_pc)); } } uint32_t z8002_device::read_irq_vector() { return RDMEM_W(AS_PROGRAM, VEC00 + 2 * (m_irq_req & 0xff)); } uint32_t z8001_device::read_irq_vector() { return segmented_addr(RDMEM_L(AS_PROGRAM, VEC00 + 4 * (m_irq_req & 0xff))); } void z8002_device::clear_internal_state() { m_op[0] = m_op[1] = m_op[2] = m_op[3] = 0; m_ppc = 0; m_pc = 0; m_psapseg = 0; m_psapoff = 0; m_fcw = 0; m_refresh = 0; m_nspseg = 0; m_nspoff = 0; m_irq_req = 0; m_irq_vec = 0; m_op_valid = 0; m_regs.Q[0] = m_regs.Q[1] = m_regs.Q[2] = m_regs.Q[3] = 0; m_nmi_state = 0; m_irq_state[0] = m_irq_state[1] = 0; } void z8002_device::register_debug_state() { state_add( Z8000_PC, "PC", m_pc ).formatstr("%08X"); state_add( Z8000_NSPOFF, "NSPOFF", m_nspoff ).formatstr("%04X"); state_add( Z8000_NSPSEG, "NSPSEG", m_nspseg ).formatstr("%04X"); state_add( Z8000_FCW, "FCW", m_fcw ).formatstr("%04X"); state_add( Z8000_PSAPOFF, "PSAPOFF", m_psapoff ).formatstr("%04X"); state_add( Z8000_PSAPSEG, "PSAPSEG", m_psapseg ).formatstr("%04X"); state_add( Z8000_REFRESH, "REFR", m_refresh ).formatstr("%04X"); state_add( Z8000_IRQ_REQ, "IRQR", m_irq_req ).formatstr("%04X"); state_add( Z8000_IRQ_VEC, "IRQV", m_irq_vec ).formatstr("%04X"); state_add( Z8000_R0, "R0", RW(0) ).formatstr("%04X"); state_add( Z8000_R1, "R1", RW(1) ).formatstr("%04X"); state_add( Z8000_R2, "R2", RW(2) ).formatstr("%04X"); state_add( Z8000_R3, "R3", RW(3) ).formatstr("%04X"); state_add( Z8000_R4, "R4", RW(4) ).formatstr("%04X"); state_add( Z8000_R5, "R5", RW(5) ).formatstr("%04X"); state_add( Z8000_R6, "R6", RW(6) ).formatstr("%04X"); state_add( Z8000_R7, "R7", RW(7) ).formatstr("%04X"); state_add( Z8000_R8, "R8", RW(8) ).formatstr("%04X"); state_add( Z8000_R9, "R9", RW(9) ).formatstr("%04X"); state_add( Z8000_R10, "R10", RW(10) ).formatstr("%04X"); state_add( Z8000_R11, "R11", RW(11) ).formatstr("%04X"); state_add( Z8000_R12, "R12", RW(12) ).formatstr("%04X"); state_add( Z8000_R13, "R13", RW(13) ).formatstr("%04X"); state_add( Z8000_R14, "R14", RW(14) ).formatstr("%04X"); state_add( Z8000_R15, "R15", RW(15) ).formatstr("%04X"); state_add( STATE_GENPC, "GENPC", m_pc ).noshow(); state_add( STATE_GENPCBASE, "CURPC", m_ppc ).noshow(); state_add( STATE_GENFLAGS, "GENFLAGS", m_fcw ).formatstr("%16s").noshow(); state_add( STATE_GENSP, "GENSP", m_nspoff ).noshow(); } void z8002_device::state_string_export(const device_state_entry &entry, std::string &str) const { switch (entry.index()) { case STATE_GENFLAGS: str = string_format("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", m_fcw & 0x8000 ? 'S':'s', m_fcw & 0x4000 ? 'n':'N', m_fcw & 0x2000 ? 'E':'e', m_fcw & 0x1000 ? 'V':'v', m_fcw & 0x0800 ? 'N':'n', m_fcw & 0x0400 ? '?':'.', m_fcw & 0x0200 ? '?':'.', m_fcw & 0x0100 ? '?':'.', m_fcw & 0x0080 ? 'C':'c', m_fcw & 0x0040 ? 'Z':'z', m_fcw & 0x0020 ? 'S':'s', m_fcw & 0x0010 ? 'V':'v', m_fcw & 0x0008 ? 'D':'d', m_fcw & 0x0004 ? 'H':'h', m_fcw & 0x0002 ? '?':'.', m_fcw & 0x0001 ? '?':'.'); break; } } void z8001_device::z8k_disass_mode(int ref, int params, const char *param[]) { size_t len; if (params == 1) { len = strlen(param[0]); if (!core_strnicmp(param[0], "segmented", len) || !core_stricmp(param[0], "z8001")) { z8k_segm = true; z8k_segm_mode = Z8K_SEGM_MODE_SEG; machine().debugger().console().printf("Disassembler mode set to Z8001/segmented\n"); } else if (!core_strnicmp(param[0], "non-segmented", len) || !core_stricmp(param[0], "z8002")) { z8k_segm = false; z8k_segm_mode = Z8K_SEGM_MODE_NONSEG; machine().debugger().console().printf("Disassembler mode set to Z8002/non-segmented\n"); } else if (!core_strnicmp(param[0], "automatic", len)) { z8k_segm_mode = Z8K_SEGM_MODE_AUTO; machine().debugger().console().printf("Disassembler mode set to automatic\n"); } else goto usage; } else if (params > 1) { usage: machine().debugger().console().printf("Usage: z8k_disass_mode \n"); machine().debugger().console().printf(" set disassembler mode\n"); machine().debugger().console().printf(" mode: \"segmented\" or \"z8001\" - Z8001 mode\n"); machine().debugger().console().printf(" \"non-segmented\" or \"z8002\" - Z8002 mode\n"); machine().debugger().console().printf(" \"automatic\" - automatic mode\n"); } else { machine().debugger().console().printf("Current disassembler mode: "); if (z8k_segm_mode == Z8K_SEGM_MODE_AUTO) machine().debugger().console().printf("automatic, currently "); machine().debugger().console().printf("%s\n", z8k_segm ? "Z8001/segmented" : "Z8002/non-segmented"); } } void z8001_device::device_start() { clear_internal_state(); m_program = &space(AS_PROGRAM); /* If the system decodes STn lines to distinguish between data and program memory fetches, install the data space. If it doesn't, install the program memory into data memory space. */ if (has_space(AS_DATA)) m_data = &space(AS_DATA); else m_data = &space(AS_PROGRAM); m_direct = &m_program->direct(); m_io = &space(AS_IO); /* already initialized? */ if(z8000_exec == nullptr) z8000_init_tables(); if (machine().debug_flags & DEBUG_FLAG_ENABLED) { using namespace std::placeholders; machine().debugger().console().register_command("z8k_disass_mode", CMDFLAG_NONE, 0, 0, 1, std::bind(&z8001_device::z8k_disass_mode, this, _1, _2, _3)); } z8k_segm = true; register_debug_state(); m_icountptr = &m_icount; m_mo_out.resolve_safe(); m_mi = CLEAR_LINE; } void z8002_device::device_start() { clear_internal_state(); m_program = &space(AS_PROGRAM); /* If the system decodes STn lines to distinguish between data and program memory fetches, install the data space. If it doesn't, install the program memory into data memory space. */ if (has_space(AS_DATA)) m_data = &space(AS_DATA); else m_data = &space(AS_PROGRAM); m_direct = &m_program->direct(); m_io = &space(AS_IO); /* already initialized? */ if(z8000_exec == nullptr) z8000_init_tables(); z8k_segm = false; register_debug_state(); m_icountptr = &m_icount; m_mo_out.resolve_safe(); m_mi = CLEAR_LINE; } void z8001_device::device_reset() { m_fcw = RDMEM_W(AS_PROGRAM, 2); /* get reset m_fcw */ if(m_fcw & F_SEG) { m_pc = ((RDMEM_W(AS_PROGRAM, 4) & 0x0700) << 8) | (RDMEM_W(AS_PROGRAM, 6) & 0xffff); /* get reset m_pc */ } else { m_pc = RDMEM_W(AS_PROGRAM, 4); /* get reset m_pc */ } m_ppc = m_pc; } void z8002_device::device_reset() { m_fcw = RDMEM_W(AS_PROGRAM, 2); /* get reset m_fcw */ m_pc = RDMEM_W(AS_PROGRAM, 4); /* get reset m_pc */ m_ppc = m_pc; } z8002_device::~z8002_device() { z8000_deinit_tables(); } void z8002_device::execute_run() { do { /* any interrupt request pending? */ if (m_irq_req) Interrupt(); if (z8k_segm_mode == Z8K_SEGM_MODE_AUTO) z8k_segm = (m_fcw & F_SEG_Z8001()) ? 1 : 0; m_ppc = m_pc; debugger_instruction_hook(this, m_pc); if (m_irq_req & Z8000_HALT) { m_icount = 0; } else { Z8000_exec *exec; m_op[0] = RDOP(); m_op_valid = 1; exec = &z8000_exec[m_op[0]]; m_icount -= exec->cycles; (this->*exec->opcode)(); m_op_valid = 0; } } while (m_icount > 0); } void z8002_device::execute_set_input(int irqline, int state) { if (irqline == INPUT_LINE_NMI) { if (m_nmi_state == state) return; m_nmi_state = state; if (state != CLEAR_LINE) { m_irq_req = Z8000_NMI; m_irq_vec = NMI; } } else if (irqline < 2) { m_irq_state[irqline] = state; if (irqline == 0) { if (state == CLEAR_LINE) { if (!(m_fcw & F_NVIE)) m_irq_req &= ~Z8000_NVI; } else { if (m_fcw & F_NVIE) m_irq_req |= Z8000_NVI; } } else { if (state == CLEAR_LINE) { if (!(m_fcw & F_VIE)) m_irq_req &= ~Z8000_VI; } else { if (m_fcw & F_VIE) m_irq_req |= Z8000_VI; } } } }