diff options
Diffstat (limited to 'src/devices/cpu/pace/pace.cpp')
-rw-r--r-- | src/devices/cpu/pace/pace.cpp | 1004 |
1 files changed, 1004 insertions, 0 deletions
diff --git a/src/devices/cpu/pace/pace.cpp b/src/devices/cpu/pace/pace.cpp new file mode 100644 index 00000000000..478a690d38a --- /dev/null +++ b/src/devices/cpu/pace/pace.cpp @@ -0,0 +1,1004 @@ +// 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_space(nullptr) + , m_cache(nullptr) + , m_bps_callback(*this) + , m_jc_callback{{*this}, {*this}, {*this}} + , m_flag_callback{{*this}, {*this}, {*this}, {*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); + for (auto &cb : m_jc_callback) + cb.resolve_safe(0); + for (auto &cb : m_flag_callback) + cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pace_device::device_start() +{ + // get memory spaces + m_space = &space(AS_PROGRAM); + m_cache = m_space->cache<1, -1, ENDIANNESS_LITTLE>(); + + 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<u16>(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<u8>(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<u16>(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<util::disasm_interface> pace_device::create_disassembler() +{ + return std::make_unique<pace_disassembler>(); +} + + +//************************************************************************** +// 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) + { + if ((m_cir & 0x00c) == 0x004) + m_mdr = m_cache->read_word(m_mar); + else + 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) +{ + if ((m_cir & 0x00c) == 0x004) + m_cache->write_word(m_mar, r); + else + 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; + } +} |