summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/hmcs40/hmcs40op.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/hmcs40/hmcs40op.c')
-rw-r--r--src/emu/cpu/hmcs40/hmcs40op.c681
1 files changed, 681 insertions, 0 deletions
diff --git a/src/emu/cpu/hmcs40/hmcs40op.c b/src/emu/cpu/hmcs40/hmcs40op.c
new file mode 100644
index 00000000000..f6faab90360
--- /dev/null
+++ b/src/emu/cpu/hmcs40/hmcs40op.c
@@ -0,0 +1,681 @@
+// license:BSD-3-Clause
+// copyright-holders:hap
+
+// HMCS40 opcode handlers
+
+#include "hmcs40.h"
+
+
+// internal helpers
+
+inline UINT8 hmcs40_cpu_device::ram_r()
+{
+ UINT8 address = (m_x << 4 | m_y) & m_datamask;
+ return m_data->read_byte(address) & 0xf;
+}
+
+inline void hmcs40_cpu_device::ram_w(UINT8 data)
+{
+ UINT8 address = (m_x << 4 | m_y) & m_datamask;
+ m_data->write_byte(address, data & 0xf);
+}
+
+void hmcs40_cpu_device::pop_stack()
+{
+ m_pc = m_stack[0] & m_pcmask;
+ for (int i = 0; i < m_stack_levels-1; i++)
+ m_stack[i] = m_stack[i+1];
+}
+
+void hmcs40_cpu_device::push_stack()
+{
+ for (int i = m_stack_levels-1; i >= 1; i--)
+ m_stack[i] = m_stack[i-1];
+ m_stack[0] = m_pc;
+}
+
+
+
+// instruction set
+
+void hmcs40_cpu_device::op_illegal()
+{
+ logerror("%s unknown opcode $%03X at $%04X\n", tag(), m_op, m_prev_pc);
+}
+
+
+// Register-to-Register Instruction
+
+void hmcs40_cpu_device::op_lab()
+{
+ // LAB: Load A from B
+ m_a = m_b;
+}
+
+void hmcs40_cpu_device::op_lba()
+{
+ // LBA: Load B from A
+ m_b = m_a;
+}
+
+void hmcs40_cpu_device::op_lay()
+{
+ // LAY: Load A from Y
+ m_a = m_y;
+}
+
+void hmcs40_cpu_device::op_laspx()
+{
+ // LASPX: Load A from SPX
+ m_a = m_spx;
+}
+
+void hmcs40_cpu_device::op_laspy()
+{
+ // LASPY: Load A from SPY
+ m_a = m_spy;
+}
+
+void hmcs40_cpu_device::op_xamr()
+{
+ // XAMR m: Exchange A and MR(m)
+
+ // determine MR(Memory Register) location
+ UINT8 address = m_op & 0xf;
+
+ // HMCS42: MR0 on file 0, MR4-MR15 on file 4 (there is no file 1-3)
+ // HMCS43: MR0-MR3 on file 0-3, MR4-MR15 on file 4
+ if (m_family == HMCS40_FAMILY_HMCS42 || m_family == HMCS40_FAMILY_HMCS43)
+ address |= (address < 4) ? (address << 4) : 0x40;
+
+ // HMCS44/45/46/47: all on last file
+ else
+ address |= 0xf0;
+
+ address &= m_datamask;
+ UINT8 old_a = m_a;
+ m_a = m_data->read_byte(address) & 0xf;
+ m_data->write_byte(address, old_a & 0xf);
+}
+
+
+// RAM Address Instruction
+
+void hmcs40_cpu_device::op_lxa()
+{
+ // LXA: Load X from A
+ m_x = m_a;
+}
+
+void hmcs40_cpu_device::op_lya()
+{
+ // LYA: Load Y from A
+ m_y = m_a;
+}
+
+void hmcs40_cpu_device::op_lxi()
+{
+ // LXI i: Load X from Immediate
+ m_x = m_i;
+}
+
+void hmcs40_cpu_device::op_lyi()
+{
+ // LYI i: Load Y from Immediate
+ m_y = m_i;
+}
+
+void hmcs40_cpu_device::op_iy()
+{
+ // IY: Increment Y
+ m_y = (m_y + 1) & 0xf;
+ m_s = (m_y != 0);
+}
+
+void hmcs40_cpu_device::op_dy()
+{
+ // DY: Decrement Y
+ m_y = (m_y - 1) & 0xf;
+ m_s = (m_y != 0xf);
+}
+
+void hmcs40_cpu_device::op_ayy()
+{
+ // AYY: Add A to Y
+ m_y += m_a;
+ m_s = m_y >> 4 & 1;
+ m_y &= 0xf;
+}
+
+void hmcs40_cpu_device::op_syy()
+{
+ // SYY: Subtract A from Y
+ m_y -= m_a;
+ m_s = ~m_y >> 4 & 1;
+ m_y &= 0xf;
+}
+
+void hmcs40_cpu_device::op_xsp()
+{
+ // XSP (XY): Exchange X and SPX, Y and SPY, or NOP if 0
+ if (m_op & 1)
+ {
+ UINT8 old_x = m_x;
+ m_x = m_spx;
+ m_spx = old_x;
+ }
+ if (m_op & 2)
+ {
+ UINT8 old_y = m_y;
+ m_y = m_spy;
+ m_spy = old_y;
+ }
+}
+
+
+// Ram Register Instruction
+
+void hmcs40_cpu_device::op_lam()
+{
+ // LAM (XY): Load A from Memory
+ m_a = ram_r();
+ op_xsp();
+}
+
+void hmcs40_cpu_device::op_lbm()
+{
+ // LBM (XY): Load B from Memory
+ m_b = ram_r();
+ op_xsp();
+}
+
+void hmcs40_cpu_device::op_xma()
+{
+ // XMA (XY): Exchange Memory and A
+ UINT8 old_a = m_a;
+ m_a = ram_r();
+ ram_w(old_a);
+ op_xsp();
+}
+
+void hmcs40_cpu_device::op_xmb()
+{
+ // XMB (XY): Exchange Memory and B
+ UINT8 old_b = m_b;
+ m_b = ram_r();
+ ram_w(old_b);
+ op_xsp();
+}
+
+void hmcs40_cpu_device::op_lmaiy()
+{
+ // LMAIY (X): Load Memory from A, Increment Y
+ ram_w(m_a);
+ op_iy();
+ op_xsp();
+}
+
+void hmcs40_cpu_device::op_lmady()
+{
+ // LMADY (X): Load Memory from A, Decrement Y
+ ram_w(m_a);
+ op_dy();
+ op_xsp();
+}
+
+
+// Immediate Instruction
+
+void hmcs40_cpu_device::op_lmiiy()
+{
+ // LMIIY i: Load Memory from Immediate, Increment Y
+ ram_w(m_i);
+ op_iy();
+}
+
+void hmcs40_cpu_device::op_lai()
+{
+ // LAI i: Load A from Immediate
+ m_a = m_i;
+}
+
+void hmcs40_cpu_device::op_lbi()
+{
+ // LBI i: Load B from Immediate
+ m_b = m_i;
+}
+
+
+// Arithmetic Instruction
+
+void hmcs40_cpu_device::op_ai()
+{
+ // AI i: Add Immediate to A
+ m_a += (m_i);
+ m_s = m_a >> 4 & 1;
+ m_a &= 0xf;
+}
+
+void hmcs40_cpu_device::op_ib()
+{
+ // IB: Increment B
+ m_b = (m_b + 1) & 0xf;
+ m_s = (m_b != 0);
+}
+
+void hmcs40_cpu_device::op_db()
+{
+ // DB: Decrement B
+ m_b = (m_b - 1) & 0xf;
+ m_s = (m_b != 0xf);
+}
+
+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_s = m_c;
+ m_a &= 0xf;
+}
+
+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_s = m_c;
+ m_a &= 0xf;
+}
+
+void hmcs40_cpu_device::op_am()
+{
+ // AM: Add A to Memory
+ m_a += ram_r();
+ m_s = m_a >> 4 & 1;
+ m_a &= 0xf;
+}
+
+void hmcs40_cpu_device::op_daa()
+{
+ // DAA: Decimal Adjust for Addition
+ if (m_c || m_a > 9)
+ {
+ m_a = (m_a + 6) & 0xf;
+ m_c = 1;
+ }
+}
+
+void hmcs40_cpu_device::op_das()
+{
+ // DAS: Decimal Adjust for Subtraction
+ if (!m_c || m_a > 9)
+ {
+ m_a = (m_a + 10) & 0xf;
+ m_c = 0;
+ }
+}
+
+void hmcs40_cpu_device::op_nega()
+{
+ // NEGA: Negate A
+ m_a = (0 - m_a) & 0xf;
+}
+
+void hmcs40_cpu_device::op_comb()
+{
+ // COMB: Complement B
+ m_b ^= 0xf;
+}
+
+void hmcs40_cpu_device::op_sec()
+{
+ // SEC: Set Carry
+ m_c = 1;
+}
+
+void hmcs40_cpu_device::op_rec()
+{
+ // REC: Reset Carry
+ m_c = 0;
+}
+
+void hmcs40_cpu_device::op_tc()
+{
+ // TC: Test Carry
+ m_s = m_c;
+}
+
+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_a &= 0xf;
+}
+
+void hmcs40_cpu_device::op_rotr()
+{
+ // ROTR: Rotate Right A with Carry
+ UINT8 c = m_a & 1;
+ m_a = m_a >> 1 | m_c << 3;
+ m_c = c;
+}
+
+void hmcs40_cpu_device::op_or()
+{
+ // OR: OR A and B
+ m_a |= m_b;
+}
+
+
+// Compare Instruction
+
+void hmcs40_cpu_device::op_mnei()
+{
+ // MNEI i: Memory Not Equal to Immediate
+ m_s = (ram_r() != (m_i));
+}
+
+void hmcs40_cpu_device::op_ynei()
+{
+ // YNEI i: Y Not Equal to Immediate
+ m_s = (m_y != (m_i));
+}
+
+void hmcs40_cpu_device::op_anem()
+{
+ // ANEM: A Not Equal to Memory
+ m_s = (m_a != ram_r());
+}
+
+void hmcs40_cpu_device::op_bnem()
+{
+ // BNEM: B Not Equal to Memory
+ m_s = (m_b != ram_r());
+}
+
+void hmcs40_cpu_device::op_alei()
+{
+ // ALEI i: A Less or Equal to Immediate
+ m_s = (m_a <= (m_i));
+}
+
+void hmcs40_cpu_device::op_alem()
+{
+ // ALEM: A Less or Equal to Memory
+ m_s = (m_a <= ram_r());
+}
+
+void hmcs40_cpu_device::op_blem()
+{
+ // BLEM: B Less or Equal to Memory
+ m_s = (m_b <= ram_r());
+}
+
+
+// RAM Bit Manipulation Instruction
+
+void hmcs40_cpu_device::op_sem()
+{
+ // SEM n: Set Memory Bit
+ ram_w(ram_r() | (1 << (m_op & 3)));
+}
+
+void hmcs40_cpu_device::op_rem()
+{
+ // REM n: Reset Memory Bit
+ ram_w(ram_r() & ~(1 << (m_op & 3)));
+}
+
+void hmcs40_cpu_device::op_tm()
+{
+ // TM n: Test Memory Bit
+ m_s = ram_r() >> (m_op & 3) & 1;
+}
+
+
+// ROM Address Instruction
+
+void hmcs40_cpu_device::op_br()
+{
+ // BR a: Branch on Status 1
+ if (m_s)
+ m_pc = (m_pc & ~0x3f) | (m_op & 0x3f);
+ else
+ m_s = 1;
+}
+
+void hmcs40_cpu_device::op_cal()
+{
+ // CAL a: Subroutine Jump on Status 1
+ if (m_s)
+ {
+ push_stack();
+ m_pc = m_op & 0x3f; // short calls default to page 0
+ }
+ else
+ m_s = 1;
+}
+
+void hmcs40_cpu_device::op_lpu()
+{
+ // LPU u: Load Program Counter Upper on Status 1
+ if (m_s)
+ m_page = m_op & 0x1f;
+ else
+ m_op = 0; // fake nop
+}
+
+void hmcs40_cpu_device::op_tbr()
+{
+ // TBR p: Table Branch
+ UINT16 address = m_a | m_b << 4 | m_c << 8 | (m_op & 7) << 9 | (m_pc & ~0x3f);
+ m_pc = address & m_pcmask;
+}
+
+void hmcs40_cpu_device::op_rtn()
+{
+ // RTN: Return from Subroutine
+ pop_stack();
+}
+
+
+// Interrupt Instruction
+
+void hmcs40_cpu_device::op_seie()
+{
+ // SEIE: Set I/E
+ m_ie = 1;
+}
+
+void hmcs40_cpu_device::op_seif0()
+{
+ // SEIF0: Set IF0
+ m_if[0] = 1;
+}
+
+void hmcs40_cpu_device::op_seif1()
+{
+ // SEIF1: Set IF1
+ m_if[1] = 1;
+}
+
+void hmcs40_cpu_device::op_setf()
+{
+ // SETF: Set TF
+ m_tf = 1;
+}
+
+void hmcs40_cpu_device::op_secf()
+{
+ // SECF: Set CF
+ m_cf = 1;
+}
+
+void hmcs40_cpu_device::op_reie()
+{
+ // REIE: Reset I/E
+ m_ie = 0;
+}
+
+void hmcs40_cpu_device::op_reif0()
+{
+ // REIF0: Reset IF0
+ m_if[0] = 0;
+}
+
+void hmcs40_cpu_device::op_reif1()
+{
+ // REIF1: Reset IF1
+ m_if[1] = 0;
+}
+
+void hmcs40_cpu_device::op_retf()
+{
+ // RETF: Reset TF
+ m_tf = 0;
+}
+
+void hmcs40_cpu_device::op_recf()
+{
+ // RECF: Reset CF
+ m_cf = 0;
+}
+
+void hmcs40_cpu_device::op_ti0()
+{
+ // TI0: Test INT0
+ m_s = m_int[0];
+}
+
+void hmcs40_cpu_device::op_ti1()
+{
+ // TI1: Test INT1
+ m_s = m_int[1];
+}
+
+void hmcs40_cpu_device::op_tif0()
+{
+ // TIF0: Test IF0
+ m_s = m_if[0];
+}
+
+void hmcs40_cpu_device::op_tif1()
+{
+ // TIF1: Test IF1
+ m_s = m_if[1];
+}
+
+void hmcs40_cpu_device::op_ttf()
+{
+ // TTF: Test TF
+ m_s = m_tf;
+}
+
+void hmcs40_cpu_device::op_lti()
+{
+ // LTI i: Load Timer/Counter from Immediate
+ m_tc = m_i;
+ reset_prescaler();
+}
+
+void hmcs40_cpu_device::op_lta()
+{
+ // LTA: Load Timer/Counter from A
+ m_tc = m_a;
+ reset_prescaler();
+}
+
+void hmcs40_cpu_device::op_lat()
+{
+ // LAT: Load A from Timer/Counter
+ m_a = m_tc;
+}
+
+void hmcs40_cpu_device::op_rtni()
+{
+ // RTNI: Return from Interrupt
+ op_seie();
+ op_rtn();
+}
+
+
+// Input/Output Instruction
+
+void hmcs40_cpu_device::op_sed()
+{
+ // SED: Set Discrete I/O Latch
+ write_d(m_y, 1);
+}
+
+void hmcs40_cpu_device::op_red()
+{
+ // RED: Reset Discrete I/O Latch
+ write_d(m_y, 0);
+}
+
+void hmcs40_cpu_device::op_td()
+{
+ // TD: Test Discrete I/O Latch
+ m_s = read_d(m_y);
+}
+
+void hmcs40_cpu_device::op_sedd()
+{
+ // SEDD n: Set Discrete I/O Latch Direct
+ write_d(m_op & 0xf, 1);
+}
+
+void hmcs40_cpu_device::op_redd()
+{
+ // REDD n: Reset Discrete I/O Latch Direct
+ write_d(m_op & 0xf, 0);
+}
+
+void hmcs40_cpu_device::op_lar()
+{
+ // LAR p: Load A from R-Port Register
+ m_a = read_r(m_op & 7);
+}
+
+void hmcs40_cpu_device::op_lbr()
+{
+ // LBR p: Load B from R-Port Register
+ m_b = read_r(m_op & 7);
+}
+
+void hmcs40_cpu_device::op_lra()
+{
+ // LRA p: Load R-Port Register from A
+ write_r(m_op & 7, m_a);
+}
+
+void hmcs40_cpu_device::op_lrb()
+{
+ // LRB p: Load R-Port Register from B
+ write_r(m_op & 7, m_b);
+}
+
+void hmcs40_cpu_device::op_p()
+{
+ // P p: Pattern Generation
+ m_icount--;
+ UINT16 address = m_a | m_b << 4 | m_c << 8 | (m_op & 7) << 9 | (m_pc & ~0x3f);
+ UINT16 o = m_program->read_word((address & m_prgmask) << 1);
+
+ // destination is determined by the 2 highest bits
+ if (o & 0x100)
+ {
+ // B3 B2 B1 B0 A0 A1 A2 A3
+ m_a = BITSWAP8(o,7,6,5,4,0,1,2,3) & 0xf;
+ m_b = o >> 4 & 0xf;
+ }
+ if (o & 0x200)
+ {
+ // R20 R21 R22 R23 R30 R31 R32 R33
+ o = BITSWAP8(o,0,1,2,3,4,5,6,7);
+ write_r(2, o & 0xf);
+ write_r(3, o >> 4 & 0xf);
+ }
+}