iz80/
opcode_alu.rs

1use super::opcode::Opcode;
2use super::environment::Environment;
3use super::registers::{Flag, Reg16, Reg8};
4use super::operators::{Operator, operator_cp};
5
6pub fn build_operator_a_r(r: Reg8, (op, name): (Operator, &str)) -> Opcode {
7    if r != Reg8::_HL && r != Reg8::H && r != Reg8::L {
8        // Fast version
9        Opcode::new(
10            format!("{name} A, {r}"),
11            move |env: &mut Environment| {
12                let a = env.state.reg.a();
13                let b = env.state.reg.get8(r);
14                let v = op(env, a, b);
15                env.state.reg.set_a(v);
16            }
17        )
18    } else {
19        Opcode::new(
20            format!("{name} A, {r}"),
21            move |env: &mut Environment| {
22                let a = env.state.reg.a();
23                let b = env.reg8_ext(r);
24                let v = op(env, a, b);
25
26                env.state.reg.set_a(v);
27            }
28        )
29    }
30}
31
32pub fn build_operator_a_n((op, name): (Operator, &str)) -> Opcode {
33    Opcode::new(
34        format!("{name} A, n"),
35        move |env: &mut Environment| {
36            let a = env.state.reg.a();
37            let b = env.advance_pc();
38            let v = op(env, a, b);
39
40            env.state.reg.set_a(v);
41        }
42    )
43}
44
45pub fn build_cp_block((inc, repeat, postfix) : (bool, bool, &'static str)) -> Opcode {
46    Opcode::new(
47        format!("CP{postfix}"),
48        move |env: &mut Environment| {
49            let a = env.state.reg.a();
50            let b = env.reg8_ext(Reg8::_HL);
51            let c_bak = env.state.reg.get_flag(Flag::C);
52            operator_cp(env, a, b);
53            let bc = env.state.reg.inc_dec16(Reg16::BC, false /*decrement*/);
54            env.state.reg.inc_dec16(Reg16::HL, inc);
55
56            // TUZD-4.2
57            let mut n = a.wrapping_sub(b);
58            if env.state.reg.get_flag(Flag::H) {
59                n = n.wrapping_sub(1);
60            }
61            env.state.reg.update_undocumented_flags_block(n);
62            env.state.reg.set_flag(Flag::N);
63            env.state.reg.put_flag(Flag::P, bc != 0);
64            env.state.reg.put_flag(Flag::C, c_bak); // C unchanged
65            // S, Z and H set by operator_cp()
66
67            if repeat && bc != 0 &&  a != b {
68                // Back to redo the instruction
69                env.set_branch_taken();
70                let pc = env.state.reg.pc().wrapping_sub(2);
71                env.state.reg.set_pc(pc);
72            }
73        }
74    )
75}