diff options
Diffstat (limited to 'src/devices/cpu/hcd62121/hcd62121.cpp')
-rw-r--r-- | src/devices/cpu/hcd62121/hcd62121.cpp | 692 |
1 files changed, 589 insertions, 103 deletions
diff --git a/src/devices/cpu/hcd62121/hcd62121.cpp b/src/devices/cpu/hcd62121/hcd62121.cpp index 4a99178dde5..7c68349f6a9 100644 --- a/src/devices/cpu/hcd62121/hcd62121.cpp +++ b/src/devices/cpu/hcd62121/hcd62121.cpp @@ -21,9 +21,10 @@ TODO: #include "emu.h" #include "hcd62121.h" + #include "hcd62121d.h" -#include "debugger.h" +#include "multibyte.h" enum @@ -41,7 +42,7 @@ enum HCD62121_R70, HCD62121_R74, HCD62121_R78, HCD62121_R7C }; - +constexpr u8 FLAG_INPUT = 0x20; constexpr u8 FLAG_CL = 0x10; constexpr u8 FLAG_Z = 0x08; constexpr u8 FLAG_C = 0x04; @@ -63,6 +64,16 @@ hcd62121_cpu_device::hcd62121_cpu_device(const machine_config &mconfig, const ch , m_dseg(0) , m_sseg(0) , m_f(0) + , m_time(0) + , m_time_op(0) + , m_unk_f5(0) + , m_cycles_until_timeout(0) + , m_is_timer_started(false) + , m_is_timer_irq_enabled(false) + , m_is_timer_irq_asserted(false) + , m_is_timer_wait_elapsed(true) + , m_is_infinite_timeout(false) + , m_timer_cycles(0) , m_lar(0) , m_opt(0) , m_port(0) @@ -72,8 +83,9 @@ hcd62121_cpu_device::hcd62121_cpu_device(const machine_config &mconfig, const ch , m_koh_cb(*this) , m_port_cb(*this) , m_opt_cb(*this) - , m_ki_cb(*this) - , m_in0_cb(*this) + , m_ki_cb(*this, 0) + , m_in0_cb(*this, 0) + , m_input_flag_cb(*this, 0) { } @@ -84,6 +96,15 @@ device_memory_interface::space_config_vector hcd62121_cpu_device::memory_space_c }; } +TIMER_CALLBACK_MEMBER(hcd62121_cpu_device::timer_tick) +{ + // TODO - Only stores seconds? How can it stop/reset? + if (m_is_timer_started) + { + m_time = (m_time + 1) % 60; + } +} + u8 hcd62121_cpu_device::read_op() { u8 d = m_program->read_byte( ( m_cseg << 16 ) | m_ip ); @@ -129,15 +150,42 @@ void hcd62121_cpu_device::write_reg(int size, u8 op1) if (op1 & 0x80) { for (int i = 0; i < size; i++) - m_reg[(op1 - i) & 0x7f] = m_temp1[i]; + set_reg((op1 - i) & 0x7f, m_temp1[i]); } else { for (int i = 0; i < size; i++) - m_reg[(op1 + i) & 0x7f] = m_temp1[i]; + set_reg((op1 + i) & 0x7f, m_temp1[i]); + } +} + + +void hcd62121_cpu_device::read_ireg(int size, u8 op1) +{ + u16 ad = m_reg[(0x40 | op1) & 0x7f ] | (m_reg[(0x40 | (op1 + 1)) & 0x7f] << 8); + + for (int i = 0; i < size; i++) + { + m_temp1[i] = m_program->read_byte((m_dseg << 16) | ad); + ad += (op1 & 0x40) ? -1 : 1; } + m_lar = ad; +} + + +void hcd62121_cpu_device::write_ireg(int size, u8 op1) +{ + u16 ad = m_reg[(0x40 | op1) & 0x7f] | (m_reg[(0x40 | (op1 + 1)) & 0x7f] << 8); + + for (int i = 0; i < size; i++) + { + m_program->write_byte((m_dseg << 16) | ad, m_temp1[i]); + ad += (op1 & 0x40) ? -1 : 1; + } + m_lar = ad; } + void hcd62121_cpu_device::read_regreg(int size, u8 op1, u8 op2, bool copy_extend_immediate) { for (int i = 0; i < size; i++) @@ -176,13 +224,13 @@ void hcd62121_cpu_device::write_regreg(int size, u8 arg1, u8 arg2) { /* store in arg1 */ for (int i = 0; i < size; i++) - m_reg[(arg1 + i) & 0x7f] = m_temp1[i]; + set_reg((arg1 + i) & 0x7f, m_temp1[i]); } else { /* store in arg2 */ for (int i = 0; i < size; i++) - m_reg[(arg2 + i) & 0x7f] = m_temp1[i]; + set_reg((arg2 + i) & 0x7f, m_temp1[i]); } } @@ -243,7 +291,7 @@ void hcd62121_cpu_device::write_iregreg(int size, u8 op1, u8 op2) { /* store in reg2 */ for (int i = 0; i < size; i++) - m_reg[(op2 + i) & 0x7f] = m_temp1[i]; + set_reg((op2 + i) & 0x7f, m_temp1[i]); } } @@ -254,7 +302,7 @@ void hcd62121_cpu_device::write_iregreg2(int size, u8 op1, u8 op2) { /* store in reg2 */ for (int i = 0; i < size; i++) - m_reg[(op2 + i) & 0x7f] = m_temp2[i]; + set_reg((op2 + i) & 0x7f, m_temp2[i]); } else { @@ -308,12 +356,8 @@ void hcd62121_cpu_device::device_start() { m_program = &space(AS_PROGRAM); - m_kol_cb.resolve_safe(); - m_koh_cb.resolve_safe(); - m_port_cb.resolve_safe(); - m_opt_cb.resolve_safe(); - m_ki_cb.resolve_safe(0); - m_in0_cb.resolve_safe(0); + m_timer = timer_alloc(FUNC(hcd62121_cpu_device::timer_tick), this); + m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); save_item(NAME(m_prev_pc)); save_item(NAME(m_sp)); @@ -323,13 +367,24 @@ void hcd62121_cpu_device::device_start() save_item(NAME(m_dseg)); save_item(NAME(m_sseg)); save_item(NAME(m_f)); + save_item(NAME(m_time)); + save_item(NAME(m_time_op)); + save_item(NAME(m_unk_f5)); + save_item(NAME(m_cycles_until_timeout)); + save_item(NAME(m_is_timer_started)); + save_item(NAME(m_is_timer_irq_enabled)); + save_item(NAME(m_is_timer_irq_asserted)); + save_item(NAME(m_is_timer_wait_elapsed)); + save_item(NAME(m_is_infinite_timeout)); + save_item(NAME(m_timer_cycles)); save_item(NAME(m_lar)); save_item(NAME(m_reg)); - save_item(NAME(m_temp1)); - save_item(NAME(m_temp2)); save_item(NAME(m_opt)); save_item(NAME(m_port)); + save_item(NAME(m_temp1)); + save_item(NAME(m_temp2)); + // Register state for debugger state_add(STATE_GENPC, "GENPC", m_rtemp).callexport().formatstr("%8s"); state_add(STATE_GENPCBASE,"CURPC", m_rtemp).callexport().formatstr("%8s"); @@ -344,51 +399,67 @@ void hcd62121_cpu_device::device_start() state_add(HCD62121_DSIZE, "DSIZE", m_dsize).callimport().callexport().formatstr("%02X"); state_add(HCD62121_F, "F", m_f ).callimport().callexport().formatstr("%02X"); - state_add(HCD62121_R00, "R00", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R04, "R04", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R08, "R08", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R0C, "R0C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R10, "R10", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R14, "R14", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R18, "R18", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R1C, "R1C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R20, "R20", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R24, "R24", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R28, "R28", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R2C, "R2C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R30, "R30", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R34, "R34", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R38, "R38", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R3C, "R3C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R40, "R40", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R44, "R44", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R48, "R48", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R4C, "R4C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R50, "R50", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R54, "R54", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R58, "R58", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R5C, "R5C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R60, "R60", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R64, "R64", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R68, "R68", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R6C, "R6C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R70, "R70", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R74, "R74", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R78, "R78", m_reg[0x00]).callimport().callexport().formatstr("%8s"); - state_add(HCD62121_R7C, "R7C", m_reg[0x00]).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R00, "R00", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R04, "R04", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R08, "R08", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R0C, "R0C", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R10, "R10", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R14, "R14", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R18, "R18", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R1C, "R1C", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R20, "R20", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R24, "R24", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R28, "R28", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R2C, "R2C", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R30, "R30", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R34, "R34", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R38, "R38", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R3C, "R3C", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R40, "R40", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R44, "R44", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R48, "R48", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R4C, "R4C", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R50, "R50", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R54, "R54", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R58, "R58", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R5C, "R5C", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R60, "R60", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R64, "R64", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R68, "R68", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R6C, "R6C", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R70, "R70", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R74, "R74", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R78, "R78", m_debugger_temp).callimport().callexport().formatstr("%8s"); + state_add(HCD62121_R7C, "R7C", m_debugger_temp).callimport().callexport().formatstr("%8s"); set_icountptr(m_icount); } +void hcd62121_cpu_device::state_import(const device_state_entry &entry) +{ + if ((entry.index() >= HCD62121_R00) && (entry.index() <= HCD62121_R7C)) + { + put_u32be(&m_reg[(entry.index() - HCD62121_R00) * 4], m_debugger_temp); + } +} + + void hcd62121_cpu_device::state_export(const device_state_entry &entry) { - switch (entry.index()) + if ((entry.index() >= HCD62121_R00) && (entry.index() <= HCD62121_R7C)) { - case STATE_GENPC: - case STATE_GENPCBASE: - m_rtemp = (m_cseg << 16) | m_ip; - break; + m_debugger_temp = get_u32be(&m_reg[(entry.index() - HCD62121_R00) * 4]); + } + else + { + switch (entry.index()) + { + case STATE_GENPC: + case STATE_GENPCBASE: + m_rtemp = (m_cseg << 16) | m_ip; + break; + } } } @@ -408,9 +479,7 @@ void hcd62121_cpu_device::state_string_export(const device_state_entry &entry, s m_f & FLAG_CL ? "CL":"__", m_f & FLAG_ZL ? "ZL":"__", m_f & FLAG_C ? 'C':'_', - m_f & FLAG_Z ? 'Z':'_' - ); - + m_f & FLAG_Z ? 'Z':'_'); break; case HCD62121_R00: @@ -517,12 +586,22 @@ void hcd62121_cpu_device::device_reset() { m_sp = 0x0000; m_ip = 0x0000; + m_dsize = 0; m_cseg = 0; m_dseg = 0; m_sseg = 0; - m_lar = 0; m_f = 0; - m_dsize = 0; + m_time = 0; + m_time_op = 0; + m_unk_f5 = 0; + m_cycles_until_timeout = 0; + m_is_timer_started = false; + m_is_timer_irq_enabled = false; + m_is_timer_irq_asserted = false; + m_is_timer_wait_elapsed = true; + m_is_infinite_timeout = false; + m_timer_cycles = 0; + m_lar = 0; m_opt = 0; m_port = 0; @@ -578,6 +657,15 @@ inline void hcd62121_cpu_device::set_cl_flag(bool is_cl) } +void hcd62121_cpu_device::set_input_flag(bool is_input_set) +{ + if (is_input_set) + m_f |= FLAG_INPUT; + else + m_f &= ~FLAG_INPUT; +} + + inline void hcd62121_cpu_device::op_msk(int size) { bool zero_high = true; @@ -674,7 +762,8 @@ inline void hcd62121_cpu_device::op_add(int size) for (int i = 0; i < size; i++) { - if (i == size - 1) { + if (i == size - 1) + { set_cl_flag((m_temp1[i] & 0x0f) + (m_temp2[i] & 0x0f) + carry > 0x0f); } @@ -704,7 +793,8 @@ inline void hcd62121_cpu_device::op_addb(int size) for (int i = 0; i < size; i++) { - if (i == size - 1) { + if (i == size - 1) + { set_cl_flag((m_temp1[i] & 0x0f) + (m_temp2[i] & 0x0f) + carry > 9); } @@ -739,7 +829,8 @@ inline void hcd62121_cpu_device::op_subb(int size) for (int i = 0; i < size; i++) { - if (i == size - 1) { + if (i == size - 1) + { set_cl_flag((m_temp1[i] & 0x0f) - (m_temp2[i] & 0x0f) - carry < 0); } @@ -773,7 +864,8 @@ inline void hcd62121_cpu_device::op_sub(int size) for (int i = 0; i < size; i++) { - if (i == size - 1) { + if (i == size - 1) + { set_cl_flag((m_temp1[i] & 0x0f) - (m_temp2[i] & 0x0f) - carry < 0); } @@ -794,15 +886,29 @@ inline void hcd62121_cpu_device::op_sub(int size) } +inline void hcd62121_cpu_device::op_pushb(u8 source) +{ + m_program->write_byte((m_sseg << 16) | m_sp, source); + m_sp--; +} + + inline void hcd62121_cpu_device::op_pushw(u16 source) { - m_program->write_byte(( m_sseg << 16) | m_sp, source & 0xff); + m_program->write_byte((m_sseg << 16) | m_sp, source & 0xff); m_sp--; - m_program->write_byte(( m_sseg << 16) | m_sp, source >> 8); + m_program->write_byte((m_sseg << 16) | m_sp, source >> 8); m_sp--; } +inline u8 hcd62121_cpu_device::op_popb() +{ + m_sp++; + return m_program->read_byte((m_sseg << 16) | m_sp); +} + + inline u16 hcd62121_cpu_device::op_popw() { m_sp++; @@ -813,11 +919,63 @@ inline u16 hcd62121_cpu_device::op_popw() return res; } +void hcd62121_cpu_device::timer_elapsed() +{ + m_is_timer_wait_elapsed = true; + + if (m_is_timer_irq_enabled) + { + m_is_timer_irq_asserted = true; + + // Call timer interrupt vector. + op_pushb(m_cseg); + op_pushw(m_ip); + m_cseg = 0x00; + m_ip = 0x0008; + } +} void hcd62121_cpu_device::execute_run() { do { + if (m_ki_cb() != 0 && m_input_flag_cb() == 0) + { + m_is_timer_wait_elapsed = true; + m_is_infinite_timeout = false; + } + + if (m_input_flag_cb() != 0) + { + set_input_flag(false); + } + + if (m_is_infinite_timeout && !m_is_timer_wait_elapsed) + { + m_icount = 0; + } + else if (m_cycles_until_timeout > 0 && !m_is_timer_irq_asserted) + { + int cycles_to_consume = std::min(m_cycles_until_timeout, m_icount); + m_cycles_until_timeout -= cycles_to_consume; + + if (!m_is_timer_wait_elapsed) + { + // It's a blocking wait, consume as much as possible in this quantum. + m_icount -= cycles_to_consume; + } + + if (m_cycles_until_timeout <= 0) + { + m_cycles_until_timeout += m_timer_cycles; + timer_elapsed(); + } + } + if (m_icount <= 0) + { + break; + } + offs_t pc = (m_cseg << 16) | m_ip; debugger_instruction_hook(pc); @@ -838,9 +996,11 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); // TODO - read_reg should support reading this - if (reg1 & 0x80) { + if (reg1 & 0x80) + { read_reg(size, (reg1 & 0x7f) - size + 1); - for (int i=0; i < size - 1; i++) { + for (int i=0; i < size - 1; i++) + { m_temp1[i] = m_temp1[i + 1]; } m_temp1[size-1] = 0; @@ -849,7 +1009,8 @@ void hcd62121_cpu_device::execute_run() else { read_reg(size, reg1); - for (int i = size-1; i > 0; i--) { + for (int i = size-1; i > 0; i--) + { m_temp1[i] = m_temp1[i - 1]; } m_temp1[0] = 0; @@ -1160,6 +1321,90 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x40: /* shrb/shlb ir1,8 */ + case 0x41: /* shrw/shlw ir1,8 */ + case 0x42: /* shrq/shlq ir1,8 */ + case 0x43: /* shrt/shlt ir1,8 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + + // TODO - read_ireg should support reading this + if (reg1 & 0x80) + { + read_ireg(size, (reg1 & 0x7f) - size + 1); + for (int i=0; i < size - 1; i++) + { + m_temp1[i] = m_temp1[i + 1]; + } + m_temp1[size-1] = 0; + write_ireg(size, (reg1 & 0x7f) - size + 1); + } + else + { + read_ireg(size, reg1); + for (int i = size-1; i > 0; i--) + { + m_temp1[i] = m_temp1[i - 1]; + } + m_temp1[0] = 0; + write_ireg(size, reg1); + } + } + break; + + case 0x44: /* mskb ir1,r2 */ + case 0x45: /* mskw ir1,r2 */ + case 0x46: /* mskq ir1,r2 */ + case 0x47: /* mskt ir1,r2 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 reg2 = read_op(); + + read_iregreg(size, reg1, reg2, true); + + op_msk(size); + } + break; + + case 0x48: /* shrb/shlb ir1,4 */ + case 0x49: /* shrw/shlw ir1,4 */ + case 0x4A: /* shrq/shlq ir1,4 */ + case 0x4B: /* shrt/shlt ir1,4 */ + /* Nibble shift */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 d1 = 0, d2 = 0; + + read_ireg(size, reg1); + + if (reg1 & 0x80) + { + // shift right + for (int i = 0; i < size; i++) + { + d1 = (m_temp1[i] & 0x0f) << 4; + m_temp1[i] = (m_temp1[i] >> 4) | d2; + d2 = d1; + } + } + else + { + // shift left + for (int i = 0; i < size; i++) + { + d1 = (m_temp1[i] & 0xf0) >> 4; + m_temp1[i] = (m_temp1[i] << 4) | d2; + d2 = d1; + } + } + + write_ireg(size, reg1); + } + break; + case 0x4C: /* testb ir1,r2 */ case 0x4D: /* testw ir1,r2 */ case 0x4E: /* testq ir1,r2 */ @@ -1240,6 +1485,41 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x60: /* shrb ir1,1 */ + case 0x61: /* shrw ir1,1 */ + case 0x62: /* shrq ir1,1 */ + case 0x63: /* shrt ir1,1 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 d1 = 0, d2 = 0; + bool zero_high = true; + bool zero_low = true; + + read_ireg(size, reg1); + + d2 = 0; + set_cl_flag ((m_temp1[0] & (1U<<4)) != 0U); + for (int i = 0; i < size; i++) + { + d1 = (m_temp1[i] & 0x01) << 7; + m_temp1[i] = (m_temp1[i] >> 1) | d2; + d2 = d1; + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; + } + + write_ireg(size, reg1); + + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); + set_carry_flag (d2 != 0); + } + break; + case 0x64: /* orb ir1,r2 */ case 0x65: /* orb ir1,r2 */ case 0x66: /* orb ir1,r2 */ @@ -1257,6 +1537,40 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x68: /* shlb ir1,1 */ + case 0x69: /* shlw ir1,1 */ + case 0x6A: /* shlq ir1,1 */ + case 0x6B: /* shlt ir1,1 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 d1 = 0, d2 = 0; + bool zero_high = true; + bool zero_low = true; + + read_ireg(size, reg1); + + set_cl_flag ((m_temp1[0] & (1U<<3)) != 0U); + for (int i = 0; i < size; i++) + { + d1 = (m_temp1[i] & 0x80) >> 7; + m_temp1[i] = (m_temp1[i] << 1) | d2; + d2 = d1; + + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; + } + + write_ireg(size, reg1); + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); + set_carry_flag (d2 != 0); + } + break; + case 0x6C: /* andb ir1,r2 */ case 0x6D: /* andw ir1,r2 */ case 0x6E: /* andq ir1,r2 */ @@ -1274,6 +1588,23 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x70: /* subbb ir1,r2 */ + case 0x71: /* subbw ir1,r2 */ + case 0x72: /* subbq ir1,r2 */ + case 0x73: /* subbt ir1,r2 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 reg2 = read_op(); + + read_iregreg(size, reg1, reg2, false); + + op_subb(size); + + write_iregreg(size, reg1, reg2); + } + break; + case 0x74: /* subb ir1,r2 */ case 0x75: /* subw ir1,r2 */ case 0x76: /* subq ir1,r2 */ @@ -1358,7 +1689,8 @@ void hcd62121_cpu_device::execute_run() case 0x8C: /* bstack_to_dmem */ { int size = m_dsize + 1; - for (int i=0; i < size; i++) { + for (int i=0; i < size; i++) + { u8 byte = m_program->read_byte((m_sseg << 16) | m_sp); m_program->write_byte((m_dseg << 16) | m_lar, byte); m_sp--; @@ -1370,7 +1702,8 @@ void hcd62121_cpu_device::execute_run() case 0x8D: /* fstack_to_dmem */ { int size = m_dsize + 1; - for (int i=0; i < size; i++) { + for (int i=0; i < size; i++) + { u8 byte = m_program->read_byte((m_sseg << 16) | m_sp); m_program->write_byte((m_dseg << 16) | m_lar, byte); m_sp++; @@ -1380,7 +1713,22 @@ void hcd62121_cpu_device::execute_run() break; case 0x8E: /* unk_8E */ - logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); + { + logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); + if (m_unk_f5 == 0xd0) + { + /* + FIXME: Needs to be validated with hardware tests. + + Instruction 0x8E is called before reading and testing inputs in some cases. + While the timer is also configured, there's no blocking wait for it to expire. + Instead, there's a busy wait on 2 bytes at register R76 that aren't updated directly by + program code. So far only seen when instruction 0xF5 is executed with operand 0xD0, but + maybe irrelevant, see JD-364 @ 21:b65f. + */ + m_is_timer_irq_enabled = true; + } + } break; case 0x90: /* retzh */ @@ -1409,6 +1757,12 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x9E: /* reti */ + m_ip = op_popw(); + m_cseg = op_popb(); + m_is_timer_irq_asserted = false; + break; + case 0x9F: /* ret */ m_ip = op_popw(); break; @@ -1451,12 +1805,87 @@ void hcd62121_cpu_device::execute_run() } break; + case 0xB0: /* unk_B0 reg/i8 */ case 0xB1: /* unk_B1 reg/i8 - PORTx control/direction? */ - case 0xB3: /* unk_B3 reg/i8 - timer/irq related? */ + case 0xB2: /* unk_B2 reg/i8 */ logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); read_op(); break; + case 0xB3: /* timer_set i8 */ + { + u8 arg = read_op(); + + /* + When timer control is set with operand 0xC0, the CPU periodically reads + from external RAM (address range 0x7c00..0x7fff) at an interval of + 832 clock cycles, with the reads themselves taking another 64 clock cycles. + This needs to be explicitly setup, involving writes to unknown segments + 0x11 and 0xE1 (see cfx9850.bin @ 00:00fe), otherwise there's only activity + on address lines without any reads. + + The total sum of these state reads can be approximated to the closest + power of two to define timeout values. Multiple samples were averaged, + as the state read interval can start at a distinct point in time from + the timer wait execution. + */ + const u64 TIMER_STATE_READ_CYCLES = 832 + 64; + m_is_infinite_timeout = false; + m_is_timer_wait_elapsed = true; + m_cycles_until_timeout = m_timer_cycles = 0; + m_time_op = arg; + switch (m_time_op) + { + case 0x01: case 0x03: + // Likely only timeouts on KO enabled input. + m_is_infinite_timeout = true; + break; + case 0x11: case 0x13: case 0x15: case 0x17: case 0x19: case 0x1b: case 0x1d: case 0x1f: + case 0x31: case 0x33: case 0x35: case 0x37: case 0x39: case 0x3b: case 0x3d: case 0x3f: + case 0x51: case 0x53: case 0x55: case 0x57: case 0x59: case 0x5b: case 0x5d: case 0x5f: + case 0x71: case 0x73: case 0x75: case 0x77: case 0x79: case 0x7b: case 0x7d: case 0x7f: + case 0x91: case 0x93: case 0x95: case 0x97: case 0x99: case 0x9b: case 0x9d: case 0x9f: + case 0xb1: case 0xb3: case 0xb5: case 0xb7: case 0xb9: case 0xbb: case 0xbd: case 0xbf: + case 0xd1: case 0xd3: case 0xd5: case 0xd7: case 0xd9: case 0xdb: case 0xdd: case 0xdf: + // Approximately 814.32us + m_timer_cycles = 0x4 * TIMER_STATE_READ_CYCLES; + break; + case 0x21: case 0x23: case 0x25: case 0x27: case 0x29: case 0x2b: case 0x2d: case 0x2f: + case 0x61: case 0x63: case 0x65: case 0x67: case 0x69: case 0x6b: case 0x6d: case 0x6f: + case 0xa1: case 0xa3: case 0xa5: case 0xa7: case 0xa9: case 0xab: case 0xad: case 0xaf: + // Approximately 1.63ms + m_timer_cycles = 0x8 * TIMER_STATE_READ_CYCLES; + break; + case 0x05: case 0x07: case 0x0d: case 0x0f: + case 0x45: case 0x47: case 0x4d: case 0x4f: + case 0xc5: case 0xc7: case 0xcd: case 0xcf: + // Approximately 209.34ms + m_timer_cycles = 0x400 * TIMER_STATE_READ_CYCLES; + break; + case 0x09: case 0x0b: + case 0x49: case 0x4b: + case 0xc9: case 0xcb: + // Approximately 837.61ms + m_timer_cycles = 0x1000 * TIMER_STATE_READ_CYCLES; + break; + case 0x41: case 0x43: + case 0xc1: case 0xc3: + // Approximately 1.68s + m_timer_cycles = 0x2000 * TIMER_STATE_READ_CYCLES; + break; + case 0x81: case 0x83: + // Approximately 100.58s + m_timer_cycles = 0x7a800 * TIMER_STATE_READ_CYCLES; + break; + default: + logerror("%02x:%04x: unimplemented timer value %02x encountered\n", m_cseg, m_ip-1, m_time_op); + break; + } + m_cycles_until_timeout = m_timer_cycles; + m_is_timer_started = true; + } + break; + case 0xB4: /* out koh,reg */ m_koh_cb(m_reg[read_op() & 0x7f]); break; @@ -1479,7 +1908,6 @@ void hcd62121_cpu_device::execute_run() break; case 0xBB: /* jmpcl a16 */ - logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); { u8 a1 = read_op(); u8 a2 = read_op(); @@ -1490,7 +1918,6 @@ void hcd62121_cpu_device::execute_run() break; case 0xBF: /* jmpncl a16 */ - logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); { u8 a1 = read_op(); u8 a2 = read_op(); @@ -1500,10 +1927,17 @@ void hcd62121_cpu_device::execute_run() } break; - //case 0xC0: /* movb reg,i8 */ // TODO - test + /* + These instructions do not modify any general purpose registers or memory, + but might be implemented on other CPUs with the same instruction set. + */ + case 0xC0: /* nop reg,i8 */ + case 0xC2: /* nop reg,i8 */ + case 0xC3: /* nop reg,i8 */ + logerror("%02x:%04x: nop instruction %02x %02x,%02x\n", m_cseg, m_ip-1, op, read_op(), read_op()); + break; + case 0xC1: /* movw reg,i16 */ - //case 0xC2: /* movw reg,i64 */ // TODO - test - //case 0xC3: /* movw reg,i80 */ // TODO - test { int size = datasize(op); u8 reg = read_op(); @@ -1513,7 +1947,7 @@ void hcd62121_cpu_device::execute_run() for (int i = 0; i < size; i++) { - m_reg[(reg + i) & 0x7f] = read_op(); + set_reg((reg + i) & 0x7f, read_op()); } } break; @@ -1555,8 +1989,20 @@ void hcd62121_cpu_device::execute_run() for (int i = 0; i < size; i++) { m_lar += pre_inc; - if (arg1 & 0x80) { + if (arg1 & 0x80) + { + /* + FIXME: Needs to be validated with hardware tests. + + JD-368 @ 20:047a must write value 0x7f @ 40:1819, despite 0x7f7f being + expected @ 20:3492. This routine is used to clear RAM, and will overflow + if 40:1818 = 0xff7f7f, since it will loop beyond the expected 0x8000 size + to clear. + + Does this instruction zero-extend immediate values? + */ m_program->write_byte((m_dseg << 16) | m_lar, arg2); + arg2 = 0; } else { @@ -1571,7 +2017,7 @@ void hcd62121_cpu_device::execute_run() for (int i = 0; i < size; i++) { m_lar += pre_inc; - m_reg[(arg2 + i) & 0x7f] = m_program->read_byte((m_dseg << 16) | m_lar); + set_reg((arg2 + i) & 0x7f, m_program->read_byte((m_dseg << 16) | m_lar)); m_lar += post_inc; } } @@ -1581,13 +2027,14 @@ void hcd62121_cpu_device::execute_run() case 0xCC: /* swapb ir1,r2 */ case 0xCD: /* swapw ir1,r2 */ case 0xCE: /* swapq ir1,r2 */ - case 0xCF: /* swapt ir1,r2? */ + case 0xCF: /* swapt ir1,r2 */ { int size = datasize(op); u8 reg1 = read_op(); u8 reg2 = read_op(); - if (reg1 & 0x80) { + if (reg1 & 0x80) + { fatalerror("%02x:%04x: unimplemented swap with immediate encountered\n", m_cseg, m_ip-1); } @@ -1602,7 +2049,8 @@ void hcd62121_cpu_device::execute_run() write_iregreg(size, reg1, reg2); write_iregreg2(size, reg1, reg2); - // TODO - are flags affected? + + m_f = 0; } break; @@ -1676,16 +2124,16 @@ void hcd62121_cpu_device::execute_run() logerror("%06x: in0 read\n", (m_cseg << 16) | m_ip); u8 reg1 = read_op(); - m_reg[reg1 & 0x7f] = m_in0_cb(); + set_reg(reg1 & 0x7f, m_in0_cb()); } break; case 0xE1: /* movb reg,OPT */ - m_reg[read_op() & 0x7f] = m_opt; + set_reg(read_op() & 0x7f, m_opt); break; case 0xE2: /* in kb, reg */ - m_reg[read_op() & 0x7f] = m_ki_cb(); + set_reg(read_op() & 0x7f, m_ki_cb()); break; case 0xE3: /* movb reg,dsize */ @@ -1693,7 +2141,7 @@ void hcd62121_cpu_device::execute_run() u8 reg = read_op(); if (reg & 0x80) fatalerror("%02x:%04x: unimplemented instruction %02x encountered with (arg & 0x80) != 0\n", m_cseg, m_ip-1, op); - m_reg[reg & 0x7f] = m_dsize; + set_reg(reg & 0x7f, m_dsize); } break; @@ -1702,20 +2150,33 @@ void hcd62121_cpu_device::execute_run() u8 reg = read_op(); if (reg & 0x80) fatalerror("%02x:%04x: unimplemented instruction %02x encountered with (arg & 0x80) != 0\n", m_cseg, m_ip-1, op); - m_reg[reg & 0x7f] = m_f; + set_reg(reg & 0x7f, m_f); } break; + case 0xE5: /* movb reg,TIME */ + set_reg(read_op() & 0x7f, m_time); + break; + case 0xE6: /* movb reg,PORT */ - m_reg[read_op() & 0x7f] = m_port; + set_reg(read_op() & 0x7f, m_port); break; case 0xE8: /* movw r1,lar */ { u8 reg1 = read_op(); - m_reg[reg1 & 0x7f] = m_lar & 0xff; - m_reg[(reg1 + 1) & 0x7f] = m_lar >> 8; + set_reg(reg1 & 0x7f, m_lar & 0xff); + set_reg((reg1 + 1) & 0x7f, m_lar >> 8); + } + break; + + case 0xEA: /* movw reg,pc */ + { + u8 reg1 = read_op(); + + set_reg(reg1 & 0x7f, m_ip & 0xff); + set_reg((reg1 + 1) & 0x7f, m_ip >> 8); } break; @@ -1723,13 +2184,21 @@ void hcd62121_cpu_device::execute_run() { u8 reg1 = read_op(); - m_reg[reg1 & 0x7f] = m_sp & 0xff; - m_reg[(reg1 + 1) & 0x7f] = m_sp >> 8; + set_reg(reg1 & 0x7f, m_sp & 0xff); + set_reg((reg1 + 1) & 0x7f, m_sp >> 8); } break; + case 0xED: /* movb reg,ds */ + set_reg(read_op() & 0x7f, m_dseg); + break; + + case 0xEE: /* movb reg,cs */ + set_reg(read_op() & 0x7f, m_cseg); + break; + case 0xEF: /* movb reg,ss */ - m_reg[read_op() & 0x7f] = m_sseg; + set_reg(read_op() & 0x7f, m_sseg); break; case 0xF0: /* movb OPT,reg */ @@ -1742,21 +2211,38 @@ void hcd62121_cpu_device::execute_run() m_port_cb(m_port); break; + case 0xF5: /* unk_F5 reg/i8 (out?) */ + logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); + m_unk_f5 = read_op(); + break; + case 0xF1: /* unk_F1 reg/i8 (out?) */ case 0xF3: /* unk_F3 reg/i8 (out?) */ - case 0xF5: /* unk_F5 reg/i8 (out?) */ - case 0xF7: /* unk_F7 reg/i8 (out?) */ + case 0xF6: /* unk_F6 reg/i8 (out?) */ + case 0xF7: /* timer_ctrl i8 */ + case 0xF8: /* unk_F8 reg/i8 (out?) */ logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); read_op(); break; - case 0xFC: /* unk_FC - disable interrupts/stop timer?? */ - case 0xFD: /* unk_FD */ - case 0xFE: /* unk_FE - wait for/start timer */ - if (op == 0xFE) - m_icount -= 75000; // TODO: temporary value that makes emulation speed acceptable + case 0xFC: /* timer_clear */ + // FIXME: Needs to be validated with hardware tests. + m_cycles_until_timeout = m_timer_cycles = 0; + m_is_timer_irq_enabled = false; + m_is_timer_irq_asserted = false; + m_is_timer_wait_elapsed = true; + break; - logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); + case 0xFD: /* timer_wait_low (no X1 clock, address or data bus activity) */ + case 0xFE: /* timer_wait */ + if (BIT(m_time_op, 0)) + { + m_is_timer_wait_elapsed = false; + } + else + { + logerror("%02x:%04x: wait for disabled timer? value %02x\n", m_cseg, m_ip-1, m_time_op); + } break; case 0xFF: /* nop */ |