diff --git a/src/devices/cpu/bcp/dp8344.cpp b/src/devices/cpu/bcp/dp8344.cpp index a1cd2fac1f1..54062c8d634 100644 --- a/src/devices/cpu/bcp/dp8344.cpp +++ b/src/devices/cpu/bcp/dp8344.cpp @@ -54,6 +54,8 @@ DEFINE_DEVICE_TYPE(DP8344, dp8344_device, "dp8344", "DP8344 BCP") // DEVICE CONSTRUCTION AND INITIALIZATION //************************************************************************** +ALLOW_SAVE_TYPE(dp8344_device::inst_state); + //------------------------------------------------- // dp8344_device - constructor //------------------------------------------------- @@ -72,6 +74,9 @@ dp8344_device::dp8344_device(const machine_config &mconfig, const char *tag, dev , m_pc(0) , m_icount(0) , m_nmi_pending(false) + , m_wait_states(0) + , m_source_data(0) + , m_data_address(0) , m_ccr(0) , m_ncf(0) , m_icr(0) @@ -86,7 +91,7 @@ dp8344_device::dp8344_device(const machine_config &mconfig, const char *tag, dev , m_tmr(0) , m_gp_main{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} , m_gp_alt{0, 0, 0, 0} - , m_ir{{0}, {0}, {0}, {0}} + , m_ir{0, 0, 0, 0} , m_tr(0) , m_as{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} , m_ds{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -151,10 +156,10 @@ void dp8344_device::device_start() set_icountptr(m_icount); // debug state registration - state_add(BCP_PC, "PC", m_pc); + state_add(BCP_PC, "PC", [this]() { return m_pc; }, [this](u16 data) { m_pc = m_ppc = data; prefetch_instruction(); }); state_add(STATE_GENPC, "GENPC", m_pc).noshow(); state_add(STATE_GENPCBASE, "GENPCBASE", m_pc).noshow(); - state_add(STATE_GENFLAGS, "GENFLAGS", m_ccr).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_ccr).formatstr("%09s").noshow(); state_add(BCP_BA, "BA", m_ba); state_add(BCP_BB, "BB", m_bb); state_add(BCP_CCR, "CCR", m_ccr); @@ -175,9 +180,13 @@ void dp8344_device::device_start() state_add(BCP_GP4_ALT + i, string_format("GP%da", 4 + i).c_str(), m_gp_alt[i]); for (int i = 0; i < 4; i++) { - state_add(BCP_IW + i, string_format("I%c", 'W' + i).c_str(), m_ir[i].w); - state_add(BCP_IWLO + i, string_format("I%cLO", 'W' + i).c_str(), m_ir[i].b.l).noshow(); - state_add(BCP_IWHI + i, string_format("I%cHI", 'W' + i).c_str(), m_ir[i].b.h).noshow(); + state_add(BCP_IW + i, string_format("I%c", 'W' + i).c_str(), m_ir[i]); + state_add(BCP_IWLO + i, string_format("I%cLO", 'W' + i).c_str(), + [this, i]() -> u8 { return m_ir[i] & 0x00ff; }, + [this, i](u8 data) { m_ir[i] = (m_ir[i] & 0xff00) | data; }).noshow(); + state_add(BCP_IWHI + i, string_format("I%cHI", 'W' + i).c_str(), + [this, i]() -> u8 { return (m_ir[i] & 0xff00) >> 8; }, + [this, i](u8 data) { m_ir[i] = (m_ir[i] & 0x00ff) | u16(data) << 8; }).noshow(); } for (int i = 8; i < 16; i++) state_add(BCP_GP8 + i - 8, string_format("GP%d", i).c_str(), m_gp_main[i]); @@ -187,6 +196,7 @@ void dp8344_device::device_start() // save states save_item(NAME(m_pc)); + save_item(NAME(m_ppc)); save_item(NAME(m_nmi_state)); save_item(NAME(m_ccr)); save_item(NAME(m_ncf)); @@ -202,8 +212,7 @@ void dp8344_device::device_start() save_item(NAME(m_tmr)); save_item(NAME(m_gp_main)); save_item(NAME(m_gp_alt)); - for (int i = 0; i < 4; i++) - save_item(NAME(m_ir[i].w), i); + save_item(NAME(m_ir)); save_item(NAME(m_tr)); save_item(NAME(m_asp)); save_item(NAME(m_dsp)); @@ -215,6 +224,10 @@ void dp8344_device::device_start() save_item(NAME(m_hib)); save_item(NAME(m_latched_instr)); save_item(NAME(m_nmi_pending)); + save_item(NAME(m_inst_state)); + save_item(NAME(m_wait_states)); + save_item(NAME(m_source_data)); + save_item(NAME(m_data_address)); save_item(NAME(m_rfifo)); // 3-frame Receive FIFO save_item(NAME(m_tfifo)); // 3-frame Transmit FIFO save_item(NAME(m_rfifo_head)); @@ -229,7 +242,7 @@ void dp8344_device::device_start() void dp8344_device::device_reset() { // Reset Program Counter - m_pc = 0x0000; + m_pc = m_ppc = 0x0000; // Reset Condition Code Register m_ccr &= 0x10; @@ -265,7 +278,9 @@ void dp8344_device::device_reset() m_ric = m_auto_start ? 0x03 : 0x01; m_hib = false; + // Reset execution state m_nmi_pending = false; + m_inst_state = T1_START; transceiver_reset(); @@ -274,49 +289,21 @@ void dp8344_device::device_reset() } -//************************************************************************** -// CONTROL REGISTERS AND CONDITION CODES -//************************************************************************** - //------------------------------------------------- -// get_flag - retrieve condition from CCR or TSR +// create_disassembler - factory method for +// disassembling program code //------------------------------------------------- -bool dp8344_device::get_flag(unsigned f) const +std::unique_ptr dp8344_device::create_disassembler() { - switch (f) - { - case 0: // Zero/Equal - return BIT(m_ccr, 0); - - case 1: // Carry - return BIT(m_ccr, 1); - - case 2: // Overflow - return BIT(m_ccr, 2); - - case 3: // Negative (or else Positive) - return BIT(m_ccr, 3); - - case 4: // Receiver Active - return BIT(m_tsr, 4); - - case 5: // Receiver Error - return BIT(m_tsr, 5); - - case 6: // Data Available - return BIT(m_tsr, 3); // FIXME: differs from numeric value! - - case 7: // Transmitter FIFO Full (or else Not Full) - return BIT(m_tsr, 7); - - default: - logerror("Unknown flag %d\n", f); - return false; - } + return std::make_unique(); } +//************************************************************************** +// INTERRUPTS AND CONTROL REGISTERS +//************************************************************************** + //------------------------------------------------- // set_receiver_interrupt - update receiver // interrupt request status @@ -405,6 +392,10 @@ void dp8344_device::set_condition_code(u8 data) } +//------------------------------------------------- +// set_interrupt_control - write to ICR +//------------------------------------------------- + void dp8344_device::set_interrupt_control(u8 data) { // IM0: Receiver @@ -469,6 +460,169 @@ void dp8344_device::set_auxiliary_control(u8 data) } +//------------------------------------------------- +// interrupt_active - determine if any of the +// five maskable interrupts is active +//------------------------------------------------- + +bool dp8344_device::interrupt_active() const +{ + // TODO + return false; +} + + +//------------------------------------------------- +// get_interrupt_vector - return the vector for +// the highest priority maskable interrupt +//------------------------------------------------- + +u8 dp8344_device::get_interrupt_vector() const +{ + // TODO + return 0; +} + + +//************************************************************************** +// CONDITION CODES AND ALU HELPERS +//************************************************************************** + +//------------------------------------------------- +// get_flag - retrieve condition from CCR or TSR +//------------------------------------------------- + +bool dp8344_device::get_flag(unsigned f) const +{ + switch (f) + { + case 0: // Zero/Equal + return BIT(m_ccr, 0); + + case 1: // Carry + return BIT(m_ccr, 1); + + case 2: // Overflow + return BIT(m_ccr, 2); + + case 3: // Negative (or else Positive) + return BIT(m_ccr, 3); + + case 4: // Receiver Active + return BIT(m_tsr, 4); + + case 5: // Receiver Error + return BIT(m_tsr, 5); + + case 6: // Data Available + return BIT(m_tsr, 3); // FIXME: differs from numeric value! + + case 7: // Transmitter FIFO Full (or else Not Full) + return BIT(m_tsr, 7); + + default: + logerror("Unknown flag %d\n", f); + return false; + } +} + + +//------------------------------------------------- +// set_nz - set the N and Z flags based on the +// result of an ALU operation +//------------------------------------------------- + +void dp8344_device::set_nz(u8 result) +{ + m_ccr &= 0xf6; + if (result == 0) + m_ccr |= 0x01; + else if (BIT(result, 7)) + m_ccr |= 0x08; +} + + +//------------------------------------------------- +// set_carry - set or clear the C flag +//------------------------------------------------- + +void dp8344_device::set_carry(bool state) +{ + if (state) + m_ccr |= 0x02; + else + m_ccr &= 0xfd; +} + + +//------------------------------------------------- +// rotate_right - perform right rotation for ROT +// and JRMK instructions +//------------------------------------------------- + +u8 dp8344_device::rotate_right(u8 data, u8 b) +{ + return (data >> b) | (data << (8 - b)); +} + + +//------------------------------------------------- +// add_nzcv - add and set N, Z, C, V flags for +// ADCA, ADD and ADDA instructions +//------------------------------------------------- + +u8 dp8344_device::add_nzcv(u8 s1, u8 s2, bool carry_in) +{ + s16 result = s8(s1) + s8(s2) + (carry_in ? 1 : 0); + if (result >= 128 && result < -128) + m_ccr |= 0x04; + else + m_ccr &= 0xfb; + + set_carry(s1 + s2 + (carry_in ? 1 : 0) >= 0x100); + set_nz(u8(result)); + return u8(result); +} + + +//------------------------------------------------- +// sub_nzcv - add and set N, Z, C, V flags for +// CMP, SBCA, SUB and SUBA instructions +//------------------------------------------------- + +u8 dp8344_device::sub_nzcv(u8 s1, u8 s2, bool carry_in) +{ + s16 result = s8(s1) - s8(s2) - (carry_in ? 1 : 0); + if (result >= 128 && result < -128) + m_ccr |= 0x04; + else + m_ccr &= 0xfb; + + set_carry(s1 < s2 + (carry_in ? 1 : 0)); + set_nz(u8(result)); + return u8(result); +} + + +void dp8344_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", + BIT(m_ccr, 7) ? 'T' : '.', // TO + BIT(m_ccr, 6) ? 'R' : '.', // RR + BIT(m_ccr, 5) ? 'W' : '.', // RW + BIT(m_ccr, 4) ? 'B' : '.', // BIRQ + BIT(m_ccr, 3) ? 'N' : '.', + BIT(m_ccr, 2) ? 'V' : '.', + BIT(m_ccr, 1) ? 'C' : '.', + BIT(m_ccr, 0) ? 'Z' : '.'); + break; + } +} + + //************************************************************************** // 16-BIT TIMER //************************************************************************** @@ -498,8 +652,8 @@ void dp8344_device::address_stack_push() { m_as[m_asp++] = u32(m_pc) | (u32(m_ccr & 0x0f) << 16) - | (m_ba << 20) - | (m_bb << 21) + | (m_ba << 21) + | (m_bb << 20) | (u32(m_acr & 0x01) << 22); if (m_asp >= 12) m_asp = 0; @@ -511,23 +665,23 @@ void dp8344_device::address_stack_push() // executing a RET or RETF instruction //------------------------------------------------- -void dp8344_device::address_stack_pop(u8 grf) +void dp8344_device::address_stack_pop(u8 g, bool rf) { m_asp = (m_asp == 0) ? 11 : m_asp - 1; m_pc = m_as[m_asp] & 0xffff; // Optionally restore, set or clear GIE - if (BIT(grf, 6)) - set_gie(BIT(grf, 5)); - else if (BIT(grf, 5)) + if (BIT(g, 1)) + set_gie(BIT(g, 0)); + else if (BIT(g, 0)) set_gie(BIT(m_as[m_asp], 22)); // Optionally restore ALU flags and register banks - if (BIT(grf, 4)) + if (rf) { - m_ccr = (m_ccr & 0xf0) | (m_as[m_asp] & 0xf0000) >> 20; - m_ba = BIT(m_as[m_asp], 20); - m_bb = BIT(m_as[m_asp], 21); + m_ccr = (m_ccr & 0xf0) | (m_as[m_asp] & 0xf0000) >> 16; + m_ba = BIT(m_as[m_asp], 21); + m_bb = BIT(m_as[m_asp], 20); } } @@ -928,28 +1082,28 @@ u8 dp8344_device::read_register(unsigned reg) return m_gp_main[7]; case 12: // IW (low byte) - return m_ir[0].b.l; + return m_ir[0] & 0x00ff; case 13: // IW (high byte) - return m_ir[0].b.h; + return (m_ir[0] & 0xff00) >> 8; case 14: // IX (low byte) - return m_ir[1].b.l; + return m_ir[1] & 0x00ff; case 15: // IX (high byte) - return m_ir[1].b.h; + return (m_ir[1] & 0xff00) >> 8; case 16: // IY (low byte) - return m_ir[2].b.l; + return m_ir[2] & 0x00ff; case 17: // IY (high byte) - return m_ir[2].b.h; + return (m_ir[2] & 0xff00) >> 8; case 18: // IZ (low byte) - return m_ir[3].b.l; + return m_ir[3] & 0x00ff; case 19: // IZ (high byte) - return m_ir[3].b.h; + return (m_ir[3] & 0xff00) >> 8; case 20: // GP8 return m_gp_main[8]; @@ -1097,35 +1251,35 @@ void dp8344_device::write_register(unsigned reg, u8 data) break; case 12: // IW (low byte) - m_ir[0].b.l = data; + m_ir[0] = (m_ir[0] & 0xff00) | data; break; case 13: // IW (high byte) - m_ir[0].b.h = data; + m_ir[0] = (m_ir[0] & 0x00ff) | u16(data) << 8; break; case 14: // IX (low byte) - m_ir[1].b.l = data; + m_ir[1] = (m_ir[1] & 0xff00) | data; break; case 15: // IX (high byte) - m_ir[1].b.h = data; + m_ir[1] = (m_ir[1] & 0x00ff) | u16(data) << 8; break; case 16: // IY (low byte) - m_ir[2].b.l = data; + m_ir[2] = (m_ir[2] & 0xff00) | data; break; case 17: // IY (high byte) - m_ir[2].b.h = data; + m_ir[2] = (m_ir[2] & 0x00ff) | u16(data) << 8; break; case 18: // IZ (low byte) - m_ir[3].b.l = data; + m_ir[3] = (m_ir[3] & 0xff00) | data; break; case 19: // IZ (high byte) - m_ir[3].b.h = data; + m_ir[3] = (m_ir[3] & 0x00ff) | u16(data) << 8; break; case 20: // GP8 @@ -1220,12 +1374,371 @@ void dp8344_device::execute_set_input(int irqline, int state) //************************************************************************** //------------------------------------------------- -// create_disassembler - +// prefetch_instruction - fetch the next +// instruction word from program memory //------------------------------------------------- -std::unique_ptr dp8344_device::create_disassembler() +void dp8344_device::prefetch_instruction() { - return std::make_unique(); + m_latched_instr = m_inst_cache->read_word(m_pc); +} + + +//------------------------------------------------- +// latch_address - handle ALE cycle and set T2 +// wait states for instructions referencing data +// memory +//------------------------------------------------- + +void dp8344_device::latch_address(bool rw) +{ + //logerror("Latching data memory address %04Xh for %sing (PC = %04Xh)\n", m_data_address, rw ? "read" : "writ", m_pc); + if ((m_dcr & 0x18) == 0) + m_wait_states = m_dcr & 0x07; + else + m_wait_states = std::max(m_dcr & 0x07, ((m_dcr & 0x18) >> 3) - 1); +} + + +//------------------------------------------------- +// instruction_wait - set T2 wait states for +// non-memory instructions +//------------------------------------------------- + +void dp8344_device::instruction_wait() +{ + m_wait_states = (m_dcr & 0x18) >> 3; +} + + +//------------------------------------------------- +// decode_instruction - begin execution of an +// opcode +//------------------------------------------------- + +dp8344_device::inst_state dp8344_device::decode_instruction() +{ + if (m_latched_instr < 0x8000) + { + m_source_data = read_register(m_latched_instr & 0x000f); + if ((m_latched_instr & 0xf000) == 0x1000) + { + // MOVE to indexed data memory + m_data_address = m_ir[3] + ((m_latched_instr & 0x0ff0) >> 4); + return TX_WRITE; + } + else + { + instruction_wait(); + return T2_STORE; + } + } + else if ((m_latched_instr & 0xf800) == 0x8000) + { + // JRMK + m_source_data = read_register(m_latched_instr & 0x001f); + return TX1_JRMK; + } + else if ((m_latched_instr & 0xfc00) == 0x8800) + { + // MOVE immediate to data memory + m_source_data = (m_latched_instr & 0x0380) >> 2 | (m_latched_instr & 0x001f); + m_data_address = m_ir[(m_latched_instr & 0x0060) >> 5]; + return TX_WRITE; + } + else if ((m_latched_instr & 0xfc00) == 0x8c00) + { + // LJMP or LCALL, conditional + m_source_data = read_register(m_latched_instr & 0x001f); + instruction_wait(); + return T2_ABSOLUTE; + } + else if ((m_latched_instr & 0xf000) == 0x9000) + { + // MOVE from indexed data memory + m_data_address = m_ir[3] + ((m_latched_instr & 0x0ff0) >> 4); + return TX_READ; + } + else if ((m_latched_instr >= 0xa000 && m_latched_instr < 0xae00) || (m_latched_instr & 0xfc00) == 0xc000) + { + if ((m_latched_instr & 0xfe00) != 0xc000) + m_source_data = read_register(m_latched_instr & 0x001f); + switch (m_latched_instr & 0x0180) + { + case 0x0000: + m_data_address = m_ir[(m_latched_instr & 0x0060) >> 5]--; + break; + case 0x0080: + m_data_address = m_ir[(m_latched_instr & 0x0060) >> 5]; + break; + case 0x0100: + m_data_address = m_ir[(m_latched_instr & 0x0060) >> 5]++; + break; + case 0x0180: + m_data_address = ++m_ir[(m_latched_instr & 0x0060) >> 5]; + break; + } + return (m_latched_instr & 0xfe00) == 0xc000 ? TX_READ : TX_WRITE; + } + else if ((m_latched_instr & 0xff80) == 0xae80) + { + // EXX + m_ba = BIT(m_latched_instr, 4); + m_bb = BIT(m_latched_instr, 3); + if (BIT(m_latched_instr, 6)) + set_gie(BIT(m_latched_instr, 5)); + instruction_wait(); + return T2_NEXT; + } + else if ((m_latched_instr & 0xff00) == 0xaf00) + { + // RET or RETF + if (BIT(m_latched_instr, 7) || get_flag(m_latched_instr & 0x0007) == BIT(m_latched_instr, 3)) + return TX_RET; + else + { + instruction_wait(); + return T2_NEXT; + } + } + else if ((m_latched_instr & 0xf000) == 0xb000) + { + // MOVE immediate to register + instruction_wait(); + return T2_STORE; + } + else if ((m_latched_instr & 0xfc00) == 0xc400) + { + // MOVE to or from accumulator-indexed data memory + if (BIT(m_latched_instr, 7)) + m_source_data = read_register(m_latched_instr & 0x001f); + m_data_address = m_ir[(m_latched_instr & 0x0060) >> 5] + read_accumulator(); + return BIT(m_latched_instr, 7) ? TX_WRITE : TX_READ; + } + else if ((m_latched_instr & 0xff00) == 0xcb00) + { + // JMP to relative destination + m_source_data = m_latched_instr & 0x00ff; + return TX2_JMP; + } + else if ((m_latched_instr & 0xff00) == 0xcc00) + { + // CALL to relative destination + m_source_data = m_latched_instr & 0x00ff; + return TX_CALL; + } + else if ((m_latched_instr & 0xff80) == 0xcd00) + { + // LJMP to index register + m_pc = m_ir[(m_latched_instr & 0x0060) >> 5]; + instruction_wait(); + return T2_NEXT; + } + else if ((m_latched_instr & 0xff80) == 0xcd80) + { + // JMP, register-based + m_source_data = read_register(m_latched_instr & 0x001f); + return TX1_JMP; + } + else if ((m_latched_instr & 0xff00) == 0xce00) + { + // LJMP or LCALL, unconditional + instruction_wait(); + return T2_ABSOLUTE; + } + else if ((m_latched_instr & 0xff80) == 0xcf80) + { + // TRAP or interrupt + address_stack_push(); + m_pc = u16(m_ibr) << 8 | (m_latched_instr & 0x003f); + if (BIT(m_latched_instr, 6)) + set_gie(false); + instruction_wait(); + return T2_NEXT; + } + else if ((m_latched_instr & 0xf000) == 0xd000) + { + // JMP, conditional + m_source_data = m_latched_instr & 0x00ff; + if (get_flag((m_latched_instr & 0x0700) >> 8) == BIT(m_latched_instr, 11)) + return TX2_JMP; + else + { + instruction_wait(); + return T2_NEXT; + } + } + else + { + m_source_data = read_register(m_latched_instr & 0x001f); + instruction_wait(); + return T2_STORE; + } +} + + +//------------------------------------------------- +// store_result - calculate and store the result +// of a register operation +//------------------------------------------------- + +void dp8344_device::store_result() +{ + switch (m_latched_instr & 0xf000) + { + case 0x0000: + m_source_data = add_nzcv(m_source_data, (m_latched_instr & 0x0ff0) >> 4, false); + write_register(m_latched_instr & 0x000f, m_source_data); + break; + + case 0x2000: + m_source_data = sub_nzcv(m_source_data, (m_latched_instr & 0x0ff0) >> 4, false); + write_register(m_latched_instr & 0x000f, m_source_data); + break; + + case 0x3000: + (void)sub_nzcv(m_source_data, (m_latched_instr & 0x0ff0) >> 4, false); + break; + + case 0x4000: + m_source_data &= (m_latched_instr & 0x0ff0) >> 4; + set_nz(m_source_data); + write_register(m_latched_instr & 0x000f, m_source_data); + break; + + case 0x5000: + m_source_data |= (m_latched_instr & 0x0ff0) >> 4; + set_nz(m_source_data); + write_register(m_latched_instr & 0x000f, m_source_data + ((m_latched_instr & 0x0ff0) >> 4)); + break; + + case 0x6000: + m_source_data ^= (m_latched_instr & 0x0ff0) >> 4; + set_nz(m_source_data); + write_register(m_latched_instr & 0x000f, m_source_data + ((m_latched_instr & 0x0ff0) >> 4)); + break; + + case 0x7000: + m_source_data &= (m_latched_instr & 0x0ff0) >> 4; + set_nz(m_source_data); + break; + + case 0xa000: + assert((m_latched_instr & 0x0f80) == 0x0e00); + m_source_data ^= 0xff; + set_nz(m_source_data); + write_register(m_latched_instr & 0x001f, m_source_data); + break; + + case 0xb000: + write_register(m_latched_instr & 0x000f, (m_latched_instr & 0x0ff0) >> 4); + break; + + case 0xc000: + switch (m_latched_instr & 0x0f00) + { + case 0x800: + set_carry(BIT(u16(m_source_data) << 1, (m_latched_instr & 0x00e0) >> 5)); + m_source_data >>= (m_latched_instr & 0x00e0) >> 5; + set_nz(m_source_data); + write_register(m_latched_instr & 0x001f, m_source_data); + break; + + case 0x900: + set_carry(BIT(m_source_data, (m_latched_instr & 0x00e0) >> 5)); + m_source_data <<= 8 - ((m_latched_instr & 0x00e0) >> 5); + set_nz(m_source_data); + write_register(m_latched_instr & 0x001f, m_source_data); + break; + + case 0xa00: + set_carry(BIT(u16(m_source_data) << 1, (m_latched_instr & 0x00e0) >> 5)); + m_source_data = rotate_right(m_source_data, (m_latched_instr & 0x00e0) >> 5); + set_nz(m_source_data); + write_register(m_latched_instr & 0x001f, m_source_data); + break; + } + + case 0xe000: + if (BIT(m_latched_instr, 11)) + m_source_data = sub_nzcv(m_source_data, read_accumulator(), BIT(m_latched_instr, 10) && BIT(m_ccr, 1)); + else + m_source_data = add_nzcv(m_source_data, read_accumulator(), BIT(m_latched_instr, 10) && BIT(m_ccr, 1)); + write_register((m_latched_instr & 0x03e0) >> 5, m_source_data); + break; + + case 0xf000: + switch (m_latched_instr & 0x0c00) + { + case 0x000: + m_source_data &= read_accumulator(); + set_nz(m_source_data); + break; + + case 0x400: + m_source_data |= read_accumulator(); + set_nz(m_source_data); + break; + + case 0x800: + m_source_data ^= read_accumulator(); + set_nz(m_source_data); + break; + + case 0xc00: + break; + } + write_register((m_latched_instr & 0x03e0) >> 5, m_source_data); + break; + } +} + + +//------------------------------------------------- +// data_write - write one byte to data memory to +// finish instruction +//------------------------------------------------- + +void dp8344_device::data_write() +{ + switch (m_latched_instr & 0xfe00) + { + case 0xa000: case 0xa200: + m_source_data = add_nzcv(m_source_data, read_accumulator(), BIT(m_latched_instr, 9) && BIT(m_ccr, 1)); + break; + + case 0xa400: case 0xa600: + m_source_data = sub_nzcv(m_source_data, read_accumulator(), BIT(m_latched_instr, 9) && BIT(m_ccr, 1)); + break; + + case 0xa800: + m_source_data &= read_accumulator(); + set_nz(m_source_data); + break; + + case 0xaa00: + m_source_data |= read_accumulator(); + set_nz(m_source_data); + break; + + case 0xac00: + m_source_data ^= read_accumulator(); + set_nz(m_source_data); + break; + } + + m_data_space->write_byte(m_data_address, m_source_data); +} + + +//------------------------------------------------- +// data_read - read one byte from data memory +// into register to finish instruction +//------------------------------------------------- + +void dp8344_device::data_read() +{ + write_register(m_latched_instr & ((m_latched_instr & 0xf000) == 0x9000 ? 0x000f : 0x001f), m_data_space->read_byte(m_data_address)); } @@ -1235,10 +1748,159 @@ std::unique_ptr dp8344_device::create_disassembler() void dp8344_device::execute_run() { - debugger_instruction_hook(m_pc); + while (m_icount > 0) + { + switch (m_inst_state) + { + case T1_DECODE: + m_ppc = m_pc; + debugger_instruction_hook(m_pc); - // TODO: everything - m_icount = 0; + if (m_nmi_pending) + { + m_nmi_pending = false; + + // TRAP to interrupt vector + m_latched_instr = 0xcfdc; + } + else if (BIT(m_acr, 0) && interrupt_active()) + { + // TRAP to interrupt vector + m_latched_instr = 0xcfc0 | get_interrupt_vector(); + } + else + m_pc++; + + m_inst_state = decode_instruction(); + break; + + case T1_START: + instruction_wait(); + m_inst_state = T2_NEXT; + break; + + case T1_SKIP: + m_pc++; + instruction_wait(); + m_inst_state = T2_NEXT; + break; + + case T1_LJMP: + m_pc = m_latched_instr; + instruction_wait(); + m_inst_state = T2_NEXT; + break; + + case T1_LCALL: + address_stack_push(); + m_pc = m_latched_instr; + instruction_wait(); + m_inst_state = T2_NEXT; + break; + + case TX_READ: + latch_address(true); + m_inst_state = T2_READ; + break; + + case TX_WRITE: + latch_address(false); + m_inst_state = T2_WRITE; + break; + + case TX1_JRMK: + m_source_data = rotate_right(m_source_data, (m_latched_instr & 0x00e0) >> 5); + m_source_data &= (0xff >> ((m_latched_instr & 0x0700) >> 8)) & 0xfe; + m_inst_state = TX2_JMP; + break; + + case TX1_JMP: + m_inst_state = TX2_JMP; + break; + + case TX2_JMP: + m_pc += s8(m_source_data); + instruction_wait(); + m_inst_state = T2_NEXT; + break; + + case TX_CALL: + address_stack_push(); + m_pc += s8(m_source_data); + instruction_wait(); + m_inst_state = T2_NEXT; + break; + + case TX_RET: + address_stack_pop((m_latched_instr & 0x0060) >> 5, BIT(m_latched_instr, 4)); + instruction_wait(); + m_inst_state = T2_NEXT; + break; + + case T2_NEXT: + if (m_wait_states != 0) + m_wait_states--; + else + { + prefetch_instruction(); + m_inst_state = T1_DECODE; + } + break; + + case T2_STORE: + if (m_wait_states != 0) + m_wait_states--; + else + { + store_result(); + prefetch_instruction(); + m_inst_state = T1_DECODE; + } + break; + + case T2_READ: + if (m_wait_states != 0) + m_wait_states--; + else + { + data_read(); + prefetch_instruction(); + m_inst_state = T1_DECODE; + } + break; + + case T2_WRITE: + if (m_wait_states != 0) + m_wait_states--; + else + { + data_write(); + prefetch_instruction(); + m_inst_state = T1_DECODE; + } + break; + + case T2_ABSOLUTE: + if (m_wait_states != 0) + m_wait_states--; + else + { + if ((m_latched_instr & 0xfc00) == 0x8c00) + { + if (BIT(m_source_data, (m_latched_instr & 0x00e0) >> 5) == BIT(m_latched_instr, 8)) + m_inst_state = BIT(m_latched_instr, 9) ? T1_LCALL : T1_LJMP; + else + m_inst_state = T1_SKIP; + } + else + m_inst_state = BIT(m_latched_instr, 7) ? T1_LCALL : T1_LJMP; + prefetch_instruction(); + } + break; + } + + m_icount--; + } } diff --git a/src/devices/cpu/bcp/dp8344.h b/src/devices/cpu/bcp/dp8344.h index b256a175dd6..c141271d999 100644 --- a/src/devices/cpu/bcp/dp8344.h +++ b/src/devices/cpu/bcp/dp8344.h @@ -82,9 +82,18 @@ protected: // device_memory_interface overrides virtual space_config_vector memory_space_config() const override; + // device_state_interface overrides + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + private: + enum inst_state : u8 { + T1_DECODE, T1_START, T1_SKIP, T1_LJMP, T1_LCALL, + TX_READ, TX_WRITE, + TX1_JRMK, TX1_JMP, TX2_JMP, TX_CALL, TX_RET, + T2_NEXT, T2_STORE, T2_READ, T2_WRITE, T2_ABSOLUTE + }; + // internal functions - bool get_flag(unsigned f) const; void set_receiver_interrupt(bool state); void set_transmitter_interrupt(bool state); void set_line_turn_around_interrupt(bool state); @@ -94,9 +103,17 @@ private: void set_condition_code(u8 data); void set_interrupt_control(u8 data); void set_auxiliary_control(u8 data); + bool interrupt_active() const; + u8 get_interrupt_vector() const; + bool get_flag(unsigned f) const; + void set_nz(u8 result); + void set_carry(bool state); + static u8 rotate_right(u8 data, u8 b); + u8 add_nzcv(u8 s1, u8 s2, bool carry_in); + u8 sub_nzcv(u8 s1, u8 s2, bool carry_in); u16 get_timer_count(); void address_stack_push(); - void address_stack_pop(u8 grf); + void address_stack_pop(u8 g, bool rf); void set_stack_pointer(u8 data); void data_stack_push(u8 data); u8 data_stack_pop(); @@ -114,6 +131,13 @@ private: u8 read_register(unsigned reg); u8 read_accumulator() const; void write_register(unsigned reg, u8 data); + void prefetch_instruction(); + void latch_address(bool rw); + void instruction_wait(); + inst_state decode_instruction(); + void store_result(); + void data_write(); + void data_read(); // address spaces const address_space_config m_inst_config; @@ -130,8 +154,13 @@ private: // execution state u16 m_pc; + u16 m_ppc; s32 m_icount; bool m_nmi_pending; + inst_state m_inst_state; + u8 m_wait_states; + u8 m_source_data; + u16 m_data_address; // control registers u8 m_ccr; @@ -152,7 +181,7 @@ private: u8 m_gp_alt[4]; // index registers - PAIR16 m_ir[4]; + u16 m_ir[4]; // timer registers u16 m_tr;