feo3boy_opcodes/opcode/
args.rs

1//! These are types which are used as arguments to the [`Opcode`s][crate::opcode::Opcode]
2//! and [`CBOpcode`s][crate::opcode::CBOpcode].
3
4use std::fmt;
5
6/// ALU Operation type.
7#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
8pub enum AluOp {
9    Add,
10    AddCarry,
11    Sub,
12    SubCarry,
13    And,
14    Xor,
15    Or,
16    Compare,
17}
18
19impl AluOp {
20    /// Get the ALU operation type for the given opcode. Panics if the code is greater than 7.
21    pub(super) fn from_ycode(code: u8) -> Self {
22        match code {
23            0 => Self::Add,
24            1 => Self::AddCarry,
25            2 => Self::Sub,
26            3 => Self::SubCarry,
27            4 => Self::And,
28            5 => Self::Xor,
29            6 => Self::Or,
30            7 => Self::Compare,
31            _ => panic!("Unrecognized ALU operation type (y code) {}", code),
32        }
33    }
34}
35
36impl fmt::Display for AluOp {
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        match *self {
39            Self::Add => f.write_str("ADD"),
40            Self::AddCarry => f.write_str("ADC"),
41            Self::Sub => f.write_str("SUB"),
42            Self::SubCarry => f.write_str("SBC"),
43            Self::And => f.write_str("AND"),
44            Self::Xor => f.write_str("XOR"),
45            Self::Or => f.write_str("OR"),
46            Self::Compare => f.write_str("CP"),
47        }
48    }
49}
50
51/// Type of unary ALU operation. All ops here apply only to A and Flags.
52#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
53pub enum AluUnaryOp {
54    /// 8-bit left rotate. Bit 7 goes to both the carry and bit 0.
55    RotateLeft8,
56    /// 9-bit left rotate. Bit 7 goes to carry and carry goes to bit 0.
57    RotateLeft9,
58    /// 8-bit right rotate. Bit 0 goes to both the carry and bit 7.
59    RotateRight8,
60    /// 9-bit left rotate. Bit 0 goes to carry and carry goes to bit 7.
61    RotateRight9,
62    /// Helper for doing binary-coded-decimal. Adjusts the hex didgits to keep both nybbles in range
63    /// 0..=9 by adding 0x06 and/or 0x60 to push the digit to the next nybble.
64    DecimalAdjust,
65    /// Sets the carry flag.
66    SetCarryFlag,
67    /// Inverts the Accumulator.
68    Compliment,
69    /// Inverts the carry flag.
70    ComplimentCarryFlag,
71}
72
73impl AluUnaryOp {
74    /// Get the ALU unary operation type for the given opcode. Panics if the code is greater than 7.
75    pub(super) fn from_ycode(code: u8) -> Self {
76        match code {
77            0 => Self::RotateLeft8,
78            1 => Self::RotateRight8,
79            2 => Self::RotateLeft9,
80            3 => Self::RotateRight9,
81            4 => Self::DecimalAdjust,
82            5 => Self::Compliment,
83            6 => Self::SetCarryFlag,
84            7 => Self::ComplimentCarryFlag,
85            _ => panic!("Unrecognized ALU unary operation type (y code) {}", code),
86        }
87    }
88}
89
90impl fmt::Display for AluUnaryOp {
91    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92        match *self {
93            Self::RotateLeft8 => f.write_str("RLCA"),
94            Self::RotateLeft9 => f.write_str("RLA"),
95            Self::RotateRight8 => f.write_str("RRCA"),
96            Self::RotateRight9 => f.write_str("RRA"),
97            Self::DecimalAdjust => f.write_str("DAA"),
98            Self::SetCarryFlag => f.write_str("SCF"),
99            Self::Compliment => f.write_str("CPL"),
100            Self::ComplimentCarryFlag => f.write_str("CCF"),
101        }
102    }
103}
104
105/// 8 bit operand. Either the source or destination of an 8 bit operation.
106#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
107pub enum Operand8 {
108    // 8 bit registers.
109    /// Normal register B.
110    B,
111    /// Normal register C.
112    C,
113    /// Normal register D.
114    D,
115    /// Normal register E.
116    E,
117    /// Normal register High.
118    H,
119    /// Normal register Low.
120    L,
121    /// Accumulator register.
122    A,
123
124    // Indirections of 16 bit register pairs.
125    /// Dereference HL.
126    AddrHL,
127    /// Dereference BC.
128    AddrBC,
129    /// Dereference DE.
130    AddrDE,
131    /// Dereference HL then increment HL.
132    AddrHLInc,
133    /// Dereference HL then decrement HL.
134    AddrHLDec,
135    // Immediates
136    /// Load value from immediate (and advance program counter). Cannot be used to store. Will
137    /// panic if used as the destination operand.
138    Immediate,
139    /// Dereference a 16 bit immediate value.
140    AddrImmediate,
141
142    // Offsets from 0xff00.
143    /// Dereference 0xff00 + register C.
144    AddrRelC,
145    /// Dereference 0xff00 + 8 bit immediate.
146    AddrRelImmediate,
147}
148
149impl Operand8 {
150    /// Get the 8 bit operand for the given register code. Panics if the code is greater than 7.
151    /// Note that register codes are mostly 8 bit registers but also include `(HL)`.
152    pub(super) fn from_regcode(code: u8) -> Self {
153        match code {
154            0 => Self::B,
155            1 => Self::C,
156            2 => Self::D,
157            3 => Self::E,
158            4 => Self::H,
159            5 => Self::L,
160            6 => Self::AddrHL,
161            7 => Self::A,
162            _ => panic!("Unrecognized Operand type {}", code),
163        }
164    }
165
166    /// Get the 8 bit operand from the given `p` code for an indirection.
167    pub(super) fn from_indirect(code: u8) -> Self {
168        match code {
169            0 => Self::AddrBC,
170            1 => Self::AddrDE,
171            2 => Self::AddrHLInc,
172            3 => Self::AddrHLDec,
173            _ => panic!("Unrecognized indirection code {}", code),
174        }
175    }
176}
177
178impl fmt::Display for Operand8 {
179    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180        match *self {
181            Self::A => f.write_str("A"),
182            Self::B => f.write_str("B"),
183            Self::C => f.write_str("C"),
184            Self::D => f.write_str("D"),
185            Self::E => f.write_str("E"),
186            Self::H => f.write_str("H"),
187            Self::L => f.write_str("L"),
188            Self::AddrHL => f.write_str("(HL)"),
189            Self::AddrBC => f.write_str("(BC)"),
190            Self::AddrDE => f.write_str("(DE)"),
191            Self::AddrHLInc => f.write_str("(HL+)"),
192            Self::AddrHLDec => f.write_str("(HL-)"),
193            Self::Immediate => f.write_str("u8"),
194            Self::AddrImmediate => f.write_str("(u16)"),
195            Self::AddrRelC => f.write_str("(FF00+C)"),
196            Self::AddrRelImmediate => f.write_str("(FF00+u8)"),
197        }
198    }
199}
200
201/// 16 bit operand.
202#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
203pub enum Operand16 {
204    /// Register pair BC.
205    BC,
206    /// Register pair DE.
207    DE,
208    /// Register pair HL.
209    HL,
210    /// Register pair of the accumulator + flags register.
211    AF,
212    /// Stack pointer.
213    Sp,
214    /// Load value from immediate (and advance program counter). Cannot be used to store. Will
215    /// panic if used as the destination operand.
216    Immediate,
217    /// Load a 16 bit immediate (and advance program counter), then dereference that address. Note:
218    /// since no actual opcode uses `(u16)` as the source for a 16 bit read, this will panic if used
219    /// to load.
220    AddrImmediate,
221}
222
223impl Operand16 {
224    /// Get a 16 bit operand from a register pair code, using the table of register pairs that
225    /// includes the stack pointer. Panics if the code is greater than 3.
226    pub(super) fn from_pair_code_sp(code: u8) -> Operand16 {
227        match code {
228            0 => Operand16::BC,
229            1 => Operand16::DE,
230            2 => Operand16::HL,
231            3 => Operand16::Sp,
232            _ => panic!("Unrecognized register pair code {}", code),
233        }
234    }
235
236    /// Get a 16 bit operand from a register pair code, using the table of register pairs that
237    /// includes the accumulator-flags pair. Panics if the code is greater than 3.
238    pub(super) fn from_pair_code_af(code: u8) -> Operand16 {
239        match code {
240            0 => Operand16::BC,
241            1 => Operand16::DE,
242            2 => Operand16::HL,
243            3 => Operand16::AF,
244            _ => panic!("Unrecognized register pair code {}", code),
245        }
246    }
247}
248
249impl fmt::Display for Operand16 {
250    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
251        match *self {
252            Operand16::BC => f.write_str("BC"),
253            Operand16::DE => f.write_str("DE"),
254            Operand16::HL => f.write_str("HL"),
255            Operand16::AF => f.write_str("AF"),
256            Operand16::Sp => f.write_str("SP"),
257            Operand16::Immediate => f.write_str("u16"),
258            Operand16::AddrImmediate => f.write_str("(u16)"),
259        }
260    }
261}
262
263/// Conditional for conditional jump/conditional ret.
264#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
265pub enum ConditionCode {
266    Unconditional,
267    NonZero,
268    Zero,
269    NoCarry,
270    Carry,
271}
272
273impl ConditionCode {
274    /// Get the condition code for the given relative-jump condition code. Relative jump condition
275    /// codes are for x = 0, z = 0, y = 3..=7 (the value given should be y). Panics if the given
276    /// value is not in range 3..=7.
277    pub(super) fn from_relative_cond_code(code: u8) -> Self {
278        match code {
279            3 => Self::Unconditional,
280            4..=7 => Self::from_absolute_cond_code(code - 4),
281            _ => panic!("Unrecognized Relative-Jump condtion code {}", code),
282        }
283    }
284
285    /// Get the condition code for the given jump, return, or call condition code. This never
286    /// returns `Unconditional`. The value must be in range 0..=3, otherwise this will panic.
287    pub(super) fn from_absolute_cond_code(code: u8) -> Self {
288        match code {
289            0 => Self::NonZero,
290            1 => Self::Zero,
291            2 => Self::NoCarry,
292            3 => Self::Carry,
293            _ => panic!("Unrecognized Absolute-Jump condtion code {}", code),
294        }
295    }
296}
297
298impl fmt::Display for ConditionCode {
299    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300        match *self {
301            Self::Unconditional => Ok(()),
302            Self::NonZero => f.write_str("NZ"),
303            Self::Zero => f.write_str("Z"),
304            Self::NoCarry => f.write_str("NC"),
305            Self::Carry => f.write_str("C"),
306        }
307    }
308}