diff options
Diffstat (limited to 'src/devices/cpu/hcd62121/hcd62121.cpp')
-rw-r--r-- | src/devices/cpu/hcd62121/hcd62121.cpp | 624 |
1 files changed, 386 insertions, 238 deletions
diff --git a/src/devices/cpu/hcd62121/hcd62121.cpp b/src/devices/cpu/hcd62121/hcd62121.cpp index 92f3deaac88..efdb53ba2cd 100644 --- a/src/devices/cpu/hcd62121/hcd62121.cpp +++ b/src/devices/cpu/hcd62121/hcd62121.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Wilbert Pol +// copyright-holders:Wilbert Pol, Ricardo Barreira /********************************************************************** Hitachi hcd62121 cpu core emulation. @@ -7,9 +7,12 @@ The Hitachi hcd62121 is the custom cpu which was used in the Casio CFX-9850 (and maybe some other things too). -This CPU core is based on the information provided by Martin Poupe. +This CPU core is mainly based on the information provided by Martin Poupe. Martin Poupe's site can be found at http://martin.poupe.org/casio/ +Other contributors to reverse-engineering this CPU include Petr Pfeifer +who hacked the hardware, Uwe Ryssel, Brad O'Dell and Ricardo Barreira. + TODO: - instruction timings - unknown instructions @@ -18,6 +21,7 @@ TODO: #include "emu.h" #include "hcd62121.h" +#include "hcd62121d.h" #include "debugger.h" @@ -38,11 +42,11 @@ enum }; +constexpr u8 FLAG_CL = 0x10; constexpr u8 FLAG_Z = 0x08; -constexpr u8 FLAG_C = 0x02; -constexpr u8 FLAG_ZL = 0x04; -constexpr u8 FLAG_CL = 0x01; -constexpr u8 FLAG_ZH = 0x10; +constexpr u8 FLAG_C = 0x04; +constexpr u8 FLAG_ZL = 0x02; +constexpr u8 FLAG_ZH = 0x01; DEFINE_DEVICE_TYPE(HCD62121, hcd62121_cpu_device, "hcd62121_cpu_device", "Hitachi HCD62121") @@ -110,12 +114,12 @@ void hcd62121_cpu_device::read_reg(int size, u8 op1) if (op1 & 0x80) { for (int i = 0; i < size; i++) - m_temp1[i] = m_reg[(op1 - i) & 0x7f]; + m_temp1[i] = m_reg[(op1 - i) & 0x7f]; // TODO - is this really how wrap-around for registers works? } else { for (int i = 0; i < size; i++) - m_temp1[i] = m_reg[(op1 + i) & 0x7f]; + m_temp1[i] = m_reg[(op1 + i) & 0x7f]; // TODO - is this really how wrap-around for registers works? } } @@ -134,8 +138,7 @@ void hcd62121_cpu_device::write_reg(int size, u8 op1) } } - -void hcd62121_cpu_device::read_regreg(int size, u8 op1, u8 op2, bool op_is_logical) +void hcd62121_cpu_device::read_regreg(int size, u8 op1, u8 op2, bool copy_extend_immediate) { for (int i = 0; i < size; i++) m_temp1[i] = m_reg[(op1 + i) & 0x7f]; @@ -145,7 +148,7 @@ void hcd62121_cpu_device::read_regreg(int size, u8 op1, u8 op2, bool op_is_logic /* Second operand is an immediate value */ m_temp2[0] = op2; for (int i = 1; i < size; i++) - m_temp2[i] = op_is_logical ? op2 : 0; + m_temp2[i] = copy_extend_immediate ? op2 : 0; } else { @@ -154,7 +157,7 @@ void hcd62121_cpu_device::read_regreg(int size, u8 op1, u8 op2, bool op_is_logic m_temp2[i] = m_reg[(op2 + i) & 0x7f]; } - if (!(op1 & 0x80) && !(op2 & 0x80)) + if (!(op1 & 0x80)) { /* We need to swap parameters */ for (int i = 0; i < size; i++) @@ -167,24 +170,24 @@ void hcd62121_cpu_device::read_regreg(int size, u8 op1, u8 op2, bool op_is_logic } -void hcd62121_cpu_device::write_regreg(int size, u8 op1, u8 op2) +void hcd62121_cpu_device::write_regreg(int size, u8 arg1, u8 arg2) { - if ((op1 & 0x80) || (op2 & 0x80)) + if ((arg1 & 0x80)) { - /* store in reg1 */ + /* store in arg1 */ for (int i = 0; i < size; i++) - m_reg[(op1 + i) & 0x7f] = m_temp1[i]; + m_reg[(arg1 + i) & 0x7f] = m_temp1[i]; } else { - /* store in reg2 */ + /* store in arg2 */ for (int i = 0; i < size; i++) - m_reg[(op2 + i) & 0x7f] = m_temp1[i]; + m_reg[(arg2 + i) & 0x7f] = m_temp1[i]; } } -void hcd62121_cpu_device::read_iregreg(int size, u8 op1, u8 op2) +void hcd62121_cpu_device::read_iregreg(int size, u8 op1, u8 op2, bool copy_extend_immediate) { u16 ad = m_reg[(0x40 | op1) & 0x7f ] | (m_reg[(0x40 | (op1 + 1)) & 0x7f] << 8); @@ -197,12 +200,14 @@ void hcd62121_cpu_device::read_iregreg(int size, u8 op1, u8 op2) if (op1 & 0x80) { + /* Second operand is an immediate value */ m_temp2[0] = op2; for (int i = 1; i < size; i++) - m_temp2[i] = 0; + m_temp2[i] = copy_extend_immediate ? op2 : 0; } else { + /* Second operand is a register */ for (int i = 0; i < size; i++) m_temp2[i] = m_reg[(op2 + i) & 0x7f]; } @@ -282,11 +287,11 @@ bool hcd62121_cpu_device::check_cond(u8 op) case 0x03: /* Z set */ return (m_f & FLAG_Z); - case 0x04: /* Z or C set */ - return (m_f & (FLAG_Z | FLAG_C)); + case 0x04: /* ZH not set */ + return (!(m_f & FLAG_ZH)); - case 0x05: /* CL set */ - return (m_f & FLAG_CL); + case 0x05: /* ZL not set */ + return (!(m_f & FLAG_ZL)); case 0x06: /* C clear */ return (!(m_f & FLAG_C)); @@ -575,169 +580,217 @@ inline void hcd62121_cpu_device::set_cl_flag(bool is_cl) inline void hcd62121_cpu_device::op_msk(int size) { - bool mskres = true; + bool zero_high = true; + bool zero_low = true; for (int i = 0; i < size; i++) { - if ((m_temp1[i] & m_temp2[i]) != m_temp2[i]) - mskres = false; + if ((m_temp1[i] & m_temp2[i] & 0xf0) != (m_temp2[i] & 0xf0)) + zero_high = false; + if ((m_temp1[i] & m_temp2[i] & 0x0f) != (m_temp2[i] & 0x0f)) + zero_low = false; } - set_zero_flag(!mskres); -} - - -inline void hcd62121_cpu_device::op_imsk(int size) -{ - bool mskres = true; - bool set_zero = false; + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); - for (int i = 0; i < size; i++) - { - if ((m_temp1[i] & ~m_temp2[i]) != ~m_temp2[i]) - mskres = false; - if (m_temp1[i] | m_temp2[i]) - set_zero = true; - } - - set_zero_flag(set_zero); - set_carry_flag(!mskres); + set_cl_flag(false); + set_carry_flag(false); } inline void hcd62121_cpu_device::op_and(int size) { - bool is_zero = true; + bool zero_high = true; + bool zero_low = true; for (int i = 0; i < size; i++) { m_temp1[i] = m_temp1[i] & m_temp2[i]; - if (m_temp1[i]) - is_zero = false; + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; } - set_zero_flag(is_zero); - set_zl_flag((m_temp1[0] & 0x0f) == 0); - set_zh_flag((m_temp1[0] & 0xf0) == 0); + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); + set_cl_flag(false); + set_carry_flag(false); } inline void hcd62121_cpu_device::op_or(int size) { - bool is_zero = true; + bool zero_high = true; + bool zero_low = true; for (int i = 0; i < size; i++) { m_temp1[i] = m_temp1[i] | m_temp2[i]; - if (m_temp1[i]) - is_zero = false; + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; } - set_zero_flag(is_zero); - set_zl_flag((m_temp1[0] & 0x0f) == 0); - set_zh_flag((m_temp1[0] & 0xf0) == 0); + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); + set_cl_flag(false); + set_carry_flag(false); } inline void hcd62121_cpu_device::op_xor(int size) { - bool is_zero = true; + bool zero_high = true; + bool zero_low = true; for (int i = 0; i < size; i++) { m_temp1[i] = m_temp1[i] ^ m_temp2[i]; - if (m_temp1[i]) - is_zero = false; + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; } - set_zero_flag(is_zero); - set_zl_flag((m_temp1[0] & 0x0f) == 0); - set_zh_flag((m_temp1[0] & 0xf0) == 0); + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); + set_cl_flag(false); + set_carry_flag(false); } inline void hcd62121_cpu_device::op_add(int size) { - bool is_zero = true; + bool zero_high = true; + bool zero_low = true; u8 carry = 0; - set_cl_flag((m_temp1[0] & 0x0f) + (m_temp2[0] & 0x0f) > 15); - for (int i = 0; i < size; i++) { - u16 res = m_temp1[i] + m_temp2[i] + carry; + if (i == size - 1) { + set_cl_flag((m_temp1[i] & 0x0f) + (m_temp2[i] & 0x0f) + carry > 0x0f); + } + u16 res = m_temp1[i] + m_temp2[i] + carry; m_temp1[i] = res & 0xff; - if (m_temp1[i]) - is_zero = false; - carry = (res & 0xff00) ? 1 : 0; + + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; } - set_zero_flag(is_zero); + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); set_carry_flag(carry); - set_zl_flag((m_temp1[0] & 0x0f) == 0); - set_zh_flag((m_temp1[0] & 0xf0) == 0); } // BCD ADD inline void hcd62121_cpu_device::op_addb(int size) { - bool is_zero = true; + bool zero_high = true; + bool zero_low = true; u8 carry = 0; - set_cl_flag((m_temp1[0] & 0x0f) + (m_temp2[0] & 0x0f) > 9); - for (int i = 0; i < size; i++) { - u16 res = (m_temp1[i] & 0x0f) + (m_temp2[i] & 0x0f) + carry; - - if (res > 9) - { - res += 6; + if (i == size - 1) { + set_cl_flag((m_temp1[i] & 0x0f) + (m_temp2[i] & 0x0f) + carry > 9); } - res += (m_temp1[i] & 0xf0) + (m_temp2[i] & 0xf0); - if (res > 0x9f) - { - res += 0x60; + + int num1 = (m_temp1[i] & 0x0f) + ((m_temp1[i] & 0xf0) >> 4) * 10; + int num2 = (m_temp2[i] & 0x0f) + ((m_temp2[i] & 0xf0) >> 4) * 10; + + int result = num1 + num2 + carry; + carry = (result > 99); + if (result > 99) + result -= 100; + m_temp1[i] = (result % 10) | ((result / 10) << 4); + + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; + } + + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); + set_carry_flag(carry); +} + + +// BCD SUBTRACT +inline void hcd62121_cpu_device::op_subb(int size) +{ + bool zero_high = true; + bool zero_low = true; + u8 carry = 0; + + for (int i = 0; i < size; i++) + { + if (i == size - 1) { + set_cl_flag((m_temp1[i] & 0x0f) - (m_temp2[i] & 0x0f) - carry < 0); } - m_temp1[i] = res & 0xff; - if (m_temp1[i]) - is_zero = false; - carry = (res & 0xff00) ? 1 : 0; + int num1 = (m_temp1[i] & 0x0f) + ((m_temp1[i] & 0xf0) >> 4) * 10; + int num2 = (m_temp2[i] & 0x0f) + ((m_temp2[i] & 0xf0) >> 4) * 10; + + int result = num1 - num2 - carry; + carry = (result < 0); + if (result < 0) + result += 100; + m_temp1[i] = (result % 10) | ((result / 10) << 4); + + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; } - set_zero_flag(is_zero); + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); set_carry_flag(carry); - set_zl_flag((m_temp1[0] & 0x0f) == 0); - set_zh_flag((m_temp1[0] & 0xf0) == 0); } inline void hcd62121_cpu_device::op_sub(int size) { - bool is_zero = true; + bool zero_high = true; + bool zero_low = true; u8 carry = 0; - set_cl_flag((m_temp1[0] & 0x0f) < (m_temp2[0] & 0x0f)); - for (int i = 0; i < size; i++) { - u16 res = m_temp1[i] - m_temp2[i] - carry; + if (i == size - 1) { + set_cl_flag((m_temp1[i] & 0x0f) - (m_temp2[i] & 0x0f) - carry < 0); + } + u16 res = m_temp1[i] - m_temp2[i] - carry; m_temp1[i] = res & 0xff; - if (m_temp1[i]) - is_zero = false; - carry = ( res & 0xff00 ) ? 1 : 0; + + if (m_temp1[i] & 0xf0) + zero_high = false; + if (m_temp1[i] & 0x0f) + zero_low = false; } - set_zero_flag(is_zero); + set_zero_flag(zero_high && zero_low); + set_zh_flag(zero_high); + set_zl_flag(zero_low); set_carry_flag(carry); - set_zl_flag((m_temp1[0] & 0x0f) == 0); - set_zh_flag((m_temp1[0] & 0xf0) == 0); } @@ -774,48 +827,36 @@ void hcd62121_cpu_device::execute_run() // actual instruction timings unknown m_icount -= 4; - switch (op) { - case 0x00: /* rorb/rolb r1,4 */ - case 0x01: /* rorw/rolw r1,4 */ - case 0x02: /* rorq/rolq r1,4 */ - case 0x03: /* rort/rolt r1,4 */ - /* Nibble rotate */ + case 0x00: /* shrb/shlb r1,8 */ // Yes, this just sets a register to 0! + case 0x01: /* shrw/shlw r1,8 */ + case 0x02: /* shrq/shlq r1,8 */ + case 0x03: /* shrt/shlt r1,8 */ { int size = datasize(op); u8 reg1 = read_op(); - u8 d1 = 0, d2 = 0; - read_reg(size, reg1); - - if (reg1 & 0x80) - { - // rotate right - d2 = (m_temp1[size-1] & 0x0f) << 4; - for (int i = 0; i < size; i++) - { - d1 = (m_temp1[i] & 0x0f) << 4; - m_temp1[i] = (m_temp1[i] >> 4) | d2; - d2 = d1; + // TODO - read_reg should support reading this + if (reg1 & 0x80) { + read_reg(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_reg(size, (reg1 & 0x7f) - size + 1); } else { - // rotate left - d2 = (m_temp1[size-1] & 0xf0) >> 4; - for (int i = 0; i < size; i++) - { - d1 = (m_temp1[i] & 0xf0) >> 4; - m_temp1[i] = (m_temp1[i] << 4) | d2; - d2 = d1; + read_reg(size, reg1); + for (int i = size-1; i > 0; i--) { + m_temp1[i] = m_temp1[i - 1]; } + m_temp1[0] = 0; + write_reg(size, reg1); } - - write_reg(size, reg1); } break; - case 0x04: /* mskb r1,r2 */ case 0x05: /* mskw r1,r2 */ case 0x06: /* mskq r1,r2 */ @@ -825,7 +866,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_regreg(size, reg1, reg2, false); + read_regreg(size, reg1, reg2, true); op_msk(size); } @@ -877,7 +918,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_regreg(size, reg1, reg2, false); + read_regreg(size, reg1, reg2, true); op_and(size); } @@ -892,7 +933,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_regreg(size, reg1, reg2, false); + read_regreg(size, reg1, reg2, true); op_xor(size); @@ -933,10 +974,10 @@ void hcd62121_cpu_device::execute_run() } break; - case 0x1C: /* imskb r1,r2 */ - case 0x1D: /* imskw r1,r2 */ - case 0x1E: /* imskq r1,r2 */ - case 0x1F: /* imskt r1,r2 */ + case 0x1C: /* cmpaddb r1,r2 */ + case 0x1D: /* cmpaddw r1,r2 */ + case 0x1E: /* cmpaddq r1,r2 */ + case 0x1F: /* cmpaddt r1,r2 */ { int size = datasize(op); u8 reg1 = read_op(); @@ -944,46 +985,42 @@ void hcd62121_cpu_device::execute_run() read_regreg(size, reg1, reg2, false); - op_imsk(size); + op_add(size); } break; - case 0x20: /* rorb/rolb r1 */ - case 0x21: /* rorw/rolw r1 */ - case 0x22: /* rorq/rolq r1 */ - case 0x23: /* rort/rolt r1 */ - /* Single bit rotate */ + case 0x20: /* shrb r1,1 */ + case 0x21: /* shrw r1,1 */ + case 0x22: /* shrq r1,1 */ + case 0x23: /* shrt r1,1 */ { int size = datasize(op); u8 reg1 = read_op(); u8 d1 = 0, d2 = 0; + bool zero_high = true; + bool zero_low = true; read_reg(size, reg1); - if (reg1 & 0x80) - { - // rotate right - d2 = (m_temp1[size-1] & 0x01) << 7; - for (int i = 0; i < size; i++) - { - d1 = (m_temp1[i] & 0x01) << 7; - m_temp1[i] = (m_temp1[i] >> 1) | d2; - d2 = d1; - } - } - else + d2 = 0; + set_cl_flag ((m_temp1[0] & (1U<<4)) != 0U); + for (int i = 0; i < size; i++) { - // rotate left - d2 = (m_temp1[size-1] & 0x80) >> 7; - for (int i = 0; i < size; i++) - { - d1 = (m_temp1[i] & 0x80) >> 7; - m_temp1[i] = (m_temp1[i] << 1) | d2; - d2 = d1; - } + 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_reg(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; @@ -996,7 +1033,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_regreg(size, reg1, reg2, false); + read_regreg(size, reg1, reg2, true); op_or(size); @@ -1004,40 +1041,37 @@ void hcd62121_cpu_device::execute_run() } break; - case 0x28: /* shrb/shlb r1 */ - case 0x29: /* shrw/shlw r1 */ - case 0x2A: /* shrq/shlq r1 */ - case 0x2B: /* shrt/shlt r1 */ - /* Single bit shift */ + case 0x28: /* shlb r1,1 */ + case 0x29: /* shlw r1,1 */ + case 0x2A: /* shlq r1,1 */ + case 0x2B: /* shlt r1,1 */ { int size = datasize(op); u8 reg1 = read_op(); u8 d1 = 0, d2 = 0; + bool zero_high = true; + bool zero_low = true; read_reg(size, reg1); - if (reg1 & 0x80) - { - // shift right - for (int i = 0; i < size; i++) - { - d1 = (m_temp1[i] & 0x01) << 7; - m_temp1[i] = (m_temp1[i] >> 1) | d2; - d2 = d1; - } - } - else + set_cl_flag ((m_temp1[0] & (1U<<3)) != 0U); + for (int i = 0; i < size; i++) { - // shift left - for (int i = 0; i < size; i++) - { - d1 = (m_temp1[i] & 0x80) >> 7; - m_temp1[i] = (m_temp1[i] << 1) | d2; - d2 = d1; - } + 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_reg(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; @@ -1058,6 +1092,23 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x30: /* subbb r1,r2 */ + case 0x31: /* subbw r1,r2 */ + case 0x32: /* subbq r1,r2 */ + case 0x33: /* subbt r1,r2 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 reg2 = read_op(); + + read_regreg(size, reg1, reg2, false); + + op_subb(size); + + write_regreg(size, reg1, reg2); + } + break; + case 0x34: /* subb r1,r2 */ case 0x35: /* subw r1,r2 */ case 0x36: /* subq r1,r2 */ @@ -1118,7 +1169,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_iregreg(size, reg1, reg2); + read_iregreg(size, reg1, reg2, true); op_and(size); } @@ -1133,7 +1184,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_iregreg(size, reg1, reg2); + read_iregreg(size, reg1, reg2, false); op_sub(size); } @@ -1148,7 +1199,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_iregreg(size, reg1, reg2); + read_iregreg(size, reg1, reg2, false); for (int i = 0; i < size; i++) m_temp1[i] = m_temp2[i]; @@ -1157,6 +1208,21 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x5C: /* cmpaddb ir1,r2 */ + case 0x5D: /* cmpaddw ir1,r2 */ + case 0x5E: /* cmpaddq ir1,r2 */ + case 0x5F: /* cmpaddt ir1,r2 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 reg2 = read_op(); + + read_iregreg(size, reg1, reg2, false); + + op_add(size); + } + break; + case 0x64: /* orb ir1,r2 */ case 0x65: /* orb ir1,r2 */ case 0x66: /* orb ir1,r2 */ @@ -1166,7 +1232,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_iregreg(size, reg1, reg2); + read_iregreg(size, reg1, reg2, true); op_or(size); @@ -1183,7 +1249,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_iregreg(size, reg1, reg2); + read_iregreg(size, reg1, reg2, true); op_and(size); @@ -1191,6 +1257,40 @@ void hcd62121_cpu_device::execute_run() } break; + case 0x74: /* subb ir1,r2 */ + case 0x75: /* subw ir1,r2 */ + case 0x76: /* subq ir1,r2 */ + case 0x77: /* subt ir1,r2 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 reg2 = read_op(); + + read_iregreg(size, reg1, reg2, false); + + op_sub(size); + + write_iregreg(size, reg1, reg2); + } + break; + + case 0x78: /* adbb ir1,r2 */ + case 0x79: /* adbw ir1,r2 */ + case 0x7A: /* adbq ir1,r2 */ + case 0x7B: /* adbt ir1,r2 */ + { + int size = datasize(op); + u8 reg1 = read_op(); + u8 reg2 = read_op(); + + read_iregreg(size, reg1, reg2, false); + + op_addb(size); + + write_iregreg(size, reg1, reg2); + } + break; + case 0x7C: /* addb ir1,r2 */ case 0x7D: /* addw ir1,r2 */ case 0x7E: /* addq ir1,r2 */ @@ -1200,7 +1300,7 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_iregreg(size, reg1, reg2); + read_iregreg(size, reg1, reg2, false); op_add(size); @@ -1209,7 +1309,11 @@ void hcd62121_cpu_device::execute_run() break; case 0x88: /* jump _a16 */ - m_ip = (read_op() << 8) | read_op(); + { + u8 a1 = read_op(); + u8 a2 = read_op(); + m_ip = (a1 << 8) | a2; + } break; case 0x89: /* jumpf cs:a16 */ @@ -1234,8 +1338,30 @@ void hcd62121_cpu_device::execute_run() } break; - case 0x8C: /* unk_8C */ - case 0x8D: /* unk_8D */ + case 0x8C: /* bstack_to_dmem */ + { + int size = m_dsize + 1; + 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--; + m_lar--; + } + } + break; + + case 0x8D: /* fstack_to_dmem */ + { + int size = m_dsize + 1; + 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++; + m_lar++; + } + } + break; + case 0x8E: /* unk_8E */ logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); break; @@ -1244,8 +1370,8 @@ void hcd62121_cpu_device::execute_run() case 0x91: /* retzl */ case 0x92: /* retc */ case 0x93: /* retz */ - case 0x94: /* retzc */ - case 0x95: /* retcl */ + case 0x94: /* retnzh */ + case 0x95: /* retnzl */ case 0x96: /* retnc */ case 0x97: /* retnz */ if (check_cond(op)) @@ -1274,8 +1400,8 @@ void hcd62121_cpu_device::execute_run() case 0xA1: /* jmpzl a16 */ case 0xA2: /* jmpc a16 */ case 0xA3: /* jmpz a16 */ - case 0xA4: /* jmpzc a16 */ - case 0xA5: /* jmpcl a16 */ + case 0xA4: /* jmpnzh a16 */ + case 0xA5: /* jmpnzl a16 */ case 0xA6: /* jmpnc a16 */ case 0xA7: /* jmpnz a16 */ { @@ -1291,8 +1417,8 @@ void hcd62121_cpu_device::execute_run() case 0xA9: /* callzl a16 */ case 0xAA: /* callc a16 */ case 0xAB: /* callz a16 */ - case 0xAC: /* callzc a16 */ - case 0xAD: /* callcl a16 */ + case 0xAC: /* callnzh a16 */ + case 0xAD: /* callnzl a16 */ case 0xAE: /* callnc a16 */ case 0xAF: /* callnz a16 */ { @@ -1335,7 +1461,7 @@ void hcd62121_cpu_device::execute_run() read_op(); break; - case 0xBB: /* jmpcl? a16 */ + case 0xBB: /* jmpcl a16 */ logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); { u8 a1 = read_op(); @@ -1346,12 +1472,7 @@ void hcd62121_cpu_device::execute_run() } break; - case 0xBC: /* unk_BC reg/i8 */ - logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); - read_op(); - break; - - case 0xBF: /* jmpncl? a16 */ + case 0xBF: /* jmpncl a16 */ logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); { u8 a1 = read_op(); @@ -1362,14 +1483,17 @@ void hcd62121_cpu_device::execute_run() } break; - case 0xC0: /* movb reg,i8 */ + //case 0xC0: /* movb reg,i8 */ // TODO - test case 0xC1: /* movw reg,i16 */ - case 0xC2: /* movw reg,i64 */ - case 0xC3: /* movw reg,i80 */ + //case 0xC2: /* movw reg,i64 */ // TODO - test + //case 0xC3: /* movw reg,i80 */ // TODO - test { int size = datasize(op); 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); + for (int i = 0; i < size; i++) { m_reg[(reg + i) & 0x7f] = read_op(); @@ -1383,12 +1507,12 @@ void hcd62121_cpu_device::execute_run() case 0xC7: /* movt (lar),r1 / r1,(lar) */ { int size = datasize(op); - u8 reg1 = read_op(); - u8 reg2 = read_op(); + u8 arg1 = read_op(); + u8 arg2 = read_op(); int pre_inc = 0; int post_inc = 1; - switch (reg1 & 0x60) + switch (arg1 & 0x60) { case 0x00: pre_inc = 0; @@ -1408,23 +1532,29 @@ void hcd62121_cpu_device::execute_run() break; } - if ((reg1 & 0x80) || (reg2 & 0x80)) + if ((arg1 & 0x80) || (arg2 & 0x80)) { - /* (lar) <- r1 */ + /* (lar) <- r2 (immediate or register) */ for (int i = 0; i < size; i++) { m_lar += pre_inc; - m_program->write_byte((m_dseg << 16) | m_lar, m_reg[(reg2 + i) & 0x7f]); + if (arg1 & 0x80) { + m_program->write_byte((m_dseg << 16) | m_lar, arg2); + } + else + { + m_program->write_byte((m_dseg << 16) | m_lar, m_reg[(arg2 + i) & 0x7f]); + } m_lar += post_inc; } } else { - /* r1 <- (lar) */ + /* r2 <- (lar) */ for (int i = 0; i < size; i++) { m_lar += pre_inc; - m_reg[(reg2 + i) & 0x7f] = m_program->read_byte((m_dseg << 16) | m_lar); + m_reg[(arg2 + i) & 0x7f] = m_program->read_byte((m_dseg << 16) | m_lar); m_lar += post_inc; } } @@ -1440,7 +1570,11 @@ void hcd62121_cpu_device::execute_run() u8 reg1 = read_op(); u8 reg2 = read_op(); - read_iregreg(size, reg1, reg2); + if (reg1 & 0x80) { + fatalerror("%02x:%04x: unimplemented swap with immediate encountered\n", m_cseg, m_ip-1); + } + + read_iregreg(size, reg1, reg2, false); for (int i = 0; i < size; i++) { @@ -1451,6 +1585,7 @@ void hcd62121_cpu_device::execute_run() write_iregreg(size, reg1, reg2); write_iregreg2(size, reg1, reg2); + // TODO - are flags affected? } break; @@ -1492,11 +1627,11 @@ void hcd62121_cpu_device::execute_run() break; case 0xD8: /* movb f,reg */ - m_f = m_reg[read_op() & 0x7f]; + m_f = m_reg[read_op() & 0x7f] & 0x3f; break; case 0xD9: /* movb f,i8 */ - m_f = read_op(); + m_f = read_op() & 0x3f; break; case 0xDC: /* movb ds,reg */ @@ -1515,6 +1650,10 @@ void hcd62121_cpu_device::execute_run() } break; + case 0xDF: /* movw lar,i8 */ + m_lar = read_op(); + break; + case 0xE0: /* in0 reg */ { logerror("%06x: in0 read\n", (m_cseg << 16) | m_ip); @@ -1532,16 +1671,26 @@ void hcd62121_cpu_device::execute_run() m_reg[read_op() & 0x7f] = m_ki_cb(); break; - case 0xE6: /* movb reg,PORT */ - m_reg[read_op() & 0x7f] = m_port; + case 0xE3: /* movb reg,dsize */ + { + 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; + } break; - case 0xE3: /* unk_e3 reg/i8 (in?) */ - case 0xE4: /* unk_e4 reg/i8 (in?) */ - case 0xE5: /* unk_e5 reg/i8 (in?) */ - case 0xE7: /* unk_e7 reg/i8 (in?) */ - logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); - read_op(); + case 0xE4: /* movb reg,f */ + { + 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; + } + break; + + case 0xE6: /* movb reg,PORT */ + m_reg[read_op() & 0x7f] = m_port; break; case 0xE8: /* movw r1,lar */ @@ -1553,7 +1702,7 @@ void hcd62121_cpu_device::execute_run() } break; - case 0xEB: /* movw reg,ss */ + case 0xEB: /* movw reg,sp */ { u8 reg1 = read_op(); @@ -1578,9 +1727,7 @@ void hcd62121_cpu_device::execute_run() case 0xF1: /* unk_F1 reg/i8 (out?) */ case 0xF3: /* unk_F3 reg/i8 (out?) */ - case 0xF4: /* unk_F4 reg/i8 (out?) */ case 0xF5: /* unk_F5 reg/i8 (out?) */ - case 0xF6: /* unk_F6 reg/i8 (out?) */ case 0xF7: /* unk_F7 reg/i8 (out?) */ logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); read_op(); @@ -1589,6 +1736,9 @@ void hcd62121_cpu_device::execute_run() 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 + logerror("%02x:%04x: unimplemented instruction %02x encountered\n", m_cseg, m_ip-1, op); break; @@ -1602,9 +1752,7 @@ void hcd62121_cpu_device::execute_run() } while (m_icount > 0); } - -offs_t hcd62121_cpu_device::disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, uint32_t options) +util::disasm_interface *hcd62121_cpu_device::create_disassembler() { - extern CPU_DISASSEMBLE(hcd62121); - return CPU_DISASSEMBLE_NAME(hcd62121)(this, stream, pc, oprom, opram, options); + return new hcd62121_disassembler; } |