From df4c6d166b3a589b3115b5e2190350d07edaff3d Mon Sep 17 00:00:00 2001 From: hap Date: Mon, 16 Sep 2024 22:04:02 +0200 Subject: hmcs400: fill in most of the opcodes --- src/devices/cpu/hmcs40/hmcs40.cpp | 13 ++- src/devices/cpu/hmcs40/hmcs40.h | 64 +++++------ src/devices/cpu/hmcs40/hmcs40op.cpp | 19 ++-- src/devices/cpu/hmcs400/hmcs400.cpp | 85 +++++++++++++-- src/devices/cpu/hmcs400/hmcs400.h | 34 ++++-- src/devices/cpu/hmcs400/hmcs400op.cpp | 198 +++++++++++++++++++++++++++++++++- 6 files changed, 352 insertions(+), 61 deletions(-) diff --git a/src/devices/cpu/hmcs40/hmcs40.cpp b/src/devices/cpu/hmcs40/hmcs40.cpp index 3ef73181693..723934604ac 100644 --- a/src/devices/cpu/hmcs40/hmcs40.cpp +++ b/src/devices/cpu/hmcs40/hmcs40.cpp @@ -159,6 +159,8 @@ void hmcs40_cpu_device::device_start() m_eint_line = 0; m_halt = 0; m_prescaler = 0; + m_block_int = false; + m_pc = 0; m_prev_pc = 0; m_page = 0; @@ -170,6 +172,7 @@ void hmcs40_cpu_device::device_start() m_spy = 0; m_s = 1; m_c = 0; + m_tc = 0; m_cf = 0; m_ie = 0; @@ -177,7 +180,6 @@ void hmcs40_cpu_device::device_start() memset(m_if, 0, sizeof(m_if)); m_tf = 0; memset(m_int, 0, sizeof(m_int)); - m_block_int = false; memset(m_r, 0, sizeof(m_r)); m_d = 0; @@ -188,6 +190,9 @@ void hmcs40_cpu_device::device_start() save_item(NAME(m_i)); save_item(NAME(m_eint_line)); save_item(NAME(m_halt)); + save_item(NAME(m_prescaler)); + save_item(NAME(m_block_int)); + save_item(NAME(m_pc)); save_item(NAME(m_prev_pc)); save_item(NAME(m_page)); @@ -199,8 +204,8 @@ void hmcs40_cpu_device::device_start() save_item(NAME(m_spy)); save_item(NAME(m_s)); save_item(NAME(m_c)); + save_item(NAME(m_tc)); - save_item(NAME(m_prescaler)); save_item(NAME(m_cf)); save_item(NAME(m_ie)); save_item(NAME(m_iri)); @@ -208,7 +213,6 @@ void hmcs40_cpu_device::device_start() save_item(NAME(m_if)); save_item(NAME(m_tf)); save_item(NAME(m_int)); - save_item(NAME(m_block_int)); save_item(NAME(m_r)); save_item(NAME(m_d)); @@ -226,6 +230,9 @@ void hmcs40_cpu_device::device_start() state_add(++m_state_count, "Y", m_y).formatstr("%01X"); // 6 state_add(++m_state_count, "SPY", m_spy).formatstr("%01X"); // 7 + state_add(++m_state_count, "S", m_s).formatstr("%01X").noshow(); // 8 + state_add(++m_state_count, "C", m_c).formatstr("%01X").noshow(); // 9 + set_icountptr(m_icount); } diff --git a/src/devices/cpu/hmcs40/hmcs40.h b/src/devices/cpu/hmcs40/hmcs40.h index 1b573e4a9e3..c9316bbe69a 100644 --- a/src/devices/cpu/hmcs40/hmcs40.h +++ b/src/devices/cpu/hmcs40/hmcs40.h @@ -139,45 +139,47 @@ protected: int m_icount; int m_state_count; - const int m_pcwidth; // Program Counter bit-width + const int m_pcwidth; // program counter bit-width const int m_prgwidth; const int m_datawidth; - const int m_family; // MCU family (42-47) - const u16 m_polarity; // i/o polarity (pmos vs cmos) - const int m_stack_levels; // number of callstack levels + const int m_family; // MCU family (42-47) + const u16 m_polarity; // i/o polarity (pmos vs cmos) + const int m_stack_levels; // number of callstack levels int m_pcmask; int m_prgmask; int m_datamask; - u16 m_stack[4]; // max 4 - u16 m_op; // current opcode + + u16 m_stack[4]; // max 4 + u16 m_op; // current opcode u16 m_prev_op; - u8 m_i; // 4-bit immediate opcode param - int m_eint_line; // which input_line caused an interrupt - int m_halt; // internal HLT state - u8 m_prescaler; // internal timer prescaler - bool m_block_int; // block interrupt on next cycle + u8 m_i; // 4-bit immediate opcode param + int m_eint_line; // which input_line caused an interrupt + int m_halt; // internal HLT state + u8 m_prescaler; // internal timer prescaler + bool m_block_int; // block interrupt on next cycle - u16 m_pc; // Program Counter + u16 m_pc; // program counter u16 m_prev_pc; - u8 m_page; // LPU prepared page - u8 m_a; // 4-bit Accumulator - u8 m_b; // 4-bit B register - u8 m_x; // 1/3/4-bit X register - u8 m_spx; // 1/3/4-bit SPX register - u8 m_y; // 4-bit Y register - u8 m_spy; // 4-bit SPY register - u8 m_s; // Status F/F (F/F = flip-flop) - u8 m_c; // Carry F/F - u8 m_tc; // Timer/Counter - u8 m_cf; // CF F/F (timer mode or counter mode) - u8 m_ie; // I/E(Interrupt Enable) F/F - u8 m_iri; // external interrupt pending I/RI F/F - u8 m_irt; // timer interrupt pending I/RT F/F - u8 m_if[2]; // external interrupt mask IF0,1 F/F - u8 m_tf; // timer interrupt mask TF F/F - u8 m_int[2]; // INT0/1 pins state - u8 m_r[8]; // R outputs state - u16 m_d; // D pins state + u8 m_page; // LPU prepared page + u8 m_a; // 4-bit accumulator + u8 m_b; // 4-bit B register + u8 m_x; // 1/3/4-bit X register + u8 m_spx; // 1/3/4-bit SPX register + u8 m_y; // 4-bit Y register + u8 m_spy; // 4-bit SPY register + u8 m_s; // status F/F (F/F = flip-flop) + u8 m_c; // carry F/F + + u8 m_tc; // timer/counter + u8 m_cf; // CF F/F (timer mode or counter mode) + u8 m_ie; // I/E (interrupt enable) F/F + u8 m_iri; // external interrupt pending I/RI F/F + u8 m_irt; // timer interrupt pending I/RT F/F + u8 m_if[2]; // external interrupt mask IF0,1 F/F + u8 m_tf; // timer interrupt mask TF F/F + u8 m_int[2]; // INT0/1 pins state + u8 m_r[8]; // R outputs state + u16 m_d; // D pins state // I/O handlers devcb_read8::array<8> m_read_r; diff --git a/src/devices/cpu/hmcs40/hmcs40op.cpp b/src/devices/cpu/hmcs40/hmcs40op.cpp index c8b6032ffd1..a2c201946cb 100644 --- a/src/devices/cpu/hmcs40/hmcs40op.cpp +++ b/src/devices/cpu/hmcs40/hmcs40op.cpp @@ -36,7 +36,6 @@ void hmcs40_cpu_device::push_stack() } - // instruction set void hmcs40_cpu_device::op_illegal() @@ -144,7 +143,7 @@ void hmcs40_cpu_device::op_ayy() { // AYY: Add A to Y m_y += m_a; - m_s = m_y >> 4 & 1; + m_s = BIT(m_y, 4); m_y &= 0xf; } @@ -152,7 +151,7 @@ void hmcs40_cpu_device::op_syy() { // SYY: Subtract A from Y m_y -= m_a; - m_s = ~m_y >> 4 & 1; + m_s = BIT(~m_y, 4); m_y &= 0xf; } @@ -253,7 +252,7 @@ void hmcs40_cpu_device::op_ai() { // AI i: Add Immediate to A m_a += m_i; - m_s = m_a >> 4 & 1; + m_s = BIT(m_a, 4); m_a &= 0xf; } @@ -275,7 +274,7 @@ void hmcs40_cpu_device::op_amc() { // AMC: Add A to Memory with Carry m_a += ram_r() + m_c; - m_c = m_a >> 4 & 1; + m_c = BIT(m_a, 4); m_s = m_c; m_a &= 0xf; } @@ -284,7 +283,7 @@ void hmcs40_cpu_device::op_smc() { // SMC: Subtract A from Memory with Carry m_a = ram_r() - m_a - (m_c ^ 1); - m_c = ~m_a >> 4 & 1; + m_c = BIT(~m_a, 4); m_s = m_c; m_a &= 0xf; } @@ -293,7 +292,7 @@ void hmcs40_cpu_device::op_am() { // AM: Add A to Memory m_a += ram_r(); - m_s = m_a >> 4 & 1; + m_s = BIT(m_a, 4); m_a &= 0xf; } @@ -351,7 +350,7 @@ void hmcs40_cpu_device::op_rotl() { // ROTL: Rotate Left A with Carry m_a = m_a << 1 | m_c; - m_c = m_a >> 4 & 1; + m_c = BIT(m_a, 4); m_a &= 0xf; } @@ -375,7 +374,7 @@ void hmcs40_cpu_device::op_or() void hmcs40_cpu_device::op_mnei() { // MNEI i: Memory Not Equal to Immediate - m_s = (ram_r() != m_i); + m_s = (m_i != ram_r()); } void hmcs40_cpu_device::op_ynei() @@ -432,7 +431,7 @@ void hmcs40_cpu_device::op_rem() void hmcs40_cpu_device::op_tm() { // TM n: Test Memory Bit - m_s = ram_r() >> (m_op & 3) & 1; + m_s = BIT(ram_r(), m_op & 3); } diff --git a/src/devices/cpu/hmcs400/hmcs400.cpp b/src/devices/cpu/hmcs400/hmcs400.cpp index 4d8212e29fc..261e482ac8c 100644 --- a/src/devices/cpu/hmcs400/hmcs400.cpp +++ b/src/devices/cpu/hmcs400/hmcs400.cpp @@ -4,8 +4,13 @@ Hitachi HMCS400 MCU family cores -It's the successor to HMCS40, around 5 times faster, and more versatile peripherals, -like a serial interface. It was mainly used in consumer electronics, not much in games. +It's the successor to HMCS40, it was mainly used in consumer electronics, not +much in games. + +Compared to HMCS40, it accepts a higher clock speed, and it has more versatile +peripherals, like a serial interface. The opcodes were mostly kept the same. +They added an extra RAM addressing mode, and interrupt-related opcodes were +removed (interrupt flags are via memory-mapped I/O). TODO: - do the LAW/LWA opcodes not work on early revisions of HMCS400? the 1988 user @@ -160,21 +165,57 @@ void hmcs400_cpu_device::device_start() // zerofill m_pc = 0; m_prev_pc = 0; + m_sp = 0; m_op = 0; m_param = 0; + m_i = 0; + + m_a = 0; + m_b = 0; + m_w = 0; + m_x = 0; + m_spx = 0; + m_y = 0; + m_spy = 0; + m_st = 0; + m_ca = 0; // register for savestates save_item(NAME(m_pc)); save_item(NAME(m_prev_pc)); + save_item(NAME(m_sp)); save_item(NAME(m_op)); save_item(NAME(m_param)); + save_item(NAME(m_i)); + + save_item(NAME(m_a)); + save_item(NAME(m_b)); + save_item(NAME(m_w)); + save_item(NAME(m_x)); + save_item(NAME(m_spx)); + save_item(NAME(m_y)); + save_item(NAME(m_spy)); + save_item(NAME(m_st)); + save_item(NAME(m_ca)); // register state for debugger state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%04X").noshow(); state_add(STATE_GENPCBASE, "CURPC", m_pc).formatstr("%04X").noshow(); - - int state_count = 0; - state_add(++state_count, "PC", m_pc).formatstr("%04X"); // 1 + state_add(STATE_GENFLAGS, "GENFLAGS", m_st).formatstr("%2s").noshow(); + + m_state_count = 0; + state_add(++m_state_count, "PC", m_pc).formatstr("%04X"); // 1 + state_add(++m_state_count, "SP", m_sp).formatstr("%03X"); // 2 + state_add(++m_state_count, "A", m_a).formatstr("%01X"); // 3 + state_add(++m_state_count, "B", m_b).formatstr("%01X"); // 4 + state_add(++m_state_count, "W", m_w).formatstr("%01X"); // 5 + state_add(++m_state_count, "X", m_x).formatstr("%01X"); // 6 + state_add(++m_state_count, "SPX", m_spx).formatstr("%01X"); // 7 + state_add(++m_state_count, "Y", m_y).formatstr("%01X"); // 8 + state_add(++m_state_count, "SPY", m_spy).formatstr("%01X"); // 9 + + state_add(++m_state_count, "ST", m_st).formatstr("%01X").noshow(); // 10 + state_add(++m_state_count, "CA", m_ca).formatstr("%01X").noshow(); // 11 set_icountptr(m_icount); } @@ -182,6 +223,28 @@ void hmcs400_cpu_device::device_start() void hmcs400_cpu_device::device_reset() { m_pc = 0; + m_sp = 0x3ff; + m_st = 1; +} + + +//------------------------------------------------- +// disasm +//------------------------------------------------- + +void hmcs400_cpu_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + str = string_format("%c%c", + m_ca ? 'C':'c', + m_st ? 'S':'s' + ); + break; + + default: break; + } } std::unique_ptr hmcs400_cpu_device::create_disassembler() @@ -219,11 +282,16 @@ device_memory_interface::space_config_vector hmcs400_cpu_device::memory_space_co // execute //------------------------------------------------- +void hmcs400_cpu_device::cycle() +{ + m_icount--; +} + u16 hmcs400_cpu_device::fetch() { u16 data = m_program->read_word(m_pc); m_pc = (m_pc + 1) & 0x3fff; - m_icount--; + cycle(); return data & 0x3ff; } @@ -236,12 +304,13 @@ void hmcs400_cpu_device::execute_run() m_prev_pc = m_pc; debugger_instruction_hook(m_pc); m_op = fetch(); + m_i = m_op & 0xf; // 2-byte opcodes / RAM address if ((m_op >= 0x100 && m_op < 0x140) || (m_op >= 0x150 && m_op < 0x1b0)) m_param = fetch(); else - m_param = 0; + m_param = (m_w << 8 | m_x << 4 | m_y) & 0x3ff; // handle opcode switch (m_op & 0x3f0) @@ -255,7 +324,7 @@ void hmcs400_cpu_device::execute_run() case 0x150: op_jmpl(); break; case 0x160: op_call(); break; case 0x170: op_brl(); break; - case 0x1a0: op_lmid(); break; + case 0x1a0: op_lmi(); break; case 0x1b0: op_p(); break; case 0x200: op_lbi(); break; diff --git a/src/devices/cpu/hmcs400/hmcs400.h b/src/devices/cpu/hmcs400/hmcs400.h index 174668a3189..965131df530 100644 --- a/src/devices/cpu/hmcs400/hmcs400.h +++ b/src/devices/cpu/hmcs400/hmcs400.h @@ -45,6 +45,7 @@ protected: // device_disasm_interface implementation virtual std::unique_ptr create_disassembler() override; + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; // memory maps void program_map(address_map &map); @@ -55,26 +56,47 @@ protected: address_space *m_program; address_space *m_data; + int m_icount; + int m_state_count; + const u32 m_rom_size; // ROM size in 16-bit words const u32 m_ram_size; // RAM size minus the 64-byte stack bool m_has_div; // MCU supports divider mask option u8 m_divider; // system clock divider - u16 m_pc; + u16 m_pc; // program counter u16 m_prev_pc; - u16 m_op; - u16 m_param; - - int m_icount; + u16 m_sp; // stack pointer + u16 m_op; // current opcode + u16 m_param; // 2-byte opcode param or RAM address + u8 m_i; // 4-bit immediate opcode param + + u8 m_a; // 4-bit accumulator + u8 m_b; // 4-bit B register + u8 m_w; // 2-bit W register + u8 m_x; // 4-bit X register + u8 m_spx; // 4-bit SPX register + u8 m_y; // 4-bit Y register + u8 m_spy; // 4-bit SPY register + u8 m_st; // status flag + u8 m_ca; // carry flag u16 fetch(); + // misc internal helpers + u8 ram_r(u8 mem_mask = 0xf); + void ram_w(u8 data, u8 mem_mask = 0xf); + void pop_stack(); + void push_stack(); + + void cycle(); + // opcode handlers void op_illegal(); void op_lai(); void op_lbi(); - void op_lmid(); + void op_lmi(); void op_lmiiy(); void op_lab(); diff --git a/src/devices/cpu/hmcs400/hmcs400op.cpp b/src/devices/cpu/hmcs400/hmcs400op.cpp index aa212e77c87..b9656db83b5 100644 --- a/src/devices/cpu/hmcs400/hmcs400op.cpp +++ b/src/devices/cpu/hmcs400/hmcs400op.cpp @@ -9,6 +9,46 @@ // internal helpers +inline u8 hmcs400_cpu_device::ram_r(u8 mem_mask) +{ + return m_data->read_byte(m_param & 0x3ff, mem_mask & 0xf) & 0xf; +} + +inline void hmcs400_cpu_device::ram_w(u8 data, u8 mem_mask) +{ + m_data->write_byte(m_param & 0x3ff, data & 0xf, mem_mask & 0xf); +} + +void hmcs400_cpu_device::pop_stack() +{ + u16 data = 0; + for (int i = 0; i < 4; i++) + { + m_sp = ((m_sp + 1) | 0x3c0) & 0x3ff; + data = data << 4 | (m_data->read_byte(m_sp) & 0xf); + } + + if (m_op & 1) + { + // RTNI restores CA and ST + m_ca = BIT(data, 7); + m_st = BIT(data, 15); + } + m_pc = (data & 0x7f00) >> 1 | (data & 0x7f); +} + +void hmcs400_cpu_device::push_stack() +{ + u16 data = (m_pc << 1 & 0x7f00) | (m_pc & 0x7f) | m_ca << 7 | m_st << 15; + m_sp |= 0x3c0; + + for (int i = 0; i < 4; i++) + { + m_data->write_byte(m_sp, data & 0xf); + data >>= 4; + m_sp = ((m_sp - 1) | 0x3c0) & 0x3ff; + } +} // instruction set @@ -24,21 +64,26 @@ void hmcs400_cpu_device::op_illegal() void hmcs400_cpu_device::op_lai() { // LAI i: Load A from Immediate + m_a = m_i; } void hmcs400_cpu_device::op_lbi() { // LBI i: Load B from Immediate + m_b = m_i; } -void hmcs400_cpu_device::op_lmid() +void hmcs400_cpu_device::op_lmi() { // LMID i,d: Load Memory from Immediate + ram_w(m_i); } void hmcs400_cpu_device::op_lmiiy() { // LMIIY i: Load Memory from Immediate, Increment Y + op_lmi(); + op_iy(); } @@ -47,41 +92,53 @@ void hmcs400_cpu_device::op_lmiiy() void hmcs400_cpu_device::op_lab() { // LAB: Load A from B + m_a = m_b; } void hmcs400_cpu_device::op_lba() { // LBA: Load B from A + m_b = m_a; } void hmcs400_cpu_device::op_law() { // LAW: Load A from W + m_a = m_w; } void hmcs400_cpu_device::op_lay() { // LAY: Load A from Y + m_a = m_y; } void hmcs400_cpu_device::op_laspx() { // LASPX: Load A from SPX + m_a = m_spx; } void hmcs400_cpu_device::op_laspy() { // LASPY: Load A from SPY + m_a = m_spy; } void hmcs400_cpu_device::op_lamr() { // LAMR m: Load A from MR + m_param = 0x20 | m_i; + m_a = ram_r(); } void hmcs400_cpu_device::op_xmra() { // XMRA m: Exchange MR and A + m_param = 0x20 | m_i; + u8 old_a = m_a; + m_a = ram_r(); + ram_w(old_a); } @@ -90,56 +147,84 @@ void hmcs400_cpu_device::op_xmra() void hmcs400_cpu_device::op_lwi() { // LWI i: Load W from Immediate + m_w = m_i; } void hmcs400_cpu_device::op_lxi() { // LXI i: Load X from Immediate + m_x = m_i; } void hmcs400_cpu_device::op_lyi() { // LYI i: Load Y from Immediate + m_y = m_i; } void hmcs400_cpu_device::op_lwa() { // LWA: Load W from A + m_w = m_a & 3; } void hmcs400_cpu_device::op_lxa() { // LXA: Load X from A + m_x = m_a; } void hmcs400_cpu_device::op_lya() { // LYA: Load Y from A + m_y = m_a; } void hmcs400_cpu_device::op_iy() { // IY: Increment Y + m_y = (m_y + 1) & 0xf; + m_st = (m_y != 0); } void hmcs400_cpu_device::op_dy() { // DY: Decrement Y + m_y = (m_y - 1) & 0xf; + m_st = (m_y != 0xf); } void hmcs400_cpu_device::op_ayy() { // AYY: Add A to Y + m_y += m_a; + m_st = BIT(m_y, 4); + m_y &= 0xf; } void hmcs400_cpu_device::op_syy() { // SYY: Subtract A from Y + m_y -= m_a; + m_st = BIT(~m_y, 4); + m_y &= 0xf; } void hmcs400_cpu_device::op_xsp() { // XSP(XY): Exchange X and SPX, Y and SPY, or NOP if 0 + if (m_op & 1) + { + u8 old_x = m_x; + m_x = m_spx; + m_spx = old_x; + } + if (m_op & 2) + { + u8 old_y = m_y; + m_y = m_spy; + m_spy = old_y; + } } @@ -148,36 +233,54 @@ void hmcs400_cpu_device::op_xsp() void hmcs400_cpu_device::op_lam() { // LAM(XY) / LAMD d: Load A from Memory + m_a = ram_r(); + op_xsp(); } void hmcs400_cpu_device::op_lbm() { // LBM(XY): Load B from Memory + m_b = ram_r(); + op_xsp(); } void hmcs400_cpu_device::op_lma() { // LMA(XY) / LMAD d: Load Memory from A + ram_w(m_a); + op_xsp(); } void hmcs400_cpu_device::op_lmaiy() { // LMAIY(X): Load Memory from A, Increment Y + op_lma(); + op_iy(); } void hmcs400_cpu_device::op_lmady() { // LMADY(X): Load Memory from A, Decrement Y + op_lma(); + op_dy(); } void hmcs400_cpu_device::op_xma() { // XMA(XY) / XMAD d: Exchange Memory and A + u8 old_a = m_a; + m_a = ram_r(); + ram_w(old_a); + op_xsp(); } void hmcs400_cpu_device::op_xmb() { // XMB(XY): Exchange Memory and B + u8 old_b = m_b; + m_b = ram_r(); + ram_w(old_b); + op_xsp(); } @@ -186,157 +289,217 @@ void hmcs400_cpu_device::op_xmb() void hmcs400_cpu_device::op_ai() { // AI i: Add Immediate to A + m_a += m_i; + m_st = BIT(m_a, 4); + m_a &= 0xf; } void hmcs400_cpu_device::op_ib() { // IB: Increment B + m_b = (m_b + 1) & 0xf; + m_st = (m_b != 0); } void hmcs400_cpu_device::op_db() { // DB: Decrement B + m_b = (m_b - 1) & 0xf; + m_st = (m_b != 0xf); } void hmcs400_cpu_device::op_daa() { // DAA: Decimal Adjust for Addition + if (m_ca || m_a > 9) + { + m_a = (m_a + 6) & 0xf; + m_ca = 1; + } } void hmcs400_cpu_device::op_das() { // DAS: Decimal Adjust for Subtraction + if (!m_ca || m_a > 9) + { + m_a = (m_a + 10) & 0xf; + m_ca = 0; + } } void hmcs400_cpu_device::op_nega() { // NEGA: Negate A + m_a = (0 - m_a) & 0xf; } void hmcs400_cpu_device::op_comb() { // COMB: Complement B + m_b ^= 0xf; } void hmcs400_cpu_device::op_rotr() { // ROTR: Rotate Right with Carry + u8 ca = m_a & 1; + m_a = m_a >> 1 | m_ca << 3; + m_ca = ca; } void hmcs400_cpu_device::op_rotl() { // ROTL: Rotate Left with Carry + m_a = m_a << 1 | m_ca; + m_ca = BIT(m_a, 4); + m_a &= 0xf; } void hmcs400_cpu_device::op_sec() { // SEC: Set Carry + m_ca = 1; } void hmcs400_cpu_device::op_rec() { // REC: Reset Carry + m_ca = 0; } void hmcs400_cpu_device::op_tc() { // TC: Test Carry + m_st = m_ca; } void hmcs400_cpu_device::op_am() { // AM / AMD d: Add A to Memory + m_a += ram_r(); + m_st = BIT(m_a, 4); + m_a &= 0xf; } void hmcs400_cpu_device::op_amc() { // AMC / AMCD d: Add A to Memory with Carry + m_a += ram_r() + m_ca; + m_ca = BIT(m_a, 4); + m_st = m_ca; + m_a &= 0xf; } void hmcs400_cpu_device::op_smc() { // SMC / SMCD d: Subtract A from Memory with Carry + m_a = ram_r() - m_a - (m_ca ^ 1); + m_ca = BIT(~m_a, 4); + m_st = m_ca; + m_a &= 0xf; } void hmcs400_cpu_device::op_or() { // OR: Or A with B + m_a |= m_b; } void hmcs400_cpu_device::op_anm() { // ANM / ANMD d: And Memory with A + m_a &= ram_r(); + m_st = (m_a != 0); } void hmcs400_cpu_device::op_orm() { // ORM / ORMD d: Or Memory with A + m_a |= ram_r(); + m_st = (m_a != 0); } void hmcs400_cpu_device::op_eorm() { // EORM / EORMD d: Exclusive Or Memory with A + m_a ^= ram_r(); + m_st = (m_a != 0); } -// RAM bit manipulation instructions +// compare instructions void hmcs400_cpu_device::op_inem() { // INEM i / INEMD i,d: Immediate Not Equal to Memory + m_st = (m_i != ram_r()); } void hmcs400_cpu_device::op_anem() { // ANEM / ANEMD d: A Not Equal to Memory + m_st = (m_a != ram_r()); } void hmcs400_cpu_device::op_bnem() { // BNEM: B Not Equal to Memory + m_st = (m_b != ram_r()); } void hmcs400_cpu_device::op_ynei() { // YNEI i: Y Not Equal to Immediate + m_st = (m_y != m_i); } void hmcs400_cpu_device::op_ilem() { // ILEM i / ILEMD i,d: Immediate Less or Equal to Memory + m_st = (m_i <= ram_r()); } void hmcs400_cpu_device::op_alem() { // ALEM / ALEMD d: A Less or Equal to Memory + m_st = (m_a <= ram_r()); } void hmcs400_cpu_device::op_blem() { // BLEM: B Less or Equal to Memory + m_st = (m_b <= ram_r()); } void hmcs400_cpu_device::op_alei() { // ALEI i: A Less or Equal to Immediate + m_st = (m_a <= m_i); } -// compare instructions +// RAM bit manipulation instructions void hmcs400_cpu_device::op_sem() { // SEM n / SEMD n,d: Set Memory Bit + u8 mask = 1 << (m_op & 3); + ram_w(ram_r(~mask) | mask, mask); } void hmcs400_cpu_device::op_rem() { // REM n / REMD n,d: Reset Memory Bit + u8 mask = 1 << (m_op & 3); + ram_w(ram_r(~mask) & ~mask, mask); } void hmcs400_cpu_device::op_tm() { // TM n / TMD n,d: Test Memory Bit + u8 mask = 1 << (m_op & 3); + m_st = (ram_r(mask) & mask) ? 1 : 0; } @@ -345,41 +508,70 @@ void hmcs400_cpu_device::op_tm() void hmcs400_cpu_device::op_br() { // BR b: Branch on Status 1 + if (m_st) + m_pc = (m_pc & ~0xff) | (m_op & 0xff); + else + m_st = 1; } void hmcs400_cpu_device::op_brl() { // BRL u: Long Branch on Status 1 + if (m_st) + op_jmpl(); + else + m_st = 1; } void hmcs400_cpu_device::op_jmpl() { // JMPL u: Long Jump Unconditionally + m_pc = m_i << 10 | m_param; } void hmcs400_cpu_device::op_cal() { // CAL a: Subroutine Jump on Status 1 + if (m_st) + { + push_stack(); + m_pc = m_op & 0x3f; + cycle(); + } + else + m_st = 1; } void hmcs400_cpu_device::op_call() { // CALL u: Long Subroutine Jump on Status 1 + if (m_st) + { + push_stack(); + op_jmpl(); + } + else + m_st = 1; } void hmcs400_cpu_device::op_tbr() { // TBR p: Table Branch + m_pc = m_i << 8 | m_b << 4 | m_a; } void hmcs400_cpu_device::op_rtn() { // RTN: Return from Subroutine + pop_stack(); + cycle(); + cycle(); } void hmcs400_cpu_device::op_rtni() { // RTNI: Return from Interrupt + op_rtn(); } -- cgit v1.2.3