diff options
Diffstat (limited to 'src/devices/cpu/pace')
-rw-r--r-- | src/devices/cpu/pace/pace.cpp | 977 | ||||
-rw-r--r-- | src/devices/cpu/pace/pace.h | 224 | ||||
-rw-r--r-- | src/devices/cpu/pace/pacedasm.cpp | 321 | ||||
-rw-r--r-- | src/devices/cpu/pace/pacedasm.h | 36 |
4 files changed, 1558 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..b48e3537ecf --- /dev/null +++ b/src/devices/cpu/pace/pace.cpp @@ -0,0 +1,977 @@ +// 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, 0) + , m_jc_callback(*this, 0) + , 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_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<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) + 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; + } +} diff --git a/src/devices/cpu/pace/pace.h b/src/devices/cpu/pace/pace.h new file mode 100644 index 00000000000..b5c00fbb912 --- /dev/null +++ b/src/devices/cpu/pace/pace.h @@ -0,0 +1,224 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + National Semiconductor PACE/INS8900 + +**************************************************************************** + _____________ + D04 1 | | 40 D05 + D03 2 | | 39 D06 + D02 3 | | 38 D07 + D01 4 | | 37 D08 + D00 5 | | 36 D09 + IDS 6 | | 35 D10 + ODS 7 | | 34 D11 + NADS 8 | | 33 D12 + NHALT 9 | | 32 D13 + CONTIN 10 | IPC-16A | 31 D14 + JC14 11 | INS8900 | 30 D15 + JC15 12 | | 29 Vgg/Vdd* + JC13 13 | | 28 BPS + NIR5 14 | | 27 EXTEND + NIR4 15 | | 26 NINIT + NIR3 16 | | 25 CLK/Vcc* + NIR2 17 | | 24 NCLK/CLKX + F11 18 | | 23 Vbb* + F12 19 | | 22 F14 + Vss* 20 |_____________| 21 F13 + + * For PACE (IPC-16A): Vss = +5V, Vbb = +8V, Vgg = -12V + * For INS8900: Vss = GND, Vbb = -8V, Vcc = +5V, Vdd = +12V + +***************************************************************************/ + +#ifndef MAME_CPU_PACE_PACE_H +#define MAME_CPU_PACE_PACE_H + +#pragma once + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> pace_device + +class pace_device : public cpu_device +{ +public: + // register enumeration + enum { + PACE_PC, + PACE_FR, + PACE_AC0, PACE_AC1, PACE_AC2, PACE_AC3, + PACE_STKD, + PACE_STK0, PACE_STK1, PACE_STK2, PACE_STK3, PACE_STK4, + PACE_STK5, PACE_STK6, PACE_STK7, PACE_STK8, PACE_STK9 + }; + + // callback configuration + auto jc13_callback() { return m_jc_callback[0].bind(); } + auto jc14_callback() { return m_jc_callback[1].bind(); } + auto jc15_callback() { return m_jc_callback[2].bind(); } + auto f11_callback() { return m_flag_callback[0].bind(); } + auto f12_callback() { return m_flag_callback[1].bind(); } + auto f13_callback() { return m_flag_callback[2].bind(); } + auto f14_callback() { return m_flag_callback[3].bind(); } + +protected: + // construction/destruction + pace_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + + // device_t implementation + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_execute_interface implementation + virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; } + virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); } + virtual void execute_run() override; + virtual void execute_set_input(int irqline, int state) override; + + // device_disasm_interface implementation + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + + // device_memory_interface implementation + virtual space_config_vector memory_space_config() const override; + + // device_state_interface implementation + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + +private: + enum class cycle : u8 { + IFETCH_M1, LEA_M2, RDEA_M3, + + BOC_M4, BOC_M5, + JMP_M4, + JMP_IND_M4, + JSR_M4, JSR_M5, + JSR_IND_M4, JSR_IND_M5, + RTS_M4, RTS_M5, + RTI_M4, RTI_M5, RTI_M6, + BRANCH, + + SKNE_M4, SKNE_M5, + SKG_M4, SKG_M5, SKG_M6, SKG_M7, + SKAZ_M4, SKAZ_M5, + ISZ_M4, ISZ_M5, ISZ_M6, ISZ_M7, + DSZ_M4, DSZ_M5, DSZ_M6, DSZ_M7, + AISZ_M4, AISZ_M5, + SKIP, + + LD_M4, + LD_IND_M4, LD_IND_M5, + ST_M4, + ST_IND_M4, + LSEX_M4, + + AND_M4, + OR_M4, + ADD_M4, + SUBB_M4, + DECA_M4, DECA_M5, DECA_M6, DECA_M7, + + LI_M4, + RCPY_M4, + RXCH_M4, RXCH_M5, RXCH_M6, + XCHRS_M4, XCHRS_M5, XCHRS_M6, + CFR_M4, + CRF_M4, + PUSH_M4, + PULL_M4, + PUSHF_M4, + PULLF_M4, + + RADD_M4, + RADC_M4, + RAND_M4, + RXOR_M4, + CAI_M4, CAI_M5, + + SHL_M4, SHL_M5, SHL_M6, SHL_M7, SHL_M8, + SHR_M4, SHR_M5, SHR_M6, SHR_M7, SHR_M8, + ROL_M4, ROL_M5, ROL_M6, ROL_M7, ROL_M8, + ROR_M4, ROR_M5, ROR_M6, ROR_M7, ROR_M8, + + HALT_M4, + PFLG_M4, PFLG_M5, PFLG_M6, + + UNKNOWN + }; + + static const cycle s_decode[64]; + + // flag and interrupt helpers + void set_control_flag(u8 fc); + void reset_control_flag(u8 fc); + void set_fr(u16 r); + + // conditions and ALU helpers + bool sign_bit(u16 r) const noexcept; + bool equals_0(u16 r) const noexcept; + bool poll_condition(u8 cc); + static void sign_extend(u16 &r); + void add(u16 &dr, u16 sr, bool c); + void decimal_add(u16 &dr, u16 sr, unsigned stage); + void prepare_shift(); + void shift_left(u16 &r, bool rotate); + void shift_right(u16 &r, bool rotate); + + // stack helpers + void stack_push(u16 r); + u16 stack_pull(); + + // execution helpers + void read_instruction(); + u16 get_effective_address(); + void read_effective_address(); + void write_effective_address(u16 r); + cycle execute_one(); + + // address space and cache + address_space_config m_space_config; + memory_access<16, 1, -1, ENDIANNESS_LITTLE>::cache m_cache; + memory_access<16, 1, -1, ENDIANNESS_LITTLE>::specific m_space; + + // callback objects + devcb_read_line m_bps_callback; + devcb_read_line::array<3> m_jc_callback; + devcb_write_line::array<4> m_flag_callback; + + // core registers + u16 m_fr; + u16 m_pc; + u16 m_mdr; + u16 m_mar; + u16 m_ac[4]; + + // stack + u8 m_stkp; + u8 m_stack_depth; + u16 m_stack[10]; + + // execution state + u16 m_ppc; + u16 m_cir; + bool m_shift_link; + cycle m_cycle; + s32 m_icount; +}; + +// ======================> ins8900_device + +class ins8900_device : public pace_device +{ +public: + // device type constructor + ins8900_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +// device type declarations +DECLARE_DEVICE_TYPE(INS8900, ins8900_device) + +#endif // MAME_CPU_PACE_PACE_H diff --git a/src/devices/cpu/pace/pacedasm.cpp b/src/devices/cpu/pace/pacedasm.cpp new file mode 100644 index 00000000000..f6c8b438813 --- /dev/null +++ b/src/devices/cpu/pace/pacedasm.cpp @@ -0,0 +1,321 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + National Semiconductor PACE (IPC-16A, INS8900) disassembler + + This uses the same basic instruction set as IMP-16, but the binary + encoding is not compatible. + +***************************************************************************/ + +#include "emu.h" +#include "pacedasm.h" + + +//************************************************************************** +// PACE DISASSEMBLER +//************************************************************************** + +pace_disassembler::pace_disassembler() + : util::disasm_interface() +{ +} + +u32 pace_disassembler::opcode_alignment() const +{ + return 1; +} + +const char *const pace_disassembler::s_cc[16] = { + "STFL", // stack full + "REQ0", // AC0 equals zero + "PSIGN", // AC0 has positive sign + "BIT0", // AC0 has bit 0 set + "BIT1", // AC0 has bit 1 set + "NREQ0", // AC0 does not equal zero + "BIT2", // AC0 has bit 2 set + "CONTIN", // CONTIN input is high + "LINK", // LINK is set + "IEN", // IEN is set + "CARRY", // CARRY is set + "NSIGN", // AC0 has negative sign + "OV", // OV is set + "JC13", // JC13 is high + "JC14", // JC14 is high + "JC15" // JC15 is high +}; + +const char *const pace_disassembler::s_flags[16] = { + "F0", // does not exist in FR + "IE1", + "IE2", + "IE3", + "IE4", + "IE5", + "OVF", + "CRY", + "LINK", + "IEN", + "BYTE", + "F11", + "F12", + "F13", + "F14", + "F15" // does not exist in FR, but used to reset IE0 after level 0 interrupt +}; + +void pace_disassembler::format_addr(std::ostream &stream, u16 addr) +{ + if (addr >= 0x1000) + stream << "0"; + util::stream_format(stream, "%04X", addr); +} + +void pace_disassembler::format_disp(std::ostream &stream, u8 disp) +{ + if (disp >= 0x80) + { + stream << "-"; + disp = 0x100 - disp; + } + if (disp < 0x0a) + util::stream_format(stream, "%d", disp); + else + util::stream_format(stream, "0%X", disp); +} + +void pace_disassembler::format_ea(std::ostream &stream, u16 pc, u16 inst) +{ + if ((inst & 0x0300) == 0x0000) + { + // 0000–00FF or 0000–007F, FF80–FFFF depending on BPS input + if ((inst & 0x00ff) >= 0x10) + stream << "0"; + util::stream_format(stream, "%02X", inst & 0x00ff); + } + else if ((inst & 0x0300) == 0x0100) + format_addr(stream, pc + 1 + s8(inst & 0x00ff)); + else + { + format_disp(stream, inst & 0x00ff); + util::stream_format(stream, "(AC%d)", (inst & 0x0300) >> 8); + } +} + +offs_t pace_disassembler::disassemble(std::ostream &stream, offs_t pc, const pace_disassembler::data_buffer &opcodes, const pace_disassembler::data_buffer ¶ms) +{ + u16 inst = opcodes.r16(pc); + + switch (inst & 0xfc00) + { + case 0x0000: + stream << "HALT"; + return 1 | SUPPORTED; + + case 0x0400: + util::stream_format(stream, "%-8sAC%d", "CFR", (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x0800: + util::stream_format(stream, "%-8sAC%d", "CRF", (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x0c00: + stream << "PUSHF"; + return 1 | SUPPORTED; + + case 0x1000: + stream << "PULLF"; + return 1 | SUPPORTED; + + case 0x1400: + util::stream_format(stream, "%-8s", "JSR"); + format_ea(stream, pc, inst); + return 1 | STEP_OVER | SUPPORTED; + + case 0x1800: + util::stream_format(stream, "%-8s", "JMP"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0x1c00: + util::stream_format(stream, "%-8sAC%d", "XCHRS", (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x2000: + util::stream_format(stream, "%-8sAC%d,%d,%d", "ROL", (inst & 0x0300) >> 8, (inst & 0x00fe) >> 1, inst & 0x0001); + return 1 | SUPPORTED; + + case 0x2400: + util::stream_format(stream, "%-8sAC%d,%d,%d", "ROR", (inst & 0x0300) >> 8, (inst & 0x00fe) >> 1, inst & 0x0001); + return 1 | SUPPORTED; + + case 0x2800: + util::stream_format(stream, "%-8sAC%d,%d,%d", "SHL", (inst & 0x0300) >> 8, (inst & 0x00fe) >> 1, inst & 0x0001); + return 1 | SUPPORTED; + + case 0x2c00: + util::stream_format(stream, "%-8sAC%d,%d,%d", "SHR", (inst & 0x0300) >> 8, (inst & 0x00fe) >> 1, inst & 0x0001); + return 1 | SUPPORTED; + + case 0x3000: case 0x3400: case 0x3800: case 0x3c00: + util::stream_format(stream, "%-8s%s", BIT(inst, 7) ? "SFLG" : "PFLG", s_flags[(inst & 0x0f00) >> 8]); + return 1 | SUPPORTED; + + case 0x4000: case 0x4400: case 0x4800: case 0x4c00: + util::stream_format(stream, "%-8s%s,", "BOC", s_cc[(inst & 0x0f00) >> 8]); + format_addr(stream, pc + 1 + s8(inst & 0x00ff)); + return 1 | STEP_COND | SUPPORTED; + + case 0x5000: + util::stream_format(stream, "%-8sAC%d,", "LI", (inst & 0x0300) >> 8); + format_disp(stream, inst & 0x00ff); + return 1 | SUPPORTED; + + case 0x5400: + util::stream_format(stream, "%-8sAC%d,AC%d", "RAND", (inst & 0x00c0) >> 6, (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x5800: + util::stream_format(stream, "%-8sAC%d,AC%d", "RXOR", (inst & 0x00c0) >> 6, (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x5c00: + if ((inst & 0x0300) >> 2 == (inst & 0x00c0)) + stream << "NOP"; + else + util::stream_format(stream, "%-8sAC%d,AC%d", "RCPY", (inst & 0x00c0) >> 6, (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x6000: + util::stream_format(stream, "%-8sAC%d", "PUSH", (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x6400: + util::stream_format(stream, "%-8sAC%d", "PULL", (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x6800: + util::stream_format(stream, "%-8sAC%d,AC%d", "RADD", (inst & 0x00c0) >> 6, (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x6c00: + util::stream_format(stream, "%-8sAC%d,AC%d", "RXCH", (inst & 0x00c0) >> 6, (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x7000: + util::stream_format(stream, "%-8sAC%d,", "CAI", (inst & 0x0300) >> 8); + format_disp(stream, inst & 0x00ff); + return 1 | SUPPORTED; + + case 0x7400: + util::stream_format(stream, "%-8sAC%d,AC%d", "RADC", (inst & 0x00c0) >> 6, (inst & 0x0300) >> 8); + return 1 | SUPPORTED; + + case 0x7800: + util::stream_format(stream, "%-8sAC%d,", "AISZ", (inst & 0x0300) >> 8); + format_disp(stream, inst & 0x00ff); + return 1 | STEP_COND | SUPPORTED; + + case 0x7c00: + util::stream_format(stream, "%-8s", "RTI"); + format_disp(stream, inst & 0x00ff); + return 1 | STEP_OUT | SUPPORTED; + + case 0x8000: + util::stream_format(stream, "%-8s", "RTS"); + format_disp(stream, inst & 0x00ff); + return 1 | STEP_OUT | SUPPORTED; + + case 0x8800: + util::stream_format(stream, "%-8sAC0,", "DECA"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0x8c00: + util::stream_format(stream, "%-8s", "ISZ"); + format_ea(stream, pc, inst); + return 1 | STEP_COND | SUPPORTED; + + case 0x9000: + util::stream_format(stream, "%-8sAC0,", "SUBB"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0x9400: + util::stream_format(stream, "%-8s@", "JSR"); + format_ea(stream, pc, inst); + return 1 | STEP_OVER | SUPPORTED; + + case 0x9800: + util::stream_format(stream, "%-8s@", "JMP"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0x9c00: + util::stream_format(stream, "%-8sAC0,", "SKG"); + format_ea(stream, pc, inst); + return 1 | STEP_COND | SUPPORTED; + + case 0xa000: + util::stream_format(stream, "%-8sAC0,@", "LD"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xa400: + util::stream_format(stream, "%-8sAC0,", "OR"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xa800: + util::stream_format(stream, "%-8sAC0,", "AND"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xac00: + util::stream_format(stream, "%-8s", "DSZ"); + format_ea(stream, pc, inst); + return 1 | STEP_COND | SUPPORTED; + + case 0xb000: + util::stream_format(stream, "%-8sAC0,@", "ST"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xb800: + util::stream_format(stream, "%-8sAC0,", "SKAZ"); + format_ea(stream, pc, inst); + return 1 | STEP_COND | SUPPORTED; + + case 0xbc00: + util::stream_format(stream, "%-8sAC0,", "LSEX"); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xc000: case 0xc400: case 0xc800: case 0xcc00: + util::stream_format(stream, "%-8sAC%d,", "LD", (inst & 0x0c00) >> 10); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xd000: case 0xd400: case 0xd800: case 0xdc00: + util::stream_format(stream, "%-8sAC%d,", "ST", (inst & 0x0c00) >> 10); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xe000: case 0xe400: case 0xe800: case 0xec00: + util::stream_format(stream, "%-8sAC%d,", "ADD", (inst & 0x0c00) >> 10); + format_ea(stream, pc, inst); + return 1 | SUPPORTED; + + case 0xf000: case 0xf400: case 0xf800: case 0xfc00: + util::stream_format(stream, "%-8sAC%d,", "SKNE", (inst & 0x0c00) >> 10); + format_ea(stream, pc, inst); + return 1 | STEP_COND | SUPPORTED; + + default: + util::stream_format(stream, "%-8s", ".WORD"); + format_addr(stream, inst); + return 1 | SUPPORTED; + } +} diff --git a/src/devices/cpu/pace/pacedasm.h b/src/devices/cpu/pace/pacedasm.h new file mode 100644 index 00000000000..19471e0950a --- /dev/null +++ b/src/devices/cpu/pace/pacedasm.h @@ -0,0 +1,36 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + National Semiconductor PACE (IPC-16, INS8900) disassembler + +***************************************************************************/ + +#ifndef MAME_CPU_PACE_PACEDASM_H +#define MAME_CPU_PACE_PACEDASM_H + +#pragma once + +class pace_disassembler : public util::disasm_interface +{ +public: + // construction/destruction + pace_disassembler(); + +protected: + // disassembler overrides + virtual u32 opcode_alignment() const override; + virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; + +private: + // internal helpers + void format_addr(std::ostream &stream, u16 addr); + void format_disp(std::ostream &stream, u8 disp); + void format_ea(std::ostream &stream, u16 pc, u16 inst); + + // tables + static const char *const s_cc[16]; + static const char *const s_flags[16]; +}; + +#endif // MAME_CPU_PACE_PACEDASM_H |