summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/hcd62121/hcd62121.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/hcd62121/hcd62121.cpp')
-rw-r--r--src/devices/cpu/hcd62121/hcd62121.cpp692
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 */