hmcs400: fill in most of the opcodes

This commit is contained in:
hap 2024-09-16 22:04:02 +02:00
parent 351dfca54b
commit df4c6d166b
6 changed files with 392 additions and 101 deletions

View File

@ -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);
}

View File

@ -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_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
u16 m_pc; // Program Counter
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
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;

View File

@ -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);
}

View File

@ -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();
state_add(STATE_GENFLAGS, "GENFLAGS", m_st).formatstr("%2s").noshow();
int state_count = 0;
state_add(++state_count, "PC", m_pc).formatstr("%04X"); // 1
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<util::disasm_interface> 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;

View File

@ -45,6 +45,7 @@ protected:
// device_disasm_interface implementation
virtual std::unique_ptr<util::disasm_interface> 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;
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
int m_icount;
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();

View File

@ -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
}
// RAM bit manipulation instructions
void hmcs400_cpu_device::op_inem()
{
// INEM i / INEMD i,d: Immediate Not Equal to Memory
}
void hmcs400_cpu_device::op_anem()
{
// ANEM / ANEMD d: A Not Equal to Memory
}
void hmcs400_cpu_device::op_bnem()
{
// BNEM: B Not Equal to Memory
}
void hmcs400_cpu_device::op_ynei()
{
// YNEI i: Y Not Equal to Immediate
}
void hmcs400_cpu_device::op_ilem()
{
// ILEM i / ILEMD i,d: Immediate Less or Equal to Memory
}
void hmcs400_cpu_device::op_alem()
{
// ALEM / ALEMD d: A Less or Equal to Memory
}
void hmcs400_cpu_device::op_blem()
{
// BLEM: B Less or Equal to Memory
}
void hmcs400_cpu_device::op_alei()
{
// ALEI i: A Less or Equal to Immediate
m_a ^= ram_r();
m_st = (m_a != 0);
}
// 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);
}
// 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();
}