#![macro_use]
macro_rules! define_instructions_scoped {
($flags:ident, $pc:ident, $cpu:ident, $control:ident, $tsc:ident) => {
macro_rules! run_mnemonic {
( NOP * @@@ $code0:expr, $code1:expr) => {
cpu_debug!([$code0, $code1] "NOP*")
};
( DAA @@@ $code:expr) => {
instr_acc_op!(daa; [$code])
};
( CPL @@@ $code:expr) => {
instr_acc_op!(cpl; [$code])
};
( NEG @@@ $code0:expr, $code1:expr) => {
instr_acc_op!(neg; [$code0, $code1])
};
( CCF @@@ $code:expr) => {
{
cpu_debug!([$code] CCF );
let q = $cpu.flavour.get_q($cpu.af.get8hi(), $flags);
ops::ccf(q, &mut $flags);
flags_op!();
}
};
( SCF @@@ $code:expr) => {
{
cpu_debug!([$code] SCF );
let q = $cpu.flavour.get_q($cpu.af.get8hi(), $flags);
ops::scf(q, &mut $flags);
flags_op!();
}
};
( NOP @@@ $code:expr) => {
cpu_debug!([$code] NOP )
};
( DI @@@ $code:expr) => {
{
cpu_debug!([$code] DI );
$cpu.disable_interrupts();
}
};
( EI break $main:tt @@@ $code:expr) => {
{
cpu_debug!([$code] EI );
$cpu.enable_interrupts();
break $main LoopExitReason::EnableInt;
}
};
( IM $mode:tt @@@ $code0:expr, $code1:expr) => {
{
cpu_debug!([$code0, $code1] IM m:$mode);
$cpu.set_im(interrupt_mode!($mode));
}
};
( LD r,r | LD (HL),r | LD r,(HL) | HALT break $main:tt @@@ $code:expr) => {
{
match Reg8::tuple_from_b5_3_and_b2_0($code) {
(Ok(dst), Ok(src)) => {
cpu_debug!([$code] LD r:dst, r:src);
$cpu.load_reg(dst, src, None);
}
(Ok(dst), Err(_)) => {
cpu_debug!([$code] LD r:dst, addr:HL);
let n: u8 = read_mem8_reg16!(<- [hl]);
$cpu.set_reg(dst, None, n);
}
(Err(_), Ok(src)) => {
cpu_debug!([$code] LD addr:HL, r:src);
write_mem8_reg16!([hl] <- $cpu.get_reg(src, None));
}
_ => { cpu_debug!([$code] HALT);
$pc -= Wrapping(1);
$cpu.halt();
break $main LoopExitReason::Halt;
}
}
}
};
( LD r,n | LD (HL),n @@@ $code:expr) => {
{ let n: u8 = fetch_next_imm8!();
match Reg8::from_b5_3($code) {
Ok(dst) => {
cpu_debug!([$code, n] LD r:dst, n:n);
$cpu.set_reg(dst, None, n);
}
Err(_) => { cpu_debug!([$code, n] LD addr:HL, n:n);
write_mem8_reg16!([hl] <- n);
}
}
}
};
( LD A,(BC) @@@ $code:expr) => {
instr_ld_rp! { A <- [bc]; [$code] }
};
( LD (BC),A @@@ $code:expr) => {
instr_ld_rp! { [bc] <- A; [$code] }
};
( LD A,(DE) @@@ $code:expr) => {
instr_ld_rp! { A <- [de]; [$code] }
};
( LD (DE),A @@@ $code:expr) => {
instr_ld_rp! { [de] <- A; [$code] }
};
( LD A,(nn) @@@ $code:expr) => {
{ let nn: u16 = fetch_next_imm16!();
cpu_debug!([$code, nn.lsb(), nn.msb()] LD r:A, adnn:nn);
$cpu.ld_a_from_mem8($control, $tsc, nn);
}
};
( LD (nn),A @@@ $code:expr) => {
{ let nn: u16 = fetch_next_imm16!();
cpu_debug!([$code, nn.lsb(), nn.msb()] LD adnn:nn, r:A);
$cpu.ld_mem8_from_a($control, $tsc, nn);
}
};
( LD A,I @@@ $code0:expr, $code1:expr) => {
instr_ld_ir! { A <- I; [$code0, $code1] }
};
( LD I,A @@@ $code0:expr, $code1:expr) => {
instr_ld_ir! { I <- A; [$code0, $code1] }
};
( LD A,R @@@ $code0:expr, $code1:expr) => {
instr_ld_ir! { A <- R; [$code0, $code1] }
};
( LD R,A @@@ $code0:expr, $code1:expr) => {
instr_ld_ir! { R <- A; [$code0, $code1] }
};
( LD dd,nn @@@ $code:expr) => {
{ let nn: u16 = fetch_next_imm16!();
let dst = Reg16::from($code);
cpu_debug!([$code, nn.lsb(), nn.msb()] LD rr:dst, nn:nn);
$cpu.reg16_mut(dst).set16(nn);
}
};
( LD HL,(nn) @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!();
cpu_debug!([$code, addr.lsb(), addr.msb()] LD rr:HL, adnn:addr);
let nn: u16 = read_mem16_addr16!(<- [addr] memptr=addr+1);
$cpu.regs.hl.set16(nn);
}
};
( LD (nn),HL @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!();
cpu_debug!([$code, addr.lsb(), addr.msb()] LD adnn:addr, rr:HL);
write_mem16_addr16!([addr] <- $cpu.regs.hl.get(); memptr=addr+1);
}
};
( LD dd,(nn) @@@ $code0:expr, $code1:expr) => {
{ let addr: u16 = fetch_next_imm16!();
let reg = Reg16::from($code1);
cpu_debug!([$code0, $code1, addr.lsb(), addr.msb()] LD rr:reg, adnn:addr);
let nn: u16 = read_mem16_addr16!(<- [addr] memptr=addr+1);
$cpu.reg16_mut(reg).set16(nn);
}
};
( LD (nn),dd @@@ $code0:expr, $code1:expr) => {
{ let addr: u16 = fetch_next_imm16!();
let reg = Reg16::from($code1);
cpu_debug!([$code0, $code1, addr.lsb(), addr.msb()] LD adnn:addr, rr:reg);
write_mem16_addr16!([addr] <- $cpu.reg16_ref(reg).get(); memptr=addr+1);
}
};
( LD SP,HL @@@ $code:expr) => {
{ cpu_debug!([$code] LD rr:SP, rr:HL);
$tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X2);
$cpu.sp.set16($cpu.regs.hl.get16());
}
};
( PUSH ss @@@ $code:expr) => {
{ let ss = StkReg16::from($code);
cpu_debug!([$code] PUSH ss:ss);
$cpu.push_ss($control, $tsc, ss, $flags);
}
};
( POP ss @@@ $code:expr) => {
{ let ss = StkReg16::from($code);
cpu_debug!([$code] POP ss:ss);
$cpu.pop_ss($control, $tsc, ss, &mut $flags);
}
};
( EX DE,HL @@@ $code:expr) => {
{
cpu_debug!([$code] EX rr:DE, rr:HL);
$cpu.ex_de_hl();
}
};
( EX AF,AF^ @@@ $code:expr) => {
{
cpu_debug!([$code] EX ss:AF, ss:AF);
$flags = $cpu.ex_af_af_with_flags($flags);
}
};
( EXX @@@ $code:expr) => {
{
cpu_debug!([$code] EXX );
$cpu.exx();
}
};
( EX (SP),HL @@@ $code:expr) => {
{ cpu_debug!([$code] EX addr:SP, rr:HL);
let val: u16 = ex_sp_nn!($cpu.regs.hl.get());
$cpu.regs.hl.set16(val);
}
};
( LDI @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] LDI );
$cpu.block_transfer::<M, T>($control, $tsc, &mut $flags, BlockDelta::Increase, None);
}
};
( LDIR @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] LDIR );
if let Some(pc) = $cpu.block_transfer::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Increase, Some($pc)) {
$pc = pc;
}
}
};
( LDD @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] LDD );
$cpu.block_transfer::<M, T>($control, $tsc, &mut $flags, BlockDelta::Decrease, None);
}
};
( LDDR @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] LDDR );
if let Some(pc) = $cpu.block_transfer::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Decrease, Some($pc)) {
$pc = pc;
}
}
};
( CPI @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] CPI );
$cpu.block_search::<M, T>($control, $tsc, &mut $flags, BlockDelta::Increase, None);
}
};
( CPIR @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] CPIR );
if let Some(pc) = $cpu.block_search::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Increase, Some($pc)) {
$pc = pc;
}
}
};
( CPD @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] CPD );
$cpu.block_search::<M, T>($control, $tsc, &mut $flags, BlockDelta::Decrease, None);
}
};
( CPDR @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] CPDR );
if let Some(pc) = $cpu.block_search::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Decrease, Some($pc)) {
$pc = pc;
}
}
};
( @ops A,r | @ops A,(HL) @@@ $code:expr) => {
{
let arg = Reg8::from_b2_0($code);
let op = Ops8::from($code);
cpu_debug!([$code] op8(op) r_addr:arg);
$cpu.op8_with_arg($control, $tsc, op, arg, &mut $flags);
}
};
( @ops A,n @@@ $code:expr) => {
{ let n: u8 = fetch_next_imm8!();
let op = Ops8::from($code);
cpu_debug!([$code, n] op8(op) n:n);
$cpu.op8(op, n, &mut $flags);
}
};
( INC r | INC (HL) @@@ $code:expr) => {
instr_inc_dec8!( inc r|[hl]; [$code])
};
( DEC r | DEC (HL) @@@ $code:expr) => {
instr_inc_dec8!( dec r|[hl]; [$code])
};
( ADD HL,dd @@@ $code:expr) => {
{ let src = Reg16::from($code);
cpu_debug!([$code] ADD rr:HL, rr:src);
op16_reg16!(add16: $cpu.regs.hl, $cpu.reg16_ref(src).get16());
}
};
( ADC HL,dd @@@ $code0:expr, $code1:expr) => {
{ let src = Reg16::from($code1);
cpu_debug!([$code0, $code1] ADC rr:HL, rr:src);
op16_reg16!(adc16: $cpu.regs.hl, $cpu.reg16_ref(src).get16());
}
};
( SBC HL,dd @@@ $code0:expr, $code1:expr) => {
{ let src = Reg16::from($code1);
cpu_debug!([$code0, $code1] SBC rr:HL, rr:src);
op16_reg16!(sbc16: $cpu.regs.hl, $cpu.reg16_ref(src).get16());
}
};
( INC dd @@@ $code:expr) => {
{ $tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X2);
let tgt = Reg16::from($code);
cpu_debug!([$code] INC rr:tgt);
$cpu.reg16_mut(tgt).inc16();
}
};
( DEC dd @@@ $code:expr) => {
{ $tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X2);
let tgt = Reg16::from($code);
cpu_debug!([$code] DEC rr:tgt);
$cpu.reg16_mut(tgt).dec16();
}
};
( RLCA @@@ $code:expr) => {
instr_acc_op!(rlca; [$code])
};
( RRCA @@@ $code:expr) => {
instr_acc_op!(rrca; [$code])
};
( RLA @@@ $code:expr) => {
instr_acc_op!(rla; [$code])
};
( RRA @@@ $code:expr) => {
instr_acc_op!(rra; [$code])
};
( @rot|BIT|RES|SET r|(HL) @@@ $code0:expr) => {
{ let code1 = fetch_next_opcode!();
let bops = BitOps::from(code1);
cpu_debug!([$code0, code1] bitops(bops));
$cpu.bitops($control, $tsc, bops, &mut $flags);
}
};
( RLD @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] RLD );
instr_rxd!(ops::rld);
}
};
( RRD @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] RRD );
instr_rxd!(ops::rrd);
}
};
( JP nn @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!();
cpu_debug!([$code, addr.lsb(), addr.msb()] JP nn:addr);
$cpu.memptr.set16(addr);
$pc = Wrapping(addr);
}
};
( JP cc,nn @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!();
let cc = Condition::from($code);
cpu_debug!([$code, addr.lsb(), addr.msb()] JP cc:cc, nn:addr);
$cpu.memptr.set16(addr);
if cc.is_satisfied($flags) {
$pc = Wrapping(addr);
}
}
};
( JR e @@@ $code:expr) => {
{ let e: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X5);
let addr = relative_jump_address!(e);
cpu_debug!([$code, e] JR nn_0:addr);
$cpu.memptr.set16(addr.0);
$pc = addr;
}
};
( JR C,e | JR NC, e | JR Z,e | JR NZ,e @@@ $code:expr) => {
{ let cc = Condition::from_jr_subset($code);
if cc.is_satisfied($flags) {
let e: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X5);
let addr = relative_jump_address!(e);
cpu_debug!([$code, e] JR cc:cc, nn_0:addr);
$cpu.memptr.set16(addr.0);
$pc = addr;
}
else {
$tsc.add_mreq($pc.0);
let e = $control.read_debug($pc.0);
$pc += Wrapping(1);
cpu_debug!([$code, e] JR cc:cc, rel:e);
}
}
};
( JP (HL) @@@ $code:expr) => {
{
cpu_debug!([$code] JP addr:HL);
$pc = Wrapping($cpu.regs.hl.get16());
}
};
( DJNZ e @@@ $code:expr) => {
{ $tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X1);
let b = $cpu.regs.bc.get8hi().wrapping_sub(1);
if b != 0 {
let e: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X5);
let addr = relative_jump_address!(e);
cpu_debug!([$code, e] DJNZ nn_0:addr);
$cpu.memptr.set16(addr.0);
$pc = addr;
}
else {
$tsc.add_mreq($pc.0);
let e = $control.read_debug($pc.0);
$pc += Wrapping(1);
cpu_debug!([$code, e] DJNZ rel:e);
}
$cpu.regs.bc.set8hi(b);
}
};
( CALL nn @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!(no_mreq: NO_MREQ_X1);
cpu_debug!([$code, addr.lsb(), addr.msb()] CALL nn:addr);
push16!($pc.0);
$cpu.memptr.set16(addr);
$pc = Wrapping(addr);
}
};
( CALL cc, nn @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!();
let cc = Condition::from($code);
cpu_debug!([$code, addr.lsb(), addr.msb()] CALL cc:cc, nn:addr);
$cpu.memptr.set16(addr);
if cc.is_satisfied($flags) {
$tsc.add_no_mreq($pc.0.wrapping_sub(1), NO_MREQ_X1);
push16!($pc.0);
$pc = Wrapping(addr);
}
}
};
( RET @@@ $code:expr) => {
{ cpu_debug!([$code] RET );
let addr: u16 = pop16!();
$cpu.memptr.set16(addr);
$pc = Wrapping(addr);
}
};
( RET cc @@@ $code:expr) => {
{ $tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X1);
let cc = Condition::from($code);
cpu_debug!([$code] RET cc:cc);
if cc.is_satisfied($flags) {
let addr: u16 = pop16!();
$cpu.memptr.set16(addr);
$pc = Wrapping(addr);
}
}
};
( RETN | RETI | break $main:tt @@@ $code0:expr, $code1:expr) => {
{ $cpu.restore_iff1(); let should_break = if $code1 == opconsts::RETI_OPCODE_T2.1 {
cpu_debug!([$code0, $code1] RETI );
$control.reti($pc.0, $tsc.as_timestamp())
}
else {
cpu_debug!([$code0, $code1] RETN );
None
};
let addr: u16 = pop16!();
$cpu.memptr.set16(addr);
$pc = Wrapping(addr);
if let Some(cause) = should_break {
break $main LoopExitReason::Reti(cause);
}
}
};
( RST p @@@ $code:expr) => {
{ $tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X1);
let addr = parse_restart_address($code);
cpu_debug!([$code] RST p:addr);
push16!($pc.0);
$cpu.memptr.set16(addr);
$pc = Wrapping(addr);
}
};
( IN A,(n) @@@ $code:expr) => {
{ let n: u8 = fetch_next_imm8!();
cpu_debug!([$code, n] IN r:A, port:n);
$cpu.io_a_inp_an($control, $tsc, n);
}
};
( IN r,(C) @@@ $code0:expr, $code1:expr) => {
{ let arg = Reg8::from_b5_3($code1);
cpu_debug!([$code0, $code1] IN maybe_r:arg, port:C);
$cpu.io_r_inp_bc($control, $tsc, arg, &mut $flags);
}
};
( INI @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] INI );
$cpu.block_in::<M, T>($control, $tsc, &mut $flags, BlockDelta::Increase, None);
}
};
( INIR @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] INIR );
if let Some(pc) = $cpu.block_in::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Increase, Some($pc)) {
$pc = pc;
}
}
};
( IND @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] IND );
$cpu.block_in::<M, T>($control, $tsc, &mut $flags, BlockDelta::Decrease, None);
}
};
( INDR @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] INDR );
if let Some(pc) = $cpu.block_in::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Decrease, Some($pc)) {
$pc = pc;
}
}
};
( OUT (n),A | break $main:tt @@@ $code:expr) => {
{ let n: u8 = fetch_next_imm8!();
cpu_debug!([$code, n] OUT port:n, r:A);
if let Some(cause) = $cpu.io_a_out_an($control, $tsc, n) {
break $main LoopExitReason::WriteIo(cause);
}
}
};
( OUT (C),r | break $main:tt @@@ $code0:expr, $code1:expr) => {
{ let arg = Reg8::from_b5_3($code1);
cpu_debug!([$code0, $code1] OUT port:C, maybe_r:arg);
if let Some(cause) = $cpu.io_r_out_bc($control, $tsc, arg) {
break $main LoopExitReason::WriteIo(cause);
}
}
};
( OUTI | break $main:tt @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] OUTI );
let (should_break, _) = $cpu.block_out::<M, T>($control, $tsc, &mut $flags, BlockDelta::Increase, None);
if let Some(cause) = should_break {
break $main LoopExitReason::WriteIo(cause);
}
}
};
( OTIR | break $main:tt @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] OTIR );
let (should_break, maybe_pc) = $cpu.block_out::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Increase, Some($pc));
if let Some(pc) = maybe_pc { $pc = pc; }
if let Some(cause) = should_break {
break $main LoopExitReason::WriteIo(cause);
}
}
};
( OUTD | break $main:tt @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] OUTD );
let (should_break, _) = $cpu.block_out::<M, T>($control, $tsc, &mut $flags, BlockDelta::Decrease, None);
if let Some(cause) = should_break {
break $main LoopExitReason::WriteIo(cause);
}
}
};
( OTDR | break $main:tt @@@ $code0:expr, $code1:expr) => {
{ cpu_debug!([$code0, $code1] OTDR );
let (should_break, maybe_pc) = $cpu.block_out::<M, T>($control, $tsc, &mut $flags,
BlockDelta::Decrease, Some($pc));
if let Some(pc) = maybe_pc { $pc = pc; }
if let Some(cause) = should_break {
break $main LoopExitReason::WriteIo(cause);
}
}
};
($statement:stmt; @@@ $_:expr) => {
{
$statement
}
};
}
macro_rules! instr_ld_rp {
(@const bc) => { true };
(@const de) => { false };
(A <- [$reg16:ident]; [$code:expr]) => {
{ cpu_debug!([$code] LD r:A, addr:$reg16);
$cpu.instr_ld_a_from_rp::<_, _, {instr_ld_rp!(@const $reg16)}>($control, $tsc);
}
};
([$reg16:ident] <- A; [$code:expr]) => {
{ cpu_debug!([$code] LD addr:$reg16, r:A);
$cpu.instr_ld_rp_from_a::<_, _, {instr_ld_rp!(@const $reg16)}>($control, $tsc);
}
};
}
macro_rules! instr_ld_ir {
(@const I) => { true };
(@const R) => { false };
(A <- $reg:tt; [$code0:expr, $code1:expr]) => {
{ cpu_debug!([$code0, $code1] LD r:A, r:$reg);
$cpu.instr_ld_a_from_ir::<_, _, {instr_ld_ir!(@const $reg)}>($control, $tsc, &mut $flags);
}
};
($reg:tt <- A; [$code0:expr, $code1:expr]) => {
{ cpu_debug!([$code0, $code1] LD r:$reg, r:A);
$cpu.instr_ld_ir_from_a::<_, {instr_ld_ir!(@const $reg)}>($tsc);
}
};
}
macro_rules! instr_acc_op {
($op:ident; [$code:expr]) => {
{
cpu_debug!([$code] str(acc_op_str!($op)));
$cpu.af.op8hi(|a| ops::$op(a, &mut $flags));
flags_op!();
}
};
($op:ident; [$code0:expr, $code1:expr]) => {
{
cpu_debug!([$code0, $code1] str(acc_op_str!($op)));
$cpu.af.op8hi(|a| ops::$op(a, &mut $flags));
flags_op!();
}
};
}
macro_rules! instr_inc_dec8 {
($op:ident r|[hl]; [$code:expr]) => {
{
let arg = Reg8::from_b5_3($code);
cpu_debug!([$code] str(incdec_str!($op)) r_addr:arg);
$cpu.instr_inc_dec8($control, $tsc, arg, &mut $flags, ops::$op);
}
};
}
};
($flags:ident, $pc:ident, $cpu:ident, $control:ident, $tsc:ident, $prefix:ident) => {
macro_rules! run_mnemonic {
( LD q,q | LD (ii+d),r | LD r,(ii+d) @@@ $code:expr) => {
{
match Reg8::tuple_from_b5_3_and_b2_0($code) {
(Ok(dst @ Reg8::H), Ok(src))|
(Ok(dst @ Reg8::L), Ok(src))|
(Ok(dst), Ok(src @ Reg8::H))|
(Ok(dst), Ok(src @ Reg8::L)) => {
cpu_debug!([$code] LD q:dst, q:src);
$cpu.load_reg(dst, src, Some($prefix));
}
(Ok(dst), Err(_)) => {
let d: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X5);
cpu_debug!([$code, d] LD r:dst, ii:d);
let val = read_mem8_reg16!(<- [$prefix+d] memptr=ii+d);
$cpu.set_reg(dst, None, val);
}
(Err(_), Ok(src)) => {
let d: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X5);
cpu_debug!([$code, d] LD ii:d, r:src);
write_mem8_reg16!([$prefix+d] <- $cpu.get_reg(src, None); memptr=ii+d);
}
_ => debug_unreachable_unchecked!()
}
}
};
( LD q,n @@@ $code:expr) => {
{ match Reg8::from_b5_3($code) {
Ok(dst @ Reg8::H) | Ok(dst @ Reg8::L) => {
let n: u8 = fetch_next_imm8!();
cpu_debug!([$code, n] LD q:dst, n:n);
$cpu.set_reg(dst, Some($prefix), n);
}
_ => debug_unreachable_unchecked!()
}
}
};
( LD (ii+d),n @@@ $code:expr) => {
{ let d: u8 = fetch_next_imm8!();
let n: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X2);
cpu_debug!([$code, d, n] LD ii:d, n:n);
write_mem8_reg16!([$prefix+d] <- n; memptr=ii+d);
}
};
( LD ii,nn @@@ $code:expr) => {
{ let nn: u16 = fetch_next_imm16!();
cpu_debug!([$code, nn.lsb(), nn.msb()] LD qq:ii, nn:nn);
$cpu.set_index16($prefix, nn);
}
};
( LD ii,(nn) @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!();
cpu_debug!([$code, addr.lsb(), addr.msb()] LD qq:ii, adnn:addr);
let nn: u16 = read_mem16_addr16!(<- [addr] memptr=addr+1);
$cpu.set_index16($prefix, nn);
}
};
( LD (nn),ii @@@ $code:expr) => {
{ let addr: u16 = fetch_next_imm16!();
cpu_debug!([$code, addr.lsb(), addr.msb()] LD adnn:addr, qq:ii);
write_mem16_addr16!([addr] <- $cpu.get_index2($prefix); memptr=addr+1);
}
};
( LD SP,ii @@@ $code:expr) => {
{ $tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X2);
cpu_debug!([$code] LD rr:SP, qq:ii);
$cpu.sp.set16($cpu.get_index16($prefix));
}
};
( EX (SP),ii @@@ $code:expr) => {
{ cpu_debug!([$code] EX addr:SP, qq:ii);
let val: u16 = ex_sp_nn!($cpu.get_index2($prefix));
$cpu.set_index16($prefix, val);
}
};
( PUSH ii @@@ $code:expr) => {
{ $tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X1);
cpu_debug!([$code] PUSH qq:ii);
let (vhi, vlo) = $cpu.get_index2($prefix);
push2!(vhi, vlo);
}
};
( POP ii @@@ $code:expr) => {
{ cpu_debug!([$code] POP qq:ii);
let val: u16 = pop16!();
$cpu.set_index16($prefix, val);
}
};
( INC ii @@@ $code:expr) => {
{ cpu_debug!([$code] INC qq:ii);
$tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X2);
$cpu.index16_mut($prefix).inc16();
}
};
( DEC ii @@@ $code:expr) => {
{ cpu_debug!([$code] DEC qq:ii);
$tsc.add_no_mreq($cpu.get_ir(), NO_MREQ_X2);
$cpu.index16_mut($prefix).dec16();
}
};
( @ops A,q | @ops A,(ii+d) @@@ $code:expr) => {
{
let op = Ops8::from($code);
let val: u8 = match Reg8::from_b2_0($code) {
Ok(src @ Reg8::H) | Ok(src @ Reg8::L) => {
cpu_debug!([$code] op8(op) q:src);
$cpu.get_reg(src, Some($prefix))
}
Err(_) => {
let d: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X5);
cpu_debug!([$code, d] op8(op) ii:d);
read_mem8_reg16!(<- [$prefix+d] memptr=ii+d)
}
_ => debug_unreachable_unchecked!()
};
$cpu.op8(op, val, &mut $flags);
}
};
( INC q | INC (ii+d) @@@ $code:expr) => {
{
instr_inc_dec8!( inc q|[ii+d]; [$code]);
}
};
( DEC q | DEC (ii+d) @@@ $code:expr) => {
{
instr_inc_dec8!( dec q|[ii+d]; [$code]);
}
};
( ADD ii,dd @@@ $code:expr) => {
{ let src = Reg16::from($code);
cpu_debug!([$code] ADD qq:ii, qq:src);
let nn = $cpu.get_prefix_reg16(src, $prefix);
match $prefix {
Prefix::Xdd => op16_reg16!(add16: $cpu.index.ix, nn),
Prefix::Yfd => op16_reg16!(add16: $cpu.index.iy, nn),
}
}
};
( @rot|BIT|RES|SET (ii+d) @@@ $code0:expr) => {
{ let d: u8 = fetch_next_imm8!();
let code1: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X2);
let bops = BitOps::from(code1);
cpu_debug!([$code0, d, code1] bitops(bops) ii:d);
$cpu.bitops_qq($control, $tsc, bops, &mut $flags, $prefix, d);
}
};
( JP (ii) @@@ $code:expr) => {
{
cpu_debug!([$code] JP addr:ii);
$pc = Wrapping($cpu.get_index16($prefix));
}
};
($statement:stmt; @@@ $_:expr) => {
{
$statement
}
};
}
macro_rules! instr_inc_dec8 {
($op:ident q|[ii+d]; [$code:expr]) => {
{
match Reg8::from_b5_3($code) {
Ok(src @ Reg8::H) | Ok(src @ Reg8::L) => {
cpu_debug!([$code] str(incdec_str!($op)) q:src);
$cpu.apply_reg8(src, Some($prefix), |v| ops::$op(v, &mut $flags));
flags_op!();
}
Err(_) => {
let d: u8 = fetch_next_imm8!(no_mreq: NO_MREQ_X5);
cpu_debug!([$code, d] str(incdec_str!($op)) ii:d);
$cpu.instr_inc_dec_x_mem8($control, $tsc, $prefix, d, &mut $flags, ops::$op);
}
_ => debug_unreachable_unchecked!()
};
}
};
}
};
}