diff options
-rw-r--r-- | src/devices/cpu/pace/pace.cpp | 848 | ||||
-rw-r--r-- | src/devices/cpu/pace/pace.h | 116 | ||||
-rw-r--r-- | src/mame/drivers/ns5652.cpp | 26 |
3 files changed, 939 insertions, 51 deletions
diff --git a/src/devices/cpu/pace/pace.cpp b/src/devices/cpu/pace/pace.cpp index 03b36312930..73d6edfb6c9 100644 --- a/src/devices/cpu/pace/pace.cpp +++ b/src/devices/cpu/pace/pace.cpp @@ -5,21 +5,31 @@ National Semiconductor PACE/INS8900 The IPC-16A PACE (Processing and Control Element) was one of the first - commercially available 16-bit microprocessors. It was a successor to - the multiple-chip IMP-16 processor (itself loosely based on the Data - General Nova) and implemented a similar four-accumulator architecture - in a single PMOS LSI package using internal microcode. 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. + 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). 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. + + 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 indexing, and instructions may + also directly access 256 words of memory. The upper 128 words of the + direct region 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 had a 16-level stack) may hold both return addresses + and register data. The flag register 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. Six interrupts are available, one triggered - only by internal stack full/empty conditions; the nonmaskable level 0 - interrupt is intended primarily for debugging. The on-chip 10-level - LIFO stack may hold both return addresses and register data. All - instructions are single-word. + asserting the EXTEND pin (the emulation does not currently support + this). Six interrupts are available, one triggered only by internal + stack full/empty conditions; the nonmaskable level 0 interrupt is + intended primarily for debugging. 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 @@ -44,6 +54,8 @@ DEFINE_DEVICE_TYPE(INS8900, ins8900_device, "ins8900", "National Semiconductor I // DEVICE CONSTRUCTION AND INITIALIZATION //************************************************************************** +ALLOW_SAVE_TYPE(pace_device::cycle); + //------------------------------------------------- // pace_device - constructor //------------------------------------------------- @@ -52,15 +64,23 @@ pace_device::pace_device(const machine_config &mconfig, device_type type, const : cpu_device(mconfig, type, tag, owner, clock) , m_space_config("program", ENDIANNESS_LITTLE, 16, 16, -1) , m_space(nullptr) - , m_inst_cache(nullptr) + , m_cache(nullptr) + , m_bps_callback(*this) , m_jc_callback{{*this}, {*this}, {*this}} , m_flag_callback{{*this}, {*this}, {*this}, {*this}} - , m_icount(0) - , m_pc(0) , m_fr(0xffff) + , m_pc(0) + , m_mdr(0) + , m_mar(0) , m_ac{0, 0, 0, 0} - , m_sp(0) - , m_stk{0, 0, 0, 0, 0, 0, 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) { } @@ -97,6 +117,7 @@ device_memory_interface::space_config_vector pace_device::memory_space_config() 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) @@ -112,30 +133,38 @@ void pace_device::device_start() { // get memory spaces m_space = &space(AS_PROGRAM); - m_inst_cache = m_space->cache<1, -1, ENDIANNESS_LITTLE>(); + 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_pc).noshow(); - state_add<u16>(PACE_FR, "FR", [this]() { return m_fr; }, [this](u16 data) { fr_w(data); }); + 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(); 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_SP, "SP", - [this]() { return m_sp; }, - [this](u8 data) { m_sp = data < 10 ? data : BIT(data, 0) ? 9 : 0; }).mask(0xf); + 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(PACE_STK0 + i, string_format("STK%d", i).c_str(), m_stk[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_pc)); 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_sp)); - save_item(NAME(m_stk)); + 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)); } @@ -145,9 +174,11 @@ void pace_device::device_start() void pace_device::device_reset() { - m_pc = 0; - fr_w(0); - m_sp = 0; + set_fr(0); + m_pc = m_ppc = 0; + m_stkp = 0; + m_stack_depth = 0; + m_cycle = cycle::IFETCH_M1; } @@ -163,21 +194,60 @@ std::unique_ptr<util::disasm_interface> pace_device::create_disassembler() //************************************************************************** -// I/O LINES, INTERRUPTS AND FLAGS +// I/O LINES, INTERRUPTS AND CONTROL FLAGS //************************************************************************** //------------------------------------------------- -// fr_w - update the flag register +// set_control_flag - set one bit in the flag +// register //------------------------------------------------- -void pace_device::fr_w(u16 data) +void pace_device::set_control_flag(u8 fc) { - for (int i = 0; i < 4; i++) - if (BIT(data, 11 + i) != BIT(m_fr, 11 + i)) - m_flag_callback[i](BIT(data, 11 + i)); + 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); - // Bits 0 and 15 are always logic 1 - m_fr = data | 0x8001; + // 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)); } @@ -192,17 +262,711 @@ void pace_device::execute_set_input(int irqline, int state) //************************************************************************** +// 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) +{ + bool carry_out = sign_bit((u32(dr) + u32(sr) + (c && BIT(m_fr, 7) ? 1 : 0)) >> (BIT(m_fr, 10) ? 1 : 9)); + 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 (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); +} + + +//------------------------------------------------- +// 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 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 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 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 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: + logerror("%04X: Unknown %02XXX opcode encountered\n", m_ppc, m_cir >> 2); + return cycle::IFETCH_M1; + } +} + + //------------------------------------------------- // execute_run - //------------------------------------------------- void pace_device::execute_run() { - // TODO - - debugger_instruction_hook(m_pc); - m_icount = 0; + while (m_icount > 0) + { + m_cycle = execute_one(); + m_icount--; + } } diff --git a/src/devices/cpu/pace/pace.h b/src/devices/cpu/pace/pace.h index 60ba9766768..6fb0daaafeb 100644 --- a/src/devices/cpu/pace/pace.h +++ b/src/devices/cpu/pace/pace.h @@ -52,7 +52,7 @@ public: PACE_PC, PACE_FR, PACE_AC0, PACE_AC1, PACE_AC2, PACE_AC3, - PACE_SP, + PACE_STKD, PACE_STK0, PACE_STK1, PACE_STK2, PACE_STK3, PACE_STK4, PACE_STK5, PACE_STK6, PACE_STK7, PACE_STK8, PACE_STK9 }; @@ -86,25 +86,123 @@ protected: virtual space_config_vector memory_space_config() const override; private: - // internal helpers - void fr_w(u16 data); + enum class cycle { + 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; address_space *m_space; - memory_access_cache<1, -1, ENDIANNESS_LITTLE> *m_inst_cache; + memory_access_cache<1, -1, ENDIANNESS_LITTLE> *m_cache; // callback objects + devcb_read_line m_bps_callback; devcb_read_line m_jc_callback[3]; devcb_write_line m_flag_callback[4]; - // execution state - s32 m_icount; - u16 m_pc; + // core registers u16 m_fr; + u16 m_pc; + u16 m_mdr; + u16 m_mar; u16 m_ac[4]; - u8 m_sp; - u16 m_stk[10]; + + // 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 diff --git a/src/mame/drivers/ns5652.cpp b/src/mame/drivers/ns5652.cpp index b059c756c0e..6e4e25f474b 100644 --- a/src/mame/drivers/ns5652.cpp +++ b/src/mame/drivers/ns5652.cpp @@ -35,6 +35,32 @@ void ns5652_state::mem_map(address_map &map) map(0x0000, 0x0bff).mirror(0xd000).rom().region("program", 0); map(0xe800, 0xebff).ram(); // 4x MM2114J-3 map(0xec00, 0xecff).lr16([this](offs_t offset) { return m_ecprom[offset]; }, "ecprom_r"); + map(0xf600, 0xf600).nopw(); // shift register outputs? + map(0xf610, 0xf610).nopw(); + map(0xf620, 0xf620).nopw(); + map(0xf630, 0xf630).nopw(); + map(0xf640, 0xf640).nopw(); + map(0xf650, 0xf650).nopw(); + map(0xf660, 0xf660).nopw(); + map(0xf670, 0xf670).nopw(); + map(0xf680, 0xf680).nopw(); + map(0xf690, 0xf690).nopw(); + map(0xf6a0, 0xf6a0).nopw(); + map(0xf6b0, 0xf6b0).nopw(); + map(0xf6c0, 0xf6c0).nopw(); + map(0xf6d0, 0xf6d0).nopw(); + map(0xf6e0, 0xf6e0).nopw(); + map(0xf6f0, 0xf6f0).nopw(); + map(0xf700, 0xf700).nopw(); + map(0xf710, 0xf710).nopw(); + map(0xf720, 0xf720).nopw(); + map(0xf730, 0xf730).nopw(); + map(0xf740, 0xf740).nopw(); + map(0xf750, 0xf750).nopw(); + map(0xf760, 0xf760).nopw(); + map(0xf770, 0xf770).nopw(); + map(0xf780, 0xf780).nopw(); + map(0xf790, 0xf790).nopw(); } |