// license:BSD-3-Clause // copyright-holders:AJR /*************************************************************************** National Semiconductor PACE/INS8900 The IPC-16A PACE (Processing and Control Element) was one of the first commercially available 16-bit microprocessors. It was am architectural successor to the multiple-chip IMP-16 processor contained in a single PMOS LSI package with internal microcode (though the emulation currently uses a state machine instead, loosely based on the published IMP-16 microcode; IMP-16's opcodes and instruction timings differ from PACE's in various ways). The two clock inputs with non-overlapping low phases required by PACE may be generated by the DP8302 STE (System Timing Element), which divides its oscillator input by 2. Much like the Data General Nova, PACE and IMP-16 have four 16-bit accumulators, two of which can be used as index registers. The program counter can also be used as a base for relative addressing, and 256 consecutive words including address 0 may be addressed absolutely. The upper 128 words of this base page may be mapped to either 0080–00FF or FF80–FFFF, depending on the state of the BPS input (which National suggests connecting to one of the flag outputs). The on-chip 10-level LIFO stack (IMP-16 has a 16-level stack) may hold both return addresses and register data. The flag register, which includes four general- purpose outputs, may be transferred to or from the stack or one of the accumulators. The standard machine cycle takes 4 clock periods (and the shortest instructions take 4 cycles each), though cycles can be stretched by asserting the EXTEND pin (the emulation does not currently support this). Six prioritized interrupts are available, one triggered only by internal stack full/empty conditions; the nonmaskable level 0 interrupt is intended primarily for debugging use. Each instruction is one word. INS8900 was a NMOS reimplementation of PACE which takes a single-phase clock and allows up to 2 MHz operation. It has different power supply requirements, but is functionally identical. ***************************************************************************/ #include "emu.h" #include "pace.h" #include "pacedasm.h" //************************************************************************** // GLOBAL VARIABLES //************************************************************************** // device type definition DEFINE_DEVICE_TYPE(INS8900, ins8900_device, "ins8900", "National Semiconductor INS8900") //************************************************************************** // DEVICE CONSTRUCTION AND INITIALIZATION //************************************************************************** ALLOW_SAVE_TYPE(pace_device::cycle); //------------------------------------------------- // pace_device - constructor //------------------------------------------------- pace_device::pace_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : cpu_device(mconfig, type, tag, owner, clock) , m_space_config("program", ENDIANNESS_LITTLE, 16, 16, -1) , m_bps_callback(*this) , m_jc_callback(*this) , m_flag_callback(*this) , m_fr(0xffff) , m_pc(0) , m_mdr(0) , m_mar(0) , m_ac{0, 0, 0, 0} , m_stkp(0) , m_stack_depth(0) , m_stack{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} , m_ppc(0) , m_cir(0) , m_shift_link(false) , m_cycle(cycle::UNKNOWN) , m_icount(0) { } //------------------------------------------------- // ins8900_device - constructor //------------------------------------------------- ins8900_device::ins8900_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : pace_device(mconfig, INS8900, tag, owner, clock) { } //------------------------------------------------- // memory_space_config - return a vector of // configuration structures for memory spaces //------------------------------------------------- device_memory_interface::space_config_vector pace_device::memory_space_config() const { return space_config_vector { std::make_pair(AS_PROGRAM, &m_space_config) }; } //------------------------------------------------- // device_resolve_objects - resolve objects that // may be needed for other devices to set // initial conditions at start time //------------------------------------------------- void pace_device::device_resolve_objects() { // resolve callbacks m_bps_callback.resolve_safe(0); m_jc_callback.resolve_all_safe(0); m_flag_callback.resolve_all_safe(); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void pace_device::device_start() { // get memory spaces space(AS_PROGRAM).cache(m_cache); space(AS_PROGRAM).specific(m_space); set_icountptr(m_icount); // debug state registration state_add(PACE_PC, "PC", m_pc); state_add(STATE_GENPC, "GENPC", m_pc).noshow(); state_add(STATE_GENPCBASE, "GENPCBASE", m_ppc).noshow(); state_add(PACE_FR, "FR", [this]() { return m_fr; }, [this](u16 data) { set_fr(data); }); state_add(STATE_GENFLAGS, "GENFLAGS", m_fr).noshow().formatstr("%14s"); for (int i = 0; i < 4; i++) state_add(PACE_AC0 + i, string_format("AC%d", i).c_str(), m_ac[i]); state_add(PACE_STKD, "STKD", [this]() { return m_stack_depth; }, [this](u8 data) { m_stack_depth = data >= 10 ? 10 : data; }).mask(0xf); for (int i = 0; i < 10; i++) state_add(PACE_STK0 + i, string_format("STK%d", i).c_str(), [this, i]() { return m_stack[m_stkp > i ? m_stkp - i - 1 : m_stkp + 9 - i]; }, [this, i](u16 data) { m_stack[m_stkp > i ? m_stkp - i - 1 : m_stkp + 9 - i] = data; } ); // save states save_item(NAME(m_fr)); save_item(NAME(m_pc)); save_item(NAME(m_mdr)); save_item(NAME(m_mar)); save_item(NAME(m_ac)); save_item(NAME(m_stkp)); save_item(NAME(m_stack_depth)); save_item(NAME(m_stack)); save_item(NAME(m_ppc)); save_item(NAME(m_cir)); save_item(NAME(m_shift_link)); save_item(NAME(m_cycle)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void pace_device::device_reset() { set_fr(0); m_pc = m_ppc = 0; m_stkp = 0; m_stack_depth = 0; m_cycle = cycle::IFETCH_M1; } //------------------------------------------------- // create_disassembler - factory method for // disassembling program code //------------------------------------------------- std::unique_ptr pace_device::create_disassembler() { return std::make_unique(); } //************************************************************************** // I/O LINES, INTERRUPTS AND CONTROL FLAGS //************************************************************************** //------------------------------------------------- // set_control_flag - set one bit in the flag // register //------------------------------------------------- void pace_device::set_control_flag(u8 fc) { if (fc == 15) { // TODO: SFLG/PFLG F15 is used to exit from level 0 interrupt } else if (!BIT(m_fr, fc)) { m_fr |= 1 << fc; if (fc >= 11 && fc <= 14) m_flag_callback[fc - 11](1); } } //------------------------------------------------- // reset_control_flag - reset one bit in the flag // register //------------------------------------------------- void pace_device::reset_control_flag(u8 fc) { // F0 and F15 are always 1 (not implemented in hardware) if (fc != 0 && fc != 15 && BIT(m_fr, fc)) { m_fr &= ~(1 << fc); if (fc >= 11 && fc <= 14) m_flag_callback[fc - 11](0); } } //------------------------------------------------- // set_fr - update the flag register //------------------------------------------------- void pace_device::set_fr(u16 r) { // F0 and F15 are always logic 1 (not implemented in hardware) r |= 0x8001; std::swap(m_fr, r); // Update flag outputs for (int i = 0; i < 4; i++) if (BIT(r, 11 + i) != BIT(m_fr, 11 + i)) m_flag_callback[i](BIT(m_fr, 11 + i)); } //------------------------------------------------- // execute_set_input - //------------------------------------------------- void pace_device::execute_set_input(int irqline, int state) { // TODO } //************************************************************************** // CONDITION CODES AND ALU //************************************************************************** //------------------------------------------------- // sign_bit - test the sign bit of a word, taking // BYTE mode into account //------------------------------------------------- bool pace_device::sign_bit(u16 r) const noexcept { return BIT(m_fr, 10) ? BIT(r, 7) : BIT(r, 15); } //------------------------------------------------- // equals_0 - test whether a word is equal to // zero, taking BYTE mode into account //------------------------------------------------- bool pace_device::equals_0(u16 r) const noexcept { // Only lower 7 bits are tested in BYTE mode return (BIT(m_fr, 10) ? r & 0x00ff : r) == 0; } //------------------------------------------------- // poll_condition - test condition by index //------------------------------------------------- bool pace_device::poll_condition(u8 cc) { switch (cc) { case 0: // STFL return m_stack_depth == 10; case 1: // REQ0 return equals_0(m_ac[0]); case 2: // PSIGN return !sign_bit(m_ac[0]); case 3: // BIT0 return BIT(m_ac[0], 0); case 4: // BIT1 return BIT(m_ac[0], 1); case 5: // NREQ0 return !equals_0(m_ac[0]); case 6: // BIT2 return BIT(m_ac[0], 2); case 7: // CONTIN (TODO) return false; case 8: // LINK return BIT(m_fr, 8); case 9: // IEN return BIT(m_fr, 9); case 10: // CARRY return BIT(m_fr, 7); case 11: // NSIGN return sign_bit(m_ac[0]); case 12: // OVF return BIT(m_fr, 6); case 13: case 14: case 15: return m_jc_callback[cc - 13](); default: return false; } } //------------------------------------------------- // sign_extend - extend byte sign into upper 8 // bits of word //------------------------------------------------- void pace_device::sign_extend(u16 &r) { if (BIT(r, 7)) r |= 0xff00; else r &= 0x00ff; } //------------------------------------------------- // add - add source to destination, with or // without carry //------------------------------------------------- void pace_device::add(u16 &dr, u16 sr, bool c) { u32 carry_test = (BIT(m_fr, 10) ? u32(dr & 0x00ff) + u32(sr & 0x00ff) : u32(dr) + u32(sr)) + (c && BIT(m_fr, 7) ? 1 : 0); s32 overflow_test = BIT(m_fr, 10) ? s32(s8(dr & 0x00ff)) + s32(s8(sr & 0x00ff)) : s32(s16(dr)) + s32(s16(sr)); dr += sr + (c && BIT(m_fr, 7) ? 1 : 0); if (BIT(m_fr, 10) ? BIT(carry_test, 8) : BIT(carry_test, 16)) set_control_flag(7); else reset_control_flag(7); if (overflow_test > s16(0x7fff) || overflow_test < s16(0x8000)) set_control_flag(6); else reset_control_flag(6); } //------------------------------------------------- // decimal_add - perform one adjusted stage of // decimal addition //------------------------------------------------- void pace_device::decimal_add(u16 &dr, u16 sr, unsigned stage) { bool carry_out = ((sr >> stage) & 15) + ((dr >> stage) & 15) >= (BIT(m_fr, 7) ? 9 : 10); s32 overflow_test = s32(s16(sr << (12 - stage))) + s32(s16(dr << (12 - stage))); dr += (sr & (0x000f << stage)) + ((BIT(m_fr, 7) + (carry_out ? 6 : 0)) << stage); if (stage == 0) reset_control_flag(7); else if (stage == (BIT(m_fr, 10) ? 4 : 12)) { if (carry_out) set_control_flag(7); else reset_control_flag(7); if (overflow_test > s16(0x7fff) || overflow_test < s16(0x8000)) set_control_flag(6); else reset_control_flag(6); } } //------------------------------------------------- // prepare_shift - setup registers for shift or // rotate instruction //------------------------------------------------- void pace_device::prepare_shift() { m_shift_link = BIT(m_mdr, 0); m_mdr = (m_mdr & 0x00fe) >> 1; } //------------------------------------------------- // shift_left - shift or rotate a register left // by one bit //------------------------------------------------- void pace_device::shift_left(u16 &r, bool rotate) { bool shift_out = sign_bit(r); r <<= 1; if (rotate && (m_shift_link ? BIT(m_fr, 8) : shift_out)) r |= 0x0001; if (BIT(m_fr, 10)) r &= 0x00ff; if (m_shift_link) { if (shift_out) set_control_flag(8); else reset_control_flag(8); } } //------------------------------------------------- // shift_right - shift or rotate a register right // by one bit //------------------------------------------------- void pace_device::shift_right(u16 &r, bool rotate) { bool shift_out = BIT(r, 0); r >>= 1; if (rotate && (m_shift_link ? BIT(m_fr, 8) : shift_out)) r |= BIT(m_fr, 10) ? 0x0080 : 0x8000; if (m_shift_link) { if (shift_out) set_control_flag(8); else reset_control_flag(8); } } //************************************************************************** // LIFO STACK MANAGEMENT //************************************************************************** //------------------------------------------------- // stack_push - push one word onto the stack //------------------------------------------------- void pace_device::stack_push(u16 r) { m_stack[m_stkp] = r; m_stkp = m_stkp == 9 ? 0 : m_stkp + 1; if (m_stack_depth == 10) logerror("%04X: Stack overflow\n", m_ppc); else m_stack_depth++; // TODO: stack full interrupt } //------------------------------------------------- // stack_pull - extract top entry from the stack //------------------------------------------------- u16 pace_device::stack_pull() { if (m_stack_depth == 0) { logerror("%04X: Stack underflow\n", m_ppc); return 0; } m_stack_depth--; m_stkp = m_stkp == 0 ? 9 : m_stkp - 1; return std::exchange(m_stack[m_stkp], 0); } //************************************************************************** // PROGRAM EXECUTION //************************************************************************** // instruction decode const pace_device::cycle pace_device::s_decode[64] = { cycle::HALT_M4, cycle::CFR_M4, cycle::CRF_M4, cycle::PUSHF_M4, cycle::PULLF_M4, cycle::JSR_M4, cycle::JMP_M4, cycle::XCHRS_M4, cycle::ROL_M4, cycle::ROR_M4, cycle::SHL_M4, cycle::SHR_M4, cycle::PFLG_M4, cycle::PFLG_M4, cycle::PFLG_M4, cycle::PFLG_M4, cycle::BOC_M4, cycle::BOC_M4, cycle::BOC_M4, cycle::BOC_M4, cycle::LI_M4, cycle::RAND_M4, cycle::RXOR_M4, cycle::RCPY_M4, cycle::PUSH_M4, cycle::PULL_M4, cycle::RADD_M4, cycle::RXCH_M4, cycle::CAI_M4, cycle::RADC_M4, cycle::AISZ_M4, cycle::RTI_M4, cycle::RTS_M4, cycle::UNKNOWN, cycle::DECA_M4, cycle::ISZ_M4, cycle::SUBB_M4, cycle::JSR_IND_M4, cycle::JMP_IND_M4, cycle::SKG_M4, cycle::LD_IND_M4, cycle::OR_M4, cycle::AND_M4, cycle::DSZ_M4, cycle::ST_IND_M4, cycle::UNKNOWN, cycle::SKAZ_M4, cycle::LSEX_M4, cycle::LD_M4, cycle::LD_M4, cycle::LD_M4, cycle::LD_M4, cycle::ST_M4, cycle::ST_M4, cycle::ST_M4, cycle::ST_M4, cycle::ADD_M4, cycle::ADD_M4, cycle::ADD_M4, cycle::ADD_M4, cycle::SKNE_M4, cycle::SKNE_M4, cycle::SKNE_M4, cycle::SKNE_M4 }; //------------------------------------------------- // read_instruction - read the next instruction // into internal registers //------------------------------------------------- void pace_device::read_instruction() { // TODO: interrupt check m_ppc = m_pc; debugger_instruction_hook(m_pc); m_mdr = m_cache.read_word(m_pc++); m_cir = m_mdr >> 6; sign_extend(m_mdr); } //------------------------------------------------- // get_effective_address - calculate effective // address for the current instruction //------------------------------------------------- u16 pace_device::get_effective_address() { if ((m_cir & 0x00c) == 0) { // Direct page mapping depends on BPS return m_mdr & (m_bps_callback() ? 0xffff : 0x00ff); } else if ((m_cir & 0x00c) == 0x004) { // PC-relative return m_mdr + m_pc; } else { // AC2 or AC3-indexed return m_mdr + m_ac[(m_cir & 0x00c) >> 2]; } } //------------------------------------------------- // read_effective_address - read the word at the // effective address into MDR, if applicable to // the current instruction //------------------------------------------------- void pace_device::read_effective_address() { // All opcodes with bit 15 set read from an EA except RTS and non-indirect ST if (m_cir > 0x200 && (m_cir & 0x3c0) != 0x340) m_mdr = m_space.read_word(m_mar); } //------------------------------------------------- // write_effective_address - write one word to // the effective address //------------------------------------------------- void pace_device::write_effective_address(u16 r) { m_space.write_word(m_mar, r); } //------------------------------------------------- // execute_one - execute one machine cycle of an // instruction //------------------------------------------------- pace_device::cycle pace_device::execute_one() { switch (m_cycle) { case cycle::IFETCH_M1: read_instruction(); return cycle::LEA_M2; case cycle::LEA_M2: m_mar = get_effective_address(); return cycle::RDEA_M3; case cycle::RDEA_M3: read_effective_address(); return s_decode[(m_cir & 0x3f0) >> 4]; case cycle::BOC_M4: return cycle::BOC_M5; case cycle::BOC_M5: return poll_condition((m_cir & 0x03c) >> 2) ? cycle::BRANCH : cycle::IFETCH_M1; case cycle::JMP_M4: case cycle::JSR_M5: m_pc = m_mar; return cycle::IFETCH_M1; case cycle::JMP_IND_M4: case cycle::JSR_IND_M5: m_pc = m_mdr; return cycle::IFETCH_M1; case cycle::JSR_M4: stack_push(m_pc); return cycle::JSR_M5; case cycle::JSR_IND_M4: stack_push(m_pc); return cycle::JSR_IND_M5; case cycle::RTS_M4: case cycle::RTI_M5: m_pc = stack_pull(); return cycle::RTS_M5; case cycle::RTI_M4: set_control_flag(9); // enable interrupts return cycle::RTI_M5; case cycle::RTS_M5: case cycle::RTI_M6: case cycle::BRANCH: m_pc += m_mdr; return cycle::IFETCH_M1; case cycle::SKNE_M4: m_mdr ^= m_ac[(m_cir & 0x030) >> 4]; return cycle::SKNE_M5; case cycle::SKNE_M5: return equals_0(m_mdr) ? cycle::IFETCH_M1 : cycle::SKIP; case cycle::SKG_M4: if (BIT(m_fr, 10)) sign_extend(m_mdr); return cycle::SKG_M5; case cycle::SKG_M5: m_mdr = ~m_mdr + m_ac[0]; return cycle::SKG_M6; case cycle::SKG_M6: if (BIT(m_fr, 10)) sign_extend(m_mdr); return cycle::SKG_M7; case cycle::SKG_M7: return BIT(m_mdr, 15) ? cycle::SKIP : cycle::IFETCH_M1; case cycle::SKAZ_M4: m_mdr &= m_ac[0]; return cycle::SKAZ_M5; case cycle::SKAZ_M5: case cycle::ISZ_M7: case cycle::DSZ_M7: return equals_0(m_mdr) ? cycle::SKIP : cycle::IFETCH_M1; case cycle::ISZ_M4: m_mdr += 1; return cycle::ISZ_M5; case cycle::ISZ_M5: case cycle::DSZ_M5: write_effective_address(m_mdr); return cycle::ISZ_M6; case cycle::ISZ_M6: case cycle::DSZ_M6: return cycle::ISZ_M7; case cycle::DSZ_M4: m_mdr -= 1; return cycle::DSZ_M5; case cycle::AISZ_M4: m_ac[(m_cir & 0x00c) >> 2] += m_mdr; return cycle::AISZ_M5; case cycle::AISZ_M5: // 16-bit test always performed even in BYTE mode return m_ac[(m_cir & 0x00c) >> 2] == 0 ? cycle::SKIP : cycle::IFETCH_M1; case cycle::SKIP: m_pc += 1; return cycle::IFETCH_M1; case cycle::LD_M4: m_ac[(m_cir & 0x030) >> 4] = m_mdr; return cycle::IFETCH_M1; case cycle::LD_IND_M4: m_mdr = m_space.read_word(m_mdr); return cycle::LD_IND_M5; case cycle::LD_IND_M5: m_ac[0] = m_mdr; return cycle::IFETCH_M1; case cycle::ST_M4: write_effective_address(m_ac[(m_cir & 0x030) >> 4]); return cycle::IFETCH_M1; case cycle::ST_IND_M4: m_space.write_word(m_mdr, m_ac[0]); return cycle::IFETCH_M1; case cycle::LSEX_M4: m_mdr = m_space.read_word(m_mdr); sign_extend(m_mdr); return cycle::IFETCH_M1; case cycle::AND_M4: m_ac[0] &= m_mdr; return cycle::IFETCH_M1; case cycle::OR_M4: m_ac[0] |= m_mdr; return cycle::IFETCH_M1; case cycle::ADD_M4: add(m_ac[(m_cir & 0x030) >> 4], m_mdr, false); return cycle::IFETCH_M1; case cycle::SUBB_M4: add(m_ac[0], ~m_mdr, true); return cycle::IFETCH_M1; case cycle::DECA_M4: decimal_add(m_ac[0], m_mdr, 0); return cycle::DECA_M5; case cycle::DECA_M5: decimal_add(m_ac[0], m_mdr, 4); return cycle::DECA_M6; case cycle::DECA_M6: decimal_add(m_ac[0], m_mdr, 8); return cycle::DECA_M7; case cycle::DECA_M7: decimal_add(m_ac[0], m_mdr, 12); return cycle::IFETCH_M1; case cycle::LI_M4: case cycle::RXCH_M6: case cycle::XCHRS_M6: case cycle::CAI_M5: m_ac[(m_cir & 0x00c) >> 2] = m_mdr; return cycle::IFETCH_M1; case cycle::RCPY_M4: m_ac[(m_cir & 0x00c) >> 2] = m_ac[m_cir & 0x003]; return cycle::IFETCH_M1; case cycle::RXCH_M4: m_mdr = m_ac[(m_cir & 0x00c) >> 2]; return cycle::RXCH_M5; case cycle::RXCH_M5: m_ac[(m_cir & 0x00c) >> 2] = m_ac[m_cir & 0x003]; return cycle::RXCH_M6; case cycle::XCHRS_M4: m_mdr = stack_pull(); // IMP-16 uses MAR as the temporary return cycle::XCHRS_M5; case cycle::XCHRS_M5: stack_push(m_ac[(m_cir & 0x00c) >> 2]); return cycle::XCHRS_M6; case cycle::CFR_M4: m_ac[(m_cir & 0x00c) >> 2] = m_fr; return cycle::IFETCH_M1; case cycle::CRF_M4: set_fr(m_ac[(m_cir & 0x00c) >> 2]); return cycle::IFETCH_M1; case cycle::PUSH_M4: stack_push(m_ac[(m_cir & 0x00c) >> 2]); return cycle::IFETCH_M1; case cycle::PULL_M4: m_ac[(m_cir & 0x00c) >> 2] = stack_pull(); return cycle::IFETCH_M1; case cycle::PUSHF_M4: stack_push(m_fr); return cycle::IFETCH_M1; case cycle::PULLF_M4: set_fr(stack_pull()); return cycle::IFETCH_M1; case cycle::RADD_M4: add(m_ac[(m_cir & 0x00c) >> 2], m_ac[m_cir & 0x003], false); return cycle::IFETCH_M1; case cycle::RADC_M4: add(m_ac[(m_cir & 0x00c) >> 2], m_ac[m_cir & 0x003], true); return cycle::IFETCH_M1; case cycle::RAND_M4: m_ac[(m_cir & 0x00c) >> 2] &= m_ac[m_cir & 0x003]; return cycle::IFETCH_M1; case cycle::RXOR_M4: m_ac[(m_cir & 0x00c) >> 2] ^= m_ac[m_cir & 0x003]; return cycle::IFETCH_M1; case cycle::CAI_M4: m_mdr += ~m_ac[(m_cir & 0x00c) >> 2]; return cycle::CAI_M5; case cycle::SHL_M4: prepare_shift(); return cycle::SHL_M5; case cycle::SHL_M5: if (BIT(m_fr, 10)) m_ac[(m_cir & 0x00c) >> 2] &= 0x00ff; return cycle::SHL_M6; case cycle::SHL_M6: return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::SHL_M7; case cycle::SHL_M7: shift_left(m_ac[(m_cir & 0x00c) >> 2], false); return cycle::SHL_M8; case cycle::SHL_M8: m_mdr -= 1; return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::SHL_M6; case cycle::SHR_M4: prepare_shift(); return cycle::SHR_M5; case cycle::SHR_M5: if (BIT(m_fr, 10)) m_ac[(m_cir & 0x00c) >> 2] &= 0x00ff; return cycle::SHR_M6; case cycle::SHR_M6: return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::SHR_M7; case cycle::SHR_M7: shift_right(m_ac[(m_cir & 0x00c) >> 2], false); return cycle::SHR_M8; case cycle::SHR_M8: m_mdr -= 1; return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::SHR_M6; case cycle::ROL_M4: prepare_shift(); return cycle::ROL_M5; case cycle::ROL_M5: if (BIT(m_fr, 10)) m_ac[(m_cir & 0x00c) >> 2] &= 0x00ff; return cycle::ROL_M6; case cycle::ROL_M6: return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::ROL_M7; case cycle::ROL_M7: shift_left(m_ac[(m_cir & 0x00c) >> 2], true); return cycle::ROL_M7; case cycle::ROL_M8: m_mdr -= 1; return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::ROL_M5; case cycle::ROR_M4: prepare_shift(); return cycle::ROR_M5; case cycle::ROR_M5: if (BIT(m_fr, 10)) m_ac[(m_cir & 0x00c) >> 2] &= 0x00ff; return cycle::ROR_M6; case cycle::ROR_M6: return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::ROR_M7; case cycle::ROR_M7: shift_right(m_ac[(m_cir & 0x00c) >> 2], true); return cycle::ROR_M8; case cycle::ROR_M8: m_mdr -= 1; return m_mdr == 0 ? cycle::IFETCH_M1 : cycle::ROR_M6; case cycle::HALT_M4: // TODO logerror("%04X: HALT opcode encountered\n", m_ppc); return cycle::IFETCH_M1; case cycle::PFLG_M4: // PFLG or SFLG return cycle::PFLG_M5; case cycle::PFLG_M5: // PFLG or SFLG set_control_flag((m_cir & 0x03c) >> 2); return BIT(m_mdr, 7) ? cycle::IFETCH_M1 : cycle::PFLG_M6; case cycle::PFLG_M6: // PFLG only reset_control_flag((m_cir & 0x03c) >> 2); return cycle::IFETCH_M1; case cycle::UNKNOWN: default: logerror("%04X: Unknown %02XXX opcode encountered\n", m_ppc, m_cir >> 2); return cycle::IFETCH_M1; } } //------------------------------------------------- // execute_run - //------------------------------------------------- void pace_device::execute_run() { while (m_icount > 0) { m_cycle = execute_one(); m_icount--; } } //------------------------------------------------- // state_string_export - //------------------------------------------------- void pace_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", BIT(m_fr, 14) ? 'F' : '.', BIT(m_fr, 13) ? 'F' : '.', BIT(m_fr, 12) ? 'F' : '.', BIT(m_fr, 11) ? 'F' : '.', BIT(m_fr, 10) ? 'B' : '.', BIT(m_fr, 9) ? 'I' : '.', BIT(m_fr, 8) ? 'L' : '.', BIT(m_fr, 7) ? 'C' : '.', BIT(m_fr, 6) ? 'O' : '.', BIT(m_fr, 5) ? '5' : '.', BIT(m_fr, 4) ? '4' : '.', BIT(m_fr, 3) ? '3' : '.', BIT(m_fr, 2) ? '2' : '.', BIT(m_fr, 1) ? '1' : '.'); break; } }