use super::opcode::Opcode;
use super::environment::Environment;
use super::registers::{Flag, Reg16, Reg8};
pub fn build_ld_r_r(dst: Reg8, src: Reg8, _special: bool) -> Opcode {
if src != Reg8::_HL && dst != Reg8::_HL
&& src != Reg8::H && dst != Reg8::H
&& src != Reg8::L && dst != Reg8::L {
Opcode::new(
format!("LD {dst}, {src}"),
move |env: &mut Environment| {
let value = env.state.reg.get8(src);
env.state.reg.set8(dst, value);
if dst == Reg8::A && (src == Reg8::I || src == Reg8::R) {
env.state.reg.update_p_flag_with_iff2();
}
}
)
} else {
Opcode::new(
format!("LD {dst}, {src}"),
move |env: &mut Environment| {
let value = if dst == Reg8::_HL {
env.state.reg.get8(src)
} else {
env.reg8_ext(src)
};
if src == Reg8::_HL {
env.state.reg.set8(dst, value);
} else {
env.set_reg(dst, value);
}
}
)
}
}
pub fn build_ld_r_n(r: Reg8) -> Opcode {
Opcode::new(
format!("LD {r}, n"),
move |env: &mut Environment| {
let value = env.advance_pc();
env.set_reg(r, value);
}
)
}
pub fn build_ld_a_prr(rr: Reg16) -> Opcode {
Opcode::new(
format!("LD A, ({rr:?})"),
move |env: &mut Environment| {
let address = env.state.reg.get16(rr);
let value = env.sys.peek(address);
env.state.reg.set_a(value);
}
)
}
pub fn build_ld_a_pnn() -> Opcode {
Opcode::new(
"LD A, (nn)".to_string(),
|env: &mut Environment| {
let address = env.advance_immediate16();
let value = env.sys.peek(address);
env.state.reg.set_a(value);
}
)
}
pub fn build_ld_prr_a(rr: Reg16) -> Opcode {
Opcode::new(
format!("LD ({rr:?}), A"),
move |env: &mut Environment| {
let value = env.state.reg.a();
let address = env.state.reg.get16(rr);
env.sys.poke(address, value);
}
)
}
pub fn build_ld_pnn_a() -> Opcode {
Opcode::new(
"LD (nn), A".to_string(),
|env: &mut Environment| {
let value = env.state.reg.a();
let address = env.advance_immediate16();
env.sys.poke(address, value);
}
)
}
pub fn build_ld_rr_nn(rr: Reg16) -> Opcode {
Opcode::new(
format!("LD {rr:?}, nn"),
move |env: &mut Environment| {
let value = env.advance_immediate16();
env.set_reg16(rr, value);
}
)
}
pub fn build_ld_sp_hl() -> Opcode {
Opcode::new(
"LD SP, HL".to_string(),
|env: &mut Environment| {
let value = env.reg16_ext(Reg16::HL);
env.set_reg16(Reg16::SP, value);
}
)
}
pub fn build_ld_pnn_rr(rr: Reg16, _fast: bool) -> Opcode {
Opcode::new(
format!("LD (nn), {rr:?}"),
move |env: &mut Environment| {
let address = env.advance_immediate16();
let value = env.reg16_ext(rr);
env.sys.poke16(address, value);
}
)
}
pub fn build_ld_rr_pnn(rr: Reg16, _fast: bool) -> Opcode {
Opcode::new(
format!("LD {rr:?}, (nn)"),
move |env: &mut Environment| {
let address = env.advance_immediate16();
let value = env.sys.peek16(address);
env.set_reg16(rr, value);
}
)
}
pub fn build_ex_af() -> Opcode {
Opcode::new(
"EX AF, AF'".to_string(),
|env: &mut Environment| {
env.state.reg.swap(Reg16::AF);
}
)
}
pub fn build_exx() -> Opcode {
Opcode::new(
"EXX".to_string(),
|env: &mut Environment| {
env.state.reg.swap(Reg16::BC);
env.state.reg.swap(Reg16::DE);
env.state.reg.swap(Reg16::HL); }
)
}
pub fn build_ex_de_hl() -> Opcode {
Opcode::new(
"EX DE, HL".to_string(),
|env: &mut Environment| {
let temp = env.state.reg.get16(Reg16::HL); env.state.reg.set16(Reg16::HL, env.state.reg.get16(Reg16::DE));
env.state.reg.set16(Reg16::DE, temp);
}
)
}
pub fn build_ex_psp_hl() -> Opcode {
Opcode::new(
"EX (SP), HL".to_string(),
|env: &mut Environment| {
let address = env.state.reg.get16(Reg16::SP);
let temp = env.reg16_ext(Reg16::HL);
let val = env.sys.peek16(address);
env.set_reg16(Reg16::HL, val);
env.sys.poke16(address, temp);
}
)
}
pub fn build_ld_block((inc, repeat, postfix) : (bool, bool, &'static str)) -> Opcode {
Opcode::new(
format!("LD{postfix}"),
move |env: &mut Environment| {
let value = env.reg8_ext(Reg8::_HL);
let address = env.state.reg.get16(Reg16::DE);
env.sys.poke(address, value);
env.state.reg.inc_dec16(Reg16::DE, inc);
env.state.reg.inc_dec16(Reg16::HL, inc);
let bc = env.state.reg.inc_dec16(Reg16::BC, false );
let n = value.wrapping_add(env.state.reg.a());
env.state.reg.update_undocumented_flags_block(n);
env.state.reg.clear_flag(Flag::N);
env.state.reg.clear_flag(Flag::H);
env.state.reg.put_flag(Flag::P, bc != 0);
if repeat && bc != 0 {
env.set_branch_taken();
let pc = env.state.reg.pc().wrapping_sub(2);
env.state.reg.set_pc(pc);
}
}
)
}