1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use super::opcode::*;
use super::environment::*;
use super::registers::*;
use super::operators::*;

pub fn build_operator_a_r(r: Reg8, (op, name): (Operator, &str)) -> Opcode {
    if r != Reg8::_HL && r != Reg8::H && r != Reg8::L {
        // Fast version
        Opcode::new(
            format!("{} A, {}", name, r),
            Box::new(move |env: &mut Environment| {
                let a = env.state.reg.a();
                let b = env.state.reg.get8(r);
                let v = op(env, a, b);
                env.state.reg.set_a(v);
            })
        )
    } else {
        Opcode::new(
            format!("{} A, {}", name, r),
            Box::new(move |env: &mut Environment| {
                let a = env.state.reg.a();
                let b = env.reg8_ext(r);
                let v = op(env, a, b);

                env.state.reg.set_a(v);
            })
        )
    }
}

pub fn build_operator_a_n((op, name): (Operator, &str)) -> Opcode {
    Opcode::new(
        format!("{} A, n", name),
        Box::new(move |env: &mut Environment| {
            let a = env.state.reg.a();
            let b = env.advance_pc();
            let v = op(env, a, b);

            env.state.reg.set_a(v);
        })
    )
}

pub fn build_cp_block((inc, repeat, postfix) : (bool, bool, &'static str)) -> Opcode {
    Opcode::new(
        format!("CP{}", postfix),
        Box::new(move |env: &mut Environment| {
            let a = env.state.reg.a();
            let b = env.reg8_ext(Reg8::_HL);
            let c_bak = env.state.reg.get_flag(Flag::C);
            operator_cp(env, a, b);
            let bc = env.state.reg.inc_dec16(Reg16::BC, false /*decrement*/);
            env.state.reg.inc_dec16(Reg16::HL, inc);

            // TUZD-4.2
            let mut n = a.wrapping_sub(b);
            if env.state.reg.get_flag(Flag::H) {
                n = n.wrapping_sub(1);
            }
            env.state.reg.update_undocumented_flags_block(n);
            env.state.reg.set_flag(Flag::N);
            env.state.reg.put_flag(Flag::P, bc != 0);
            env.state.reg.put_flag(Flag::C, c_bak); // C unchanged
            // S, Z and H set by operator_cp()

            if repeat && bc != 0 &&  a != b {
                // Back to redo the instruction
                env.set_branch_taken();
                let pc = env.state.reg.pc().wrapping_sub(2);
                env.state.reg.set_pc(pc);
            }
        })
    )
}