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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//! Contains models and functions used to manage a Z80 processor's internal storage,
//! including single registers, register pairs, and status flags.

use std::fmt;
use strum_macros::Display;

macro_rules! impl_display_register {
    ($( $ident: ident ),*) => (
        $( impl fmt::Display for $ident {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                // Write out the enum variant name, replacing underscores with straight quotes.
                write!(f, "{}", format!("{:?}", self).replace("_", "'"))
            }
        } )*
    );
}

/// Represents the order of a given register in a pair.
/// For example, `RegisterPairType::AF` includes the
/// registers `SingleRegisterType::A` and
/// `SingleRegisterType::F`, which are high and low
/// within the pair respectively.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RegisterOrder {
    High,
    Low,
}

/// Used to identify a single register in an
/// implementation-independent manner.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SingleRegisterType {
    A,   // Accumulator register
    F,   // Flag register
    B,   // B general purpose register
    C,   // C general purpose register
    D,   // D general purpose register
    E,   // E general purpose register
    H,   // H general purpose register
    L,   // L general purpose register
    IXH, // IX index register, high byte
    IXL, // IX index register, low byte
    IYH, // IY index register, high byte
    IYL, // IY index register, low byte
    PCH, // Program counter, high byte
    PCL, // Program counter, low byte
    SPH, // Stack pointer, high byte
    SPL, // Stack pointer, low byte
    I,   // Interrupt vector register
    R,   // Memory refresh register
    W,   // Temporary storage register, high byte
    Z,   // Temporary storage register, low byte
    A_,  // Alternate accumulator register
    F_,  // Alternate flag register
    B_,  // Alternate B general purpose register
    C_,  // Alternate C general purpose register
    D_,  // Alternate D general purpose register
    E_,  // Alternate E general purpose register
    H_,  // Alternate H general purpose register
    L_,  // Alternate L general purpose register
}

impl SingleRegisterType {
    #[inline(always)]
    pub fn to_register_pair_type(self) -> (RegisterPairType, RegisterOrder) {
        use RegisterOrder::*;
        use RegisterPairType::*;
        use SingleRegisterType::*;

        match self {
            A => (AF, High),
            F => (AF, Low),
            B => (BC, High),
            C => (BC, Low),
            D => (DE, High),
            E => (DE, Low),
            H => (HL, High),
            L => (HL, Low),
            IXH => (IX, High),
            IXL => (IX, Low),
            IYH => (IY, High),
            IYL => (IY, Low),
            PCH => (PC, High),
            PCL => (PC, Low),
            SPH => (SP, High),
            SPL => (SP, Low),
            I => (IR, High),
            R => (IR, Low),
            W => (WZ, High),
            Z => (WZ, Low),
            A_ => (AF_, High),
            F_ => (AF_, Low),
            B_ => (BC_, High),
            C_ => (BC_, Low),
            D_ => (DE_, High),
            E_ => (DE_, Low),
            H_ => (HL_, High),
            L_ => (HL_, Low),
        }
    }
}

/// Used to identify a register pair in an
/// implementation-independent manner.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum RegisterPairType {
    AF,  // Accumulator and flag registers
    BC,  // B and C general purpose registers
    DE,  // D and E general purpose registers
    HL,  // H and L general purpose registers
    IX,  // IX index register
    IY,  // IY index register
    PC,  // Program counter
    SP,  // Stack pointer
    IR,  // Interrupt vector and memory refresh registers
    WZ,  // Temporary storage register
    AF_, // Alternate accumulator and flag registers
    BC_, // Alternate B and C general purpose registers
    DE_, // Alternate D and E general purpose registers
    HL_, // Alternate H and L general purpose registers
}

impl RegisterPairType {
    #[inline(always)]
    pub fn to_single_register_types(self) -> (SingleRegisterType, SingleRegisterType) {
        use RegisterPairType::*;
        use SingleRegisterType::*;

        match self {
            AF => (A, F),
            BC => (B, C),
            DE => (D, E),
            HL => (H, L),
            IX => (IXH, IXL),
            IY => (IYH, IYL),
            PC => (PCH, PCL),
            SP => (SPH, SPL),
            IR => (I, R),
            WZ => (W, Z),
            AF_ => (A_, F_),
            BC_ => (B_, C_),
            DE_ => (D_, E_),
            HL_ => (H_, L_),
        }
    }
}

impl_display_register!(SingleRegisterType, RegisterPairType);

/// Used to identify either a single register or a register pair.
pub enum RegisterType {
    SingleRegister(SingleRegisterType),
    RegisterPair(RegisterPairType),
}

/// Represents individual Z80 status flags, with their masks as their values.
#[derive(Clone, Copy, Debug, Display, PartialEq)]
#[repr(u8)]
pub enum Flag {
    S = 0b1000_0000,
    Z = 0b0100_0000,
    F5 = 0b0010_0000,
    H = 0b0001_0000,
    F3 = 0b0000_1000,
    PV = 0b0000_0100,
    N = 0b0000_0010,
    C = 0b0000_0001,
}

impl Flag {
    pub const SIGN: Self = Flag::S;
    pub const ZERO: Self = Flag::Z;
    pub const BIT5: Self = Flag::F5;
    pub const HALF_CARRY: Self = Flag::H;
    pub const BIT3: Self = Flag::F3;
    pub const PARITY: Self = Flag::PV;
    pub const OVERFLOW: Self = Flag::PV;
    pub const SUBTRACT: Self = Flag::N;
    pub const CARRY: Self = Flag::C;

    /// Returns the zero-based bit index of a flag as stored
    /// in the flag register (`SingleRegisterType::F`).
    pub fn index(self) -> usize {
        use Flag::*;

        match self {
            S => 7,
            Z => 6,
            F5 => 5,
            H => 4,
            F3 => 3,
            PV => 2,
            N => 1,
            C => 0,
        }
    }
}