dez80/
instruction.rs

1//! Contains models and functions to define, decode,
2//! and format Z80 instructions and their components.
3//!
4//! # Example
5//!
6//! ```
7//! use dez80::Instruction;
8//!
9//! // Initialize a buffer containing raw Z80 opcodes.
10//! let mut data: &[u8] = &[0x00, 0x04, 0x05]; // NOP, INC B, DEC B
11//!
12//! // Decode a single instruction from the raw bytes.
13//! if let Ok(instruction) = Instruction::decode_one(&mut data) {
14//!     // Convert the instruction to a string, in its symbolic format.
15//!     assert_eq!("NOP", instruction.to_string());
16//! } else {
17//!     panic!("Could not decode an instruction!");
18//! }
19//!
20//! // Decode a sequence of instructions from the remaining bytes.
21//! let instructions = Instruction::decode_all(&mut data);
22//! assert_eq!(2, instructions.len()); // bytes are consumed as they are decoded
23//!
24//! for instruction in instructions {
25//!     println!("Decoded {}.", instruction);
26//! }
27//! ```
28
29use crate::register::*;
30use std::fmt;
31use std::io::{Bytes, Read};
32use std::iter::Peekable;
33use strum_macros::IntoStaticStr;
34
35macro_rules! instruction {
36    ($opcode: expr, $type: expr) => {
37        Instruction { opcode: $opcode, r#type: $type, ..Default::default() }
38    };
39    ($opcode: expr, $type: expr, source: $src: expr) => {
40        Instruction { opcode: $opcode, r#type: $type, source: Some($src), ..Default::default() }
41    };
42    ($opcode: expr, $type: expr, destination: $dst: expr) => {
43        Instruction {
44            opcode: $opcode,
45            r#type: $type,
46            destination: Some($dst),
47            ..Default::default()
48        }
49    };
50    ($opcode: expr, $type: expr, destination: $dst: expr, source: $src: expr) => {
51        Instruction {
52            opcode: $opcode,
53            r#type: $type,
54            destination: Some($dst),
55            source: Some($src),
56            ..Default::default()
57        }
58    };
59    ($opcode: expr, $type: expr, $src: expr, $dst: expr) => {
60        Instruction {
61            opcode: $opcode,
62            r#type: $type,
63            source: Some($src),
64            destination: Some($dst),
65            ..Default::default()
66        }
67    };
68}
69
70/// Represents a prerequisite condition for an instruction.
71#[derive(Clone, Copy, Debug, PartialEq)]
72pub enum Condition {
73    FlagSet(Flag),
74    FlagNotSet(Flag),
75    RegisterValue(SingleRegisterType, u8),
76    RegisterNotValue(SingleRegisterType, u8),
77    RegisterPairValue(RegisterPairType, u16),
78    RegisterPairNotValue(RegisterPairType, u16),
79}
80
81/// Represents a target for data operations.
82/// Variants are closely related to Z80 addressing modes.
83#[derive(Clone, Copy, Debug, PartialEq)]
84pub enum Operand {
85    OctetImmediate(u8),
86    DoubletImmediate(u16),
87    OctetImplied(u8),
88    RegisterImplied(SingleRegisterType),
89    RegisterPairImplied(RegisterPairType),
90    RegisterImpliedBit(SingleRegisterType, u8),
91    MemoryDirect(u16),
92    MemoryIndirect(RegisterPairType),
93    MemoryIndexed(RegisterPairType, i8),
94    MemoryIndexedAndRegister(RegisterPairType, i8, SingleRegisterType),
95    MemoryIndirectBit(RegisterPairType, u8),
96    MemoryIndexedBit(RegisterPairType, i8, u8),
97    MemoryIndexedBitAndRegister(RegisterPairType, i8, u8, SingleRegisterType),
98    ProgramCounterRelative(i8),
99    PortDirect(u8),
100    PortIndirect(SingleRegisterType),
101}
102
103impl fmt::Display for Operand {
104    /// Formats operands based on standard notation.
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        use Operand::*;
107
108        match self {
109            OctetImmediate(val) | OctetImplied(val) => write!(f, "0x{:02x}", val),
110            DoubletImmediate(val) => write!(f, "0x{:04x}", val),
111            RegisterImplied(reg) => write!(f, "{}", reg),
112            RegisterPairImplied(reg) => write!(f, "{}", reg),
113            RegisterImpliedBit(reg, bit) => write!(f, "{}, {}", bit, reg),
114            MemoryDirect(val) => write!(f, "(0x{:04x})", val.to_le()),
115            MemoryIndirect(reg) => write!(f, "({})", reg),
116            MemoryIndexed(reg, idx) => write!(f, "({} + 0x{:02x})", reg, *idx as u8),
117            MemoryIndexedAndRegister(reg_in, idx, reg_out) => {
118                write!(f, "({} + 0x{:02x}), {}", reg_in, *idx as u8, reg_out)
119            }
120            MemoryIndirectBit(reg, bit) => write!(f, "{}, ({})", bit, reg),
121            MemoryIndexedBit(reg, idx, bit) => {
122                write!(f, "{}, ({} + 0x{:02x})", bit, reg, *idx as u8)
123            }
124            MemoryIndexedBitAndRegister(reg_in, idx, bit, reg_out) => {
125                write!(f, "{}, ({} + 0x{:02x}), {}", bit, reg_in, *idx as u8, reg_out)
126            }
127            ProgramCounterRelative(val) => write!(f, "0x{:02x}", *val as u8),
128            PortDirect(val) => write!(f, "(0x{:02x})", val),
129            PortIndirect(reg) => write!(f, "({})", reg),
130        }
131    }
132}
133
134/// Represents a type of instruction, categorized by mnemonic.
135#[derive(Clone, Copy, Debug, IntoStaticStr, PartialEq)]
136pub enum InstructionType {
137    Adc,
138    Add,
139    And,
140    Bit,
141    Call(Option<Condition>),
142    Ccf,
143    Cp,
144    Cpd,
145    Cpdr,
146    Cpi,
147    Cpir,
148    Cpl,
149    Daa,
150    Dec,
151    Di,
152    Djnz,
153    Ei,
154    Ex,
155    Exx,
156    Halt,
157    Im(u8),
158    In,
159    Inc,
160    Ind,
161    Indr,
162    Ini,
163    Inir,
164    Inva, // Unofficial mnemonic, invalid instruction with no observable side effect
165    Jp(Option<Condition>),
166    Jr(Option<Condition>),
167    Ld,
168    Ldd,
169    Lddr,
170    Ldi,
171    Ldir,
172    Neg,
173    Nop,
174    Or,
175    Otdr,
176    Otir,
177    Out,
178    Outd,
179    Outi,
180    Pop,
181    Push,
182    Res,
183    Ret(Option<Condition>),
184    Reti,
185    Retn,
186    Rl,
187    Rla,
188    Rlc,
189    Rlca,
190    Rld,
191    Rr,
192    Rra,
193    Rrc,
194    Rrca,
195    Rrd,
196    Rst(u8),
197    Sbc,
198    Scf,
199    Set,
200    Sla,
201    Sll, // Unofficial mnemonic, also known as SLS and SL1; shift left and pad with 1
202    Sra,
203    Srl,
204    Sub,
205    Xor,
206}
207
208impl fmt::Display for InstructionType {
209    /// Formats instruction types as their canonical mnemonics.
210    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211        use InstructionType::*;
212
213        // Write the instruction mnemonic
214        let type_upper = <&'static str>::from(self).to_ascii_uppercase();
215        write!(f, "{}", type_upper)?;
216
217        // If the instruction type has an associated value, write it as needed
218        match self {
219            // IM: Write the associated integer directly
220            Im(val) => write!(f, " {}", val),
221            // Conditional instructions: format the associated condition as its standard abbreviation
222            Call(Some(cond)) | Jp(Some(cond)) | Jr(Some(cond)) | Ret(Some(cond)) => match cond {
223                Condition::FlagSet(flag) => match flag {
224                    Flag::PV => write!(f, " PE"), // Parity Even
225                    Flag::S => write!(f, " M"),   // Sign Positive
226                    _ => write!(f, " {}", flag),
227                },
228                Condition::FlagNotSet(flag) => match flag {
229                    Flag::PV => write!(f, " PO"), // Parity Odd
230                    Flag::S => write!(f, " P"),   // Sign Negative
231                    _ => write!(f, " N{}", flag),
232                },
233                _ => Ok(()),
234            },
235            // RST: Write the associated address in hexadecimal form
236            Rst(val) => write!(f, " 0x{:02x}", val),
237            _ => Ok(()),
238        }
239    }
240}
241
242/// Represents a set of one or two bytes modifying an instruction's opcode.
243#[derive(Clone, Copy, Debug, PartialEq)]
244#[repr(u8)]
245pub enum OpcodePrefix {
246    Bitwise,                          // 0xCB
247    Extended,                         // 0xED
248    Indexed(RegisterPairType),        // 0xDD or 0xFD
249    IndexedBitwise(RegisterPairType), // 0xDDCB or 0xFDCB
250}
251
252impl OpcodePrefix {
253    pub fn to_bytes(&self) -> &[u8] {
254        use OpcodePrefix::*;
255        use RegisterPairType::*;
256
257        match self {
258            Bitwise => &[0xCB],
259            Extended => &[0xED],
260            Indexed(IX) => &[0xDD],
261            Indexed(IY) => &[0xFD],
262            IndexedBitwise(IX) => &[0xDD, 0xCB],
263            IndexedBitwise(IY) => &[0xFD, 0xCB],
264            _ => unreachable!(),
265        }
266    }
267}
268
269impl fmt::Display for OpcodePrefix {
270    /// Formats the prefix as its raw byte values.
271    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272        let bytes = self.to_bytes();
273
274        write!(f, "{:02X}", bytes[0])?;
275
276        for byte in &bytes[1..] {
277            write!(f, " {:02X}", byte)?;
278        }
279
280        Ok(())
281    }
282}
283
284/// Represents an instruction opcode, including prefixes but excluding operands.
285#[derive(Clone, Copy, Debug, Default, PartialEq)]
286pub struct Opcode {
287    pub prefix: Option<OpcodePrefix>,
288    pub value: u8,
289}
290
291impl fmt::Display for Opcode {
292    /// Formats the opcode as a sequence of raw hexadecimal values.
293    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294        if let Some(prefix) = self.prefix {
295            write!(f, "{} {:02X}", prefix, self.value)
296        } else {
297            write!(f, "{:02X}", self.value)
298        }
299    }
300}
301
302/// Represents a state in the decoding process, defined as a combination of the
303/// current opcode table, and the role of the next byte to decode.
304/// This corresponds to a decoding state that the decoder has yet to perform.
305#[derive(Clone, Debug, PartialEq)]
306pub enum DecodingState {
307    /// The initial decoding state. A root opcode must be decoded.
308    RootOpcode,
309    /// An operand must be decoded for a root instruction.
310    RootOperand,
311    /// A displacement operand must be decoded for a root instruction.
312    RootDisplacement,
313    /// An opcode must be decoded for an extended instruction.
314    ExtendedOpcode,
315    /// An operand must be decoded for an extended instruction.
316    ExtendedOperand,
317    /// An opcode must be decoded for an indexed instruction.
318    IndexedOpcode,
319    /// A displacement operand must be decoded for an indexed instruction.
320    IndexedDisplacement,
321    /// An operand must be decoded for an indexed instruction.
322    IndexedOperand,
323    /// An opcode must be decoded for a bitwise instruction.
324    BitwiseOpcode,
325    /// A displacement operand must be decoded for an indexed bitwise instruction.
326    IndexedBitwiseDisplacement,
327    /// An opcode must be decoded for an indexed bitwise instruction.
328    IndexedBitwiseOpcode,
329}
330
331/// Represents a single Z80 instruction.
332#[derive(Clone, Debug, PartialEq)]
333pub struct Instruction {
334    /// Collection of 0xDD and 0xFD opcodes (indexed instruction prefixes) that
335    /// are ignored during the decoding process, due to the opcodes they precede
336    /// not mapping to an actual indexed instruction. These ignored prefixes
337    /// incur a runtime cost, but have no other effect on the decoded instruction.
338    pub ignored_prefixes: Vec<OpcodePrefix>,
339    /// The actual opcode decoded for this instruction, including any prefix.
340    pub opcode: Opcode,
341    /// The instruction type for this instruction, which maps to a mnemonic.
342    pub r#type: InstructionType,
343    /// The source operand for this instruction if any, indicating where data is read.
344    pub source: Option<Operand>,
345    /// The destination operand for this instruction if any, indicating where data is written.
346    pub destination: Option<Operand>,
347}
348
349impl Instruction {
350    /// Provides the raw encoded representation of the instruction.
351    pub fn to_bytes(&self) -> Vec<u8> {
352        use Operand::*;
353
354        let mut bytes = Vec::with_capacity(4 + self.ignored_prefixes.len());
355        bytes.extend(self.ignored_prefixes.iter().flat_map(|x| x.to_bytes()));
356
357        // While writing any prefix bytes, signal a delay in the opcode write
358        // if the instruction is a bitwise indexed one.
359        let mut delay_opcode = false;
360        if let Some(prefix) = self.opcode.prefix {
361            bytes.extend(prefix.to_bytes());
362
363            if let OpcodePrefix::IndexedBitwise(_) = prefix {
364                delay_opcode = true
365            }
366        }
367
368        if !delay_opcode {
369            bytes.push(self.opcode.value);
370        }
371
372        match self.destination {
373            Some(MemoryDirect(addr)) => bytes.extend(&addr.to_le_bytes()),
374            Some(MemoryIndexed(_, idx))
375            | Some(MemoryIndexedBit(_, idx, _))
376            | Some(MemoryIndexedAndRegister(_, idx, _))
377            | Some(MemoryIndexedBitAndRegister(_, idx, _, _)) => bytes.push(idx as u8),
378            Some(ProgramCounterRelative(offset)) => bytes.push(offset as u8),
379            Some(PortDirect(port)) => bytes.push(port),
380            _ => (),
381        };
382
383        match self.source {
384            Some(OctetImmediate(val)) => bytes.push(val),
385            Some(DoubletImmediate(val)) => bytes.extend(&val.to_le_bytes()),
386            Some(MemoryDirect(addr)) => bytes.extend(&addr.to_le_bytes()),
387            Some(MemoryIndexed(_, idx))
388            | Some(MemoryIndexedBit(_, idx, _))
389            | Some(MemoryIndexedAndRegister(_, idx, _))
390            | Some(MemoryIndexedBitAndRegister(_, idx, _, _)) => bytes.push(idx as u8),
391            Some(ProgramCounterRelative(offset)) => bytes.push(offset as u8),
392            Some(PortDirect(port)) => bytes.push(port),
393            _ => (),
394        };
395
396        if delay_opcode {
397            bytes.push(self.opcode.value);
398        }
399
400        bytes
401    }
402
403    /// Decodes a single instruction (opcode and operands).
404    #[allow(clippy::cognitive_complexity)]
405    #[rustfmt::skip]
406    fn decode_one_inner<R: Read>(bytes: &mut Peekable<Bytes<R>>) -> Result<Self, DecodingState> {
407        /// Flattens the next byte in the stream to an `Option<u8>` value.
408        /// Any read error (due to having reached the end of the stream or otherwise) returns `None`.
409        fn next_byte<R: Read>(bytes: &mut Peekable<Bytes<R>>) -> Option<u8> {
410            bytes.next()?.ok()
411        }
412
413        /// Flattens the next two bytes in the stream to an `Option<u16>` value.
414        /// Any read error (due to having reached the end of the stream or otherwise) returns `None`.
415        fn next_doublet<R: Read>(bytes: &mut Peekable<Bytes<R>>) -> Option<u16> {
416            Some(u16::from_le_bytes([next_byte(bytes)?, next_byte(bytes)?]))
417        }
418
419        /// Flattens the next byte in the stream to an `Option<u8>` value.
420        /// Any read error (due to having reached the end of the stream or otherwise) returns `None`.
421        fn peek_byte<R: Read>(bytes: &mut Peekable<Bytes<R>>) -> Option<u8> {
422            if let Some(&Ok(val)) = bytes.peek() {
423                Some(val)
424            } else {
425                None
426            }
427        }
428
429        use Condition::*;
430        use InstructionType::*;
431        use OpcodePrefix::*;
432        use Operand::*;
433        use RegisterPairType::*;
434        use SingleRegisterType::*;
435
436        /// Decodes a partial extended instruction, whose opcode is known to begin with `0xED`.
437        fn decode_extended_instruction<R: Read>(bytes: &mut Peekable<Bytes<R>>) -> Result<Instruction, DecodingState> {
438            let opcode = next_byte(bytes).ok_or(DecodingState::ExtendedOpcode)?;
439
440            macro_rules! extended {
441                ($($args: tt)+) => { instruction!(Opcode { prefix: Some(Extended), value: opcode }, $($args)+) }
442            }
443
444            // Simplifies instruction definitions by abstracting away the conversion
445            // from a `None` returned from an operand fetch to the appropriate error.
446            macro_rules! next_doublet {
447                () => { next_doublet(bytes).ok_or(DecodingState::ExtendedOperand)? };
448            }
449
450            let instruction = match opcode {
451                // 0x00 ~ 0x3F
452                0x40 => extended!(In, PortIndirect(C), RegisterImplied(B)),
453                0x41 => extended!(Out, RegisterImplied(B), PortIndirect(C)),
454                0x42 => extended!(Sbc, RegisterPairImplied(BC), RegisterPairImplied(HL)),
455                0x43 => extended!(Ld, RegisterPairImplied(BC), MemoryDirect(next_doublet!())),
456                0x44 => extended!(Neg),
457                0x45 => extended!(Retn),
458                0x46 => extended!(Im(0)),
459                0x47 => extended!(Ld, RegisterImplied(A), RegisterImplied(I)),
460                0x48 => extended!(In, PortIndirect(C), RegisterImplied(C)),
461                0x49 => extended!(Out, RegisterImplied(C), PortIndirect(C)),
462                0x4A => extended!(Adc, RegisterPairImplied(BC), RegisterPairImplied(HL)),
463                0x4B => extended!(Ld, MemoryDirect(next_doublet!()), RegisterPairImplied(BC)),
464                0x4C => extended!(Neg),
465                0x4D => extended!(Reti),
466                0x4E => extended!(Im(0)), // sometimes reported as undefined between Im(0) and Im(1)
467                0x4F => extended!(Ld, RegisterImplied(A), RegisterImplied(R)),
468                0x50 => extended!(In, PortIndirect(C), RegisterImplied(D)),
469                0x51 => extended!(Out, RegisterImplied(D), PortIndirect(C)),
470                0x52 => extended!(Sbc, RegisterPairImplied(DE), RegisterPairImplied(HL)),
471                0x53 => extended!(Ld, RegisterPairImplied(DE), MemoryDirect(next_doublet!())),
472                0x54 => extended!(Neg),
473                0x55 => extended!(Retn),
474                0x56 => extended!(Im(1)),
475                0x57 => extended!(Ld, RegisterImplied(I), RegisterImplied(A)),
476                0x58 => extended!(In, PortIndirect(C), RegisterImplied(E)),
477                0x59 => extended!(Out, RegisterImplied(E), PortIndirect(C)),
478                0x5A => extended!(Adc, RegisterPairImplied(DE), RegisterPairImplied(HL)),
479                0x5B => extended!(Ld, MemoryDirect(next_doublet!()), RegisterPairImplied(DE)),
480                0x5C => extended!(Neg),
481                0x5D => extended!(Retn),
482                0x5E => extended!(Im(2)),
483                0x5F => extended!(Ld, RegisterImplied(R), RegisterImplied(A)),
484                0x60 => extended!(In, PortIndirect(C), RegisterImplied(H)),
485                0x61 => extended!(Out, RegisterImplied(H), PortIndirect(C)),
486                0x62 => extended!(Sbc, RegisterPairImplied(HL), RegisterPairImplied(HL)),
487                0x63 => extended!(Ld, RegisterPairImplied(HL), MemoryDirect(next_doublet!())),
488                0x64 => extended!(Neg),
489                0x65 => extended!(Retn),
490                0x66 => extended!(Im(0)),
491                0x67 => extended!(Rrd),
492                0x68 => extended!(In, PortIndirect(C), RegisterImplied(L)),
493                0x69 => extended!(Out, RegisterImplied(L), PortIndirect(C)),
494                0x6A => extended!(Adc, RegisterPairImplied(HL), RegisterPairImplied(HL)),
495                0x6B => extended!(Ld, MemoryDirect(next_doublet!()), RegisterPairImplied(HL)),
496                0x6C => extended!(Neg),
497                0x6D => extended!(Retn),
498                0x6E => extended!(Im(0)), // sometimes reported as undefined between Im(0) and Im(1)
499                0x6F => extended!(Rld),
500                0x70 => extended!(In, source: PortIndirect(C)),
501                0x71 => extended!(Out, OctetImplied(0), PortIndirect(C)),
502                0x72 => extended!(Sbc, RegisterPairImplied(SP), RegisterPairImplied(HL)),
503                0x73 => extended!(Ld, RegisterPairImplied(SP), MemoryDirect(next_doublet!())),
504                0x74 => extended!(Neg),
505                0x75 => extended!(Retn),
506                0x76 => extended!(Im(1)),
507                // 0x77
508                0x78 => extended!(In, PortIndirect(C), RegisterImplied(A)),
509                0x79 => extended!(Out, RegisterImplied(A), PortIndirect(C)),
510                0x7A => extended!(Adc, RegisterPairImplied(SP), RegisterPairImplied(HL)),
511                0x7B => extended!(Ld, MemoryDirect(next_doublet!()), RegisterPairImplied(SP)),
512                0x7C => extended!(Neg),
513                0x7D => extended!(Retn),
514                0x7E => extended!(Im(2)),
515                // 0x7F ~ 0x9F
516                0xA0 => extended!(Ldi),
517                0xA1 => extended!(Cpi),
518                0xA2 => extended!(Ini),
519                0xA3 => extended!(Outi),
520                // 0xA4 ~ 0xA7
521                0xA8 => extended!(Ldd),
522                0xA9 => extended!(Cpd),
523                0xAA => extended!(Ind),
524                0xAB => extended!(Outd),
525                // 0xAC ~ 0xAF
526                0xB0 => extended!(Ldir),
527                0xB1 => extended!(Cpir),
528                0xB2 => extended!(Inir),
529                0xB3 => extended!(Otir),
530                // 0xB4 ~ 0xB7
531                0xB8 => extended!(Lddr),
532                0xB9 => extended!(Cpdr),
533                0xBA => extended!(Indr),
534                0xBB => extended!(Otdr),
535                // 0xBC ~ 0xFF
536                _ => extended!(Inva),
537            };
538
539            Ok(instruction)
540        }
541
542        /// Decodes a partial bit instruction, whose opcode is known to begin with `0xCB`, `0xDDCB`, or `0xFDCB`.
543        /// The prefix, ending with `0xCB`, is assumed to have been read already, so only the remainder is read from `bytes`.
544        fn decode_bit_instruction<R: Read>(
545            bytes: &mut Peekable<Bytes<R>>,
546            index_register: Option<RegisterPairType>,
547        ) -> Result<Instruction, DecodingState> {
548            // For indexed bitwise instructions, an offset is provided before the final opcode.
549            let (offset, opcode) = if index_register.is_some() {
550                (
551                    next_byte(bytes).ok_or(DecodingState::IndexedBitwiseDisplacement)? as i8,
552                    next_byte(bytes).ok_or(DecodingState::IndexedBitwiseOpcode)?,
553                )
554            } else {
555                (Default::default(), next_byte(bytes).ok_or(DecodingState::BitwiseOpcode)?)
556            };
557
558            macro_rules! bitwise {
559                ($($args: tt)+) => { instruction!(Opcode { prefix: Some(Bitwise), value: opcode }, $($args)+) }
560            }
561
562            macro_rules! indexed_bitwise {
563                ($($args: tt)+) => { instruction!(Opcode { prefix: Some(IndexedBitwise(index_register.unwrap())), value: opcode }, $($args)+) }
564            }
565
566            let instruction = match opcode & 0xF8 {
567                0x00 => Rlc,
568                0x08 => Rrc,
569                0x10 => Rl,
570                0x18 => Rr,
571                0x20 => Sla,
572                0x28 => Sra,
573                0x30 => Sll,
574                0x38 => Srl,
575                0x40 | 0x48 | 0x50 | 0x58 | 0x60 | 0x68 | 0x70 | 0x78 => Bit,
576                0x80 | 0x88 | 0x90 | 0x98 | 0xA0 | 0xA8 | 0xB0 | 0xB8 => Res,
577                0xC0 | 0xC8 | 0xD0 | 0xD8 | 0xE0 | 0xE8 | 0xF0 | 0xF8 => Set,
578                _ => unreachable!(),
579            };
580
581            let operand_register = match opcode & 0x07 {
582                0x00 => Some(B),
583                0x01 => Some(C),
584                0x02 => Some(D),
585                0x03 => Some(E),
586                0x04 => Some(H),
587                0x05 => Some(L),
588                0x06 => None,
589                0x07 => Some(A),
590                _ => unreachable!(),
591            };
592
593            let operand = if opcode < 0x40 {
594                match index_register {
595                    None => match operand_register {
596                        Some(reg) => RegisterImplied(reg),
597                        None => MemoryIndirect(HL),
598                    },
599                    Some(idx) => match operand_register {
600                        Some(reg) => MemoryIndexedAndRegister(idx, offset, reg),
601                        None => MemoryIndexed(idx, offset),
602                    },
603                }
604            } else {
605                let bit = opcode >> 3 & 0x07;
606                match index_register {
607                    None => match operand_register {
608                        Some(reg) => RegisterImpliedBit(reg, bit),
609                        None => MemoryIndirectBit(HL, bit),
610                    },
611                    Some(idx) => match operand_register {
612                        Some(reg) => MemoryIndexedBitAndRegister(idx, offset, bit, reg),
613                        None => MemoryIndexedBit(idx, offset, bit),
614                    },
615                }
616            };
617
618            let instruction = if index_register.is_some() {
619                indexed_bitwise!(instruction, destination: operand)
620            } else {
621                bitwise!(instruction, destination: operand)
622            };
623
624            Ok(instruction)
625        }
626
627        /// Decodes a partial index instruction, whose opcode is known to begin with `0xDD` or `0xFD`.
628        fn decode_index_instruction<R: Read>(
629            bytes: &mut Peekable<Bytes<R>>,
630            index_register: RegisterPairType,
631        ) -> Result<Instruction, DecodingState> {
632            let idx = index_register;
633            assert!(idx == IX || idx == IY);
634
635            let (idx_h, idx_l) = match idx {
636                IX => (IXH, IXL),
637                IY => (IYH, IYL),
638                _ => unreachable!(),
639            };
640            let opcode = peek_byte(bytes).ok_or(DecodingState::IndexedOpcode)?;
641
642            macro_rules! indexed {
643                ($($args: tt)+) => { instruction!(Opcode { prefix: Some(Indexed(idx)), value: opcode }, $($args)+) }
644            }
645
646            // Simplifies instruction definitions by abstracting away the conversion
647            // from a `None` returned from an operand fetch to the appropriate error.
648            macro_rules! next_byte {
649                () => { next_byte(bytes).ok_or(DecodingState::IndexedOperand)? };
650            }
651            macro_rules! next_doublet {
652                () => { next_doublet(bytes).ok_or(DecodingState::IndexedOperand)? };
653            }
654            macro_rules! next_displacement {
655                () => { next_byte(bytes).ok_or(DecodingState::IndexedDisplacement)? as i8 };
656            }
657
658            match opcode {
659                // Detect an invalid instruction first. This is needed to ensure that
660                // the reader moves ahead to the next opcode if it can be decoded.
661                // In the case of an invalid instruction, the reader should not advance
662                // and the next decoding step will begin with the second opcode in the
663                // sequence. Otherwise, the reader must advance to read operands correctly.
664                0x00..=0x08 | 0x0A..=0x18 | 0x1A..=0x20 |
665                0x27..=0x28 | 0x2F..=0x33 | 0x37..=0x38 |
666                0x3A..=0x43 | 0x47..=0x4B | 0x4F..=0x53 |
667                0x57..=0x5B | 0x5F | 0x76 | 0x78..=0x7B |
668                0x7F..=0x83 | 0x87..=0x8B | 0x8F..=0x93 |
669                0x97..=0x9B | 0x9F..=0xA3 | 0xA7..=0xAB |
670                0xAF..=0xB3 | 0xB7..=0xBB | 0xBF..=0xCA |
671                0xCC..=0xE0 | 0xE2 | 0xE4 | 0xE6..=0xE8 |
672                0xEA..=0xF8 | 0xFA..=0xFF => {
673                    // Decode up to the final instruction recursively.
674                    // This ensures that even if the opcode stream has multiple
675                    // redundant indexed instruction opcodes, the instruction
676                    // returned to the user will be the result of a full single
677                    // decode-fetch cycle.
678                    let mut final_instruction = Instruction::decode_one_inner(bytes)?;
679                    final_instruction.ignored_prefixes.insert(0, Indexed(idx));
680
681                    Ok(final_instruction)
682                }
683                _ => {
684                    bytes.next();
685
686                    let instruction = match opcode {
687                        // 0x00 ~ 0x08
688                        0x09 => indexed!(Add, RegisterPairImplied(BC), RegisterPairImplied(idx)),
689                        // 0x0A ~ 0x18
690                        0x19 => indexed!(Add, RegisterPairImplied(DE), RegisterPairImplied(idx)),
691                        // 0x1A ~ 0x20
692                        0x21 => indexed!(Ld, DoubletImmediate(next_doublet!()), RegisterPairImplied(idx)),
693                        0x22 => indexed!(Ld, RegisterPairImplied(idx), MemoryDirect(next_doublet!())),
694                        0x23 => indexed!(Inc, destination: RegisterPairImplied(idx)),
695                        0x24 => indexed!(Inc, destination: RegisterImplied(idx_h)),
696                        0x25 => indexed!(Dec, destination: RegisterImplied(idx_h)),
697                        0x26 => indexed!(Ld, OctetImmediate(next_byte!()), RegisterImplied(idx_h)),
698                        // 0x27 ~ 0x28
699                        0x29 => indexed!(Add, RegisterPairImplied(idx), RegisterPairImplied(idx)),
700                        0x2A => indexed!(Ld, MemoryDirect(next_doublet!()), RegisterPairImplied(idx)),
701                        0x2B => indexed!(Dec, destination: RegisterPairImplied(idx)),
702                        0x2C => indexed!(Inc, destination: RegisterImplied(idx_l)),
703                        0x2D => indexed!(Dec, destination: RegisterImplied(idx_l)),
704                        0x2E => indexed!(Ld, OctetImmediate(next_byte!()), RegisterImplied(idx_l)),
705                        // 0x2F ~ 0x33
706                        0x34 => indexed!(Inc, destination: MemoryIndexed(idx, next_displacement!())),
707                        0x35 => indexed!(Dec, destination: MemoryIndexed(idx, next_displacement!())),
708                        0x36 => indexed!(Ld, destination: MemoryIndexed(idx, next_displacement!()), source: OctetImmediate(next_byte!())),
709                        // 0x37 ~ 0x38
710                        0x39 => indexed!(Add, RegisterPairImplied(SP), RegisterPairImplied(idx)),
711                        // 0x3A ~ 0x43
712                        0x44 => indexed!(Ld, RegisterImplied(idx_h), RegisterImplied(B)),
713                        0x45 => indexed!(Ld, RegisterImplied(idx_l), RegisterImplied(B)),
714                        0x46 => indexed!(Ld, MemoryIndexed(idx, next_displacement!()), RegisterImplied(B)),
715                        // 0x47 ~ 0x4B
716                        0x4C => indexed!(Ld, RegisterImplied(idx_h), RegisterImplied(C)),
717                        0x4D => indexed!(Ld, RegisterImplied(idx_l), RegisterImplied(C)),
718                        0x4E => indexed!(Ld, MemoryIndexed(idx, next_displacement!()), RegisterImplied(C)),
719                        // 0x4F ~ 0x53
720                        0x54 => indexed!(Ld, RegisterImplied(idx_h), RegisterImplied(D)),
721                        0x55 => indexed!(Ld, RegisterImplied(idx_l), RegisterImplied(D)),
722                        0x56 => indexed!(Ld, MemoryIndexed(idx, next_displacement!()), RegisterImplied(D)),
723                        // 0x57 ~ 0x5B
724                        0x5C => indexed!(Ld, RegisterImplied(idx_h), RegisterImplied(E)),
725                        0x5D => indexed!(Ld, RegisterImplied(idx_l), RegisterImplied(E)),
726                        0x5E => indexed!(Ld, MemoryIndexed(idx, next_displacement!()), RegisterImplied(E)),
727                        // 0x5F
728                        0x60 => indexed!(Ld, RegisterImplied(B), RegisterImplied(idx_h)),
729                        0x61 => indexed!(Ld, RegisterImplied(C), RegisterImplied(idx_h)),
730                        0x62 => indexed!(Ld, RegisterImplied(D), RegisterImplied(idx_h)),
731                        0x63 => indexed!(Ld, RegisterImplied(E), RegisterImplied(idx_h)),
732                        0x64 => indexed!(Ld, RegisterImplied(idx_h), RegisterImplied(idx_h)),
733                        0x65 => indexed!(Ld, RegisterImplied(idx_l), RegisterImplied(idx_h)),
734                        0x66 => indexed!(Ld, MemoryIndexed(idx, next_displacement!()), RegisterImplied(H)),
735                        0x67 => indexed!(Ld, RegisterImplied(A), RegisterImplied(idx_h)),
736                        0x68 => indexed!(Ld, RegisterImplied(B), RegisterImplied(idx_l)),
737                        0x69 => indexed!(Ld, RegisterImplied(C), RegisterImplied(idx_l)),
738                        0x6A => indexed!(Ld, RegisterImplied(D), RegisterImplied(idx_l)),
739                        0x6B => indexed!(Ld, RegisterImplied(E), RegisterImplied(idx_l)),
740                        0x6C => indexed!(Ld, RegisterImplied(idx_h), RegisterImplied(idx_l)),
741                        0x6D => indexed!(Ld, RegisterImplied(idx_l), RegisterImplied(idx_l)),
742                        0x6E => indexed!(Ld, MemoryIndexed(idx, next_displacement!()), RegisterImplied(L)),
743                        0x6F => indexed!(Ld, RegisterImplied(A), RegisterImplied(idx_l)),
744                        0x70 => indexed!(Ld, RegisterImplied(B), MemoryIndexed(idx, next_displacement!())),
745                        0x71 => indexed!(Ld, RegisterImplied(C), MemoryIndexed(idx, next_displacement!())),
746                        0x72 => indexed!(Ld, RegisterImplied(D), MemoryIndexed(idx, next_displacement!())),
747                        0x73 => indexed!(Ld, RegisterImplied(E), MemoryIndexed(idx, next_displacement!())),
748                        0x74 => indexed!(Ld, RegisterImplied(H), MemoryIndexed(idx, next_displacement!())),
749                        0x75 => indexed!(Ld, RegisterImplied(L), MemoryIndexed(idx, next_displacement!())),
750                        // 0x76
751                        0x77 => indexed!(Ld, RegisterImplied(A), MemoryIndexed(idx, next_displacement!())),
752                        // 0x78 ~ 0x7B
753                        0x7C => indexed!(Ld, RegisterImplied(idx_h), RegisterImplied(A)),
754                        0x7D => indexed!(Ld, RegisterImplied(idx_l), RegisterImplied(A)),
755                        0x7E => indexed!(Ld, MemoryIndexed(idx, next_displacement!()), RegisterImplied(A)),
756                        // 0x7F ~ 0x83
757                        0x84 => indexed!(Add, RegisterImplied(idx_h), RegisterImplied(A)),
758                        0x85 => indexed!(Add, RegisterImplied(idx_l), RegisterImplied(A)),
759                        0x86 => indexed!(Add, MemoryIndexed(idx, next_displacement!()), RegisterImplied(A)),
760                        // 0x87 ~ 0x8B
761                        0x8C => indexed!(Adc, RegisterImplied(idx_h), RegisterImplied(A)),
762                        0x8D => indexed!(Adc, RegisterImplied(idx_l), RegisterImplied(A)),
763                        0x8E => indexed!(Adc, MemoryIndexed(idx, next_displacement!()), RegisterImplied(A)),
764                        // 0x8F ~ 0x93
765                        0x94 => indexed!(Sub, source: RegisterImplied(idx_h)),
766                        0x95 => indexed!(Sub, source: RegisterImplied(idx_l)),
767                        0x96 => indexed!(Sub, source: MemoryIndexed(idx, next_displacement!())),
768                        // 0x97 ~ 0x9B
769                        0x9C => indexed!(Sbc, RegisterImplied(idx_h), RegisterImplied(A)),
770                        0x9D => indexed!(Sbc, RegisterImplied(idx_l), RegisterImplied(A)),
771                        0x9E => indexed!(Sbc, MemoryIndexed(idx, next_displacement!()), RegisterImplied(A)),
772                        // 0x9F ~ 0xA3
773                        0xA4 => indexed!(And, source: RegisterImplied(idx_h)),
774                        0xA5 => indexed!(And, source: RegisterImplied(idx_l)),
775                        0xA6 => indexed!(And, source: MemoryIndexed(idx, next_displacement!())),
776                        // 0xA7 ~ 0xAB
777                        0xAC => indexed!(Xor, source: RegisterImplied(idx_h)),
778                        0xAD => indexed!(Xor, source: RegisterImplied(idx_l)),
779                        0xAE => indexed!(Xor, source: MemoryIndexed(idx, next_displacement!())),
780                        // 0xAF ~ 0xB3
781                        0xB4 => indexed!(Or, source: RegisterImplied(idx_h)),
782                        0xB5 => indexed!(Or, source: RegisterImplied(idx_l)),
783                        0xB6 => indexed!(Or, source: MemoryIndexed(idx, next_displacement!())),
784                        // 0xB7 ~ 0xBB
785                        0xBC => indexed!(Cp, source: RegisterImplied(idx_h)),
786                        0xBD => indexed!(Cp, source: RegisterImplied(idx_l)),
787                        0xBE => indexed!(Cp, source: MemoryIndexed(idx, next_displacement!())),
788                        // 0xBF ~ 0xCA
789                        0xCB => decode_bit_instruction(bytes, Some(idx))?,
790                        // 0xCC ~ 0xE0
791                        0xE1 => indexed!(Pop, destination: RegisterPairImplied(idx)),
792                        // 0xE2
793                        0xE3 => indexed!(Ex, RegisterPairImplied(idx), MemoryIndirect(SP)),
794                        // 0xE4
795                        0xE5 => indexed!(Push, source: RegisterPairImplied(idx)),
796                        // 0xE6 ~ 0xE8
797                        0xE9 => indexed!(Jp(None), source: RegisterPairImplied(idx)),
798                        // 0xEA ~ 0xF8
799                        0xF9 => indexed!(Ld, RegisterPairImplied(idx), RegisterPairImplied(SP)),
800                        // 0xFA ~ 0xFF
801                        _ => unreachable!(),
802                    };
803
804                    Ok(instruction)
805                }
806            }
807        }
808
809        // Parse the instruction opcode and operands byte by byte.
810        let opcode = next_byte(bytes).ok_or(DecodingState::RootOpcode)?;
811
812        macro_rules! root {
813            ($($args: tt)+) => { instruction!(Opcode { prefix: None, value: opcode }, $($args)+) }
814        }
815
816        // Simplifies instruction definitions by abstracting away the conversion
817        // from a `None` returned from an operand fetch to the appropriate error.
818        macro_rules! next_byte {
819            () => { next_byte(bytes).ok_or(DecodingState::RootOperand)? };
820        }
821        macro_rules! next_doublet {
822            () => { next_doublet(bytes).ok_or(DecodingState::RootOperand)? };
823        }
824        macro_rules! next_displacement {
825            () => { next_byte(bytes).ok_or(DecodingState::RootDisplacement)? as i8 };
826        }
827
828        let instruction = match opcode {
829            0x00 => root!(Nop),
830            0x01 => root!(Ld, DoubletImmediate(next_doublet!()), RegisterPairImplied(BC)),
831            0x02 => root!(Ld, RegisterImplied(A), MemoryIndirect(BC)),
832            0x03 => root!(Inc, destination: RegisterPairImplied(BC)),
833            0x04 => root!(Inc, destination: RegisterImplied(B)),
834            0x05 => root!(Dec, destination: RegisterImplied(B)),
835            0x06 => root!(Ld, OctetImmediate(next_byte!()), RegisterImplied(B)),
836            0x07 => root!(Rlca),
837            0x08 => root!(Ex, RegisterPairImplied(AF_), RegisterPairImplied(AF)),
838            0x09 => root!(Add, RegisterPairImplied(BC), RegisterPairImplied(HL)),
839            0x0A => root!(Ld, MemoryIndirect(BC), RegisterImplied(A)),
840            0x0B => root!(Dec, destination: RegisterPairImplied(BC)),
841            0x0C => root!(Inc, destination: RegisterImplied(C)),
842            0x0D => root!(Dec, destination: RegisterImplied(C)),
843            0x0E => root!(Ld, OctetImmediate(next_byte!()), RegisterImplied(C)),
844            0x0F => root!(Rrca),
845            0x10 => root!(Djnz, source: ProgramCounterRelative(next_displacement!())),
846            0x11 => root!(Ld, DoubletImmediate(next_doublet!()), RegisterPairImplied(DE)),
847            0x12 => root!(Ld, RegisterImplied(A), MemoryIndirect(DE)),
848            0x13 => root!(Inc, destination: RegisterPairImplied(DE)),
849            0x14 => root!(Inc, destination: RegisterImplied(D)),
850            0x15 => root!(Dec, destination: RegisterImplied(D)),
851            0x16 => root!(Ld, OctetImmediate(next_byte!()), RegisterImplied(D)),
852            0x17 => root!(Rla),
853            0x18 => root!(Jr(None), source: ProgramCounterRelative(next_displacement!())),
854            0x19 => root!(Add, RegisterPairImplied(DE), RegisterPairImplied(HL)),
855            0x1A => root!(Ld, MemoryIndirect(DE), RegisterImplied(A)),
856            0x1B => root!(Dec, destination: RegisterPairImplied(DE)),
857            0x1C => root!(Inc, destination: RegisterImplied(E)),
858            0x1D => root!(Dec, destination: RegisterImplied(E)),
859            0x1E => root!(Ld, OctetImmediate(next_byte!()), RegisterImplied(E)),
860            0x1F => root!(Rra),
861            0x20 => root!(Jr(Some(FlagNotSet(Flag::Z))), source: ProgramCounterRelative(next_displacement!())),
862            0x21 => root!(Ld, DoubletImmediate(next_doublet!()), RegisterPairImplied(HL)),
863            0x22 => root!(Ld, RegisterPairImplied(HL), MemoryDirect(next_doublet!())),
864            0x23 => root!(Inc, destination: RegisterPairImplied(HL)),
865            0x24 => root!(Inc, destination: RegisterImplied(H)),
866            0x25 => root!(Dec, destination: RegisterImplied(H)),
867            0x26 => root!(Ld, OctetImmediate(next_byte!()), RegisterImplied(H)),
868            0x27 => root!(Daa),
869            0x28 => root!(Jr(Some(FlagSet(Flag::Z))), source: ProgramCounterRelative(next_displacement!())),
870            0x29 => root!(Add, RegisterPairImplied(HL), RegisterPairImplied(HL)),
871            0x2A => root!(Ld, MemoryDirect(next_doublet!()), RegisterPairImplied(HL)),
872            0x2B => root!(Dec, destination: RegisterPairImplied(HL)),
873            0x2C => root!(Inc, destination: RegisterImplied(L)),
874            0x2D => root!(Dec, destination: RegisterImplied(L)),
875            0x2E => root!(Ld, OctetImmediate(next_byte!()), RegisterImplied(L)),
876            0x2F => root!(Cpl),
877            0x30 => root!(Jr(Some(FlagNotSet(Flag::C))), source: ProgramCounterRelative(next_displacement!())),
878            0x31 => root!(Ld, DoubletImmediate(next_doublet!()), RegisterPairImplied(SP)),
879            0x32 => root!(Ld, RegisterImplied(A), MemoryDirect(next_doublet!())),
880            0x33 => root!(Inc, destination: RegisterPairImplied(SP)),
881            0x34 => root!(Inc, destination: MemoryIndirect(HL)),
882            0x35 => root!(Dec, destination: MemoryIndirect(HL)),
883            0x36 => root!(Ld, OctetImmediate(next_byte!()), MemoryIndirect(HL)),
884            0x37 => root!(Scf),
885            0x38 => root!(Jr(Some(FlagSet(Flag::C))), source: ProgramCounterRelative(next_displacement!())),
886            0x39 => root!(Add, RegisterPairImplied(SP), RegisterPairImplied(HL)),
887            0x3A => root!(Ld, MemoryDirect(next_doublet!()), RegisterImplied(A)),
888            0x3B => root!(Dec, destination: RegisterPairImplied(SP)),
889            0x3C => root!(Inc, destination: RegisterImplied(A)),
890            0x3D => root!(Dec, destination: RegisterImplied(A)),
891            0x3E => root!(Ld, OctetImmediate(next_byte!()), RegisterImplied(A)),
892            0x3F => root!(Ccf),
893            0x40 => root!(Ld, RegisterImplied(B), RegisterImplied(B)),
894            0x41 => root!(Ld, RegisterImplied(C), RegisterImplied(B)),
895            0x42 => root!(Ld, RegisterImplied(D), RegisterImplied(B)),
896            0x43 => root!(Ld, RegisterImplied(E), RegisterImplied(B)),
897            0x44 => root!(Ld, RegisterImplied(H), RegisterImplied(B)),
898            0x45 => root!(Ld, RegisterImplied(L), RegisterImplied(B)),
899            0x46 => root!(Ld, MemoryIndirect(HL), RegisterImplied(B)),
900            0x47 => root!(Ld, RegisterImplied(A), RegisterImplied(B)),
901            0x48 => root!(Ld, RegisterImplied(B), RegisterImplied(C)),
902            0x49 => root!(Ld, RegisterImplied(C), RegisterImplied(C)),
903            0x4A => root!(Ld, RegisterImplied(D), RegisterImplied(C)),
904            0x4B => root!(Ld, RegisterImplied(E), RegisterImplied(C)),
905            0x4C => root!(Ld, RegisterImplied(H), RegisterImplied(C)),
906            0x4D => root!(Ld, RegisterImplied(L), RegisterImplied(C)),
907            0x4E => root!(Ld, MemoryIndirect(HL), RegisterImplied(C)),
908            0x4F => root!(Ld, RegisterImplied(A), RegisterImplied(C)),
909            0x50 => root!(Ld, RegisterImplied(B), RegisterImplied(D)),
910            0x51 => root!(Ld, RegisterImplied(C), RegisterImplied(D)),
911            0x52 => root!(Ld, RegisterImplied(D), RegisterImplied(D)),
912            0x53 => root!(Ld, RegisterImplied(E), RegisterImplied(D)),
913            0x54 => root!(Ld, RegisterImplied(H), RegisterImplied(D)),
914            0x55 => root!(Ld, RegisterImplied(L), RegisterImplied(D)),
915            0x56 => root!(Ld, MemoryIndirect(HL), RegisterImplied(D)),
916            0x57 => root!(Ld, RegisterImplied(A), RegisterImplied(D)),
917            0x58 => root!(Ld, RegisterImplied(B), RegisterImplied(E)),
918            0x59 => root!(Ld, RegisterImplied(C), RegisterImplied(E)),
919            0x5A => root!(Ld, RegisterImplied(D), RegisterImplied(E)),
920            0x5B => root!(Ld, RegisterImplied(E), RegisterImplied(E)),
921            0x5C => root!(Ld, RegisterImplied(H), RegisterImplied(E)),
922            0x5D => root!(Ld, RegisterImplied(L), RegisterImplied(E)),
923            0x5E => root!(Ld, MemoryIndirect(HL), RegisterImplied(E)),
924            0x5F => root!(Ld, RegisterImplied(A), RegisterImplied(E)),
925            0x60 => root!(Ld, RegisterImplied(B), RegisterImplied(H)),
926            0x61 => root!(Ld, RegisterImplied(C), RegisterImplied(H)),
927            0x62 => root!(Ld, RegisterImplied(D), RegisterImplied(H)),
928            0x63 => root!(Ld, RegisterImplied(E), RegisterImplied(H)),
929            0x64 => root!(Ld, RegisterImplied(H), RegisterImplied(H)),
930            0x65 => root!(Ld, RegisterImplied(L), RegisterImplied(H)),
931            0x66 => root!(Ld, MemoryIndirect(HL), RegisterImplied(H)),
932            0x67 => root!(Ld, RegisterImplied(A), RegisterImplied(H)),
933            0x68 => root!(Ld, RegisterImplied(B), RegisterImplied(L)),
934            0x69 => root!(Ld, RegisterImplied(C), RegisterImplied(L)),
935            0x6A => root!(Ld, RegisterImplied(D), RegisterImplied(L)),
936            0x6B => root!(Ld, RegisterImplied(E), RegisterImplied(L)),
937            0x6C => root!(Ld, RegisterImplied(H), RegisterImplied(L)),
938            0x6D => root!(Ld, RegisterImplied(L), RegisterImplied(L)),
939            0x6E => root!(Ld, MemoryIndirect(HL), RegisterImplied(L)),
940            0x6F => root!(Ld, RegisterImplied(A), RegisterImplied(L)),
941            0x70 => root!(Ld, RegisterImplied(B), MemoryIndirect(HL)),
942            0x71 => root!(Ld, RegisterImplied(C), MemoryIndirect(HL)),
943            0x72 => root!(Ld, RegisterImplied(D), MemoryIndirect(HL)),
944            0x73 => root!(Ld, RegisterImplied(E), MemoryIndirect(HL)),
945            0x74 => root!(Ld, RegisterImplied(H), MemoryIndirect(HL)),
946            0x75 => root!(Ld, RegisterImplied(L), MemoryIndirect(HL)),
947            0x76 => root!(Halt),
948            0x77 => root!(Ld, RegisterImplied(A), MemoryIndirect(HL)),
949            0x78 => root!(Ld, RegisterImplied(B), RegisterImplied(A)),
950            0x79 => root!(Ld, RegisterImplied(C), RegisterImplied(A)),
951            0x7A => root!(Ld, RegisterImplied(D), RegisterImplied(A)),
952            0x7B => root!(Ld, RegisterImplied(E), RegisterImplied(A)),
953            0x7C => root!(Ld, RegisterImplied(H), RegisterImplied(A)),
954            0x7D => root!(Ld, RegisterImplied(L), RegisterImplied(A)),
955            0x7E => root!(Ld, MemoryIndirect(HL), RegisterImplied(A)),
956            0x7F => root!(Ld, RegisterImplied(A), RegisterImplied(A)),
957            0x80 => root!(Add, RegisterImplied(B), RegisterImplied(A)),
958            0x81 => root!(Add, RegisterImplied(C), RegisterImplied(A)),
959            0x82 => root!(Add, RegisterImplied(D), RegisterImplied(A)),
960            0x83 => root!(Add, RegisterImplied(E), RegisterImplied(A)),
961            0x84 => root!(Add, RegisterImplied(H), RegisterImplied(A)),
962            0x85 => root!(Add, RegisterImplied(L), RegisterImplied(A)),
963            0x86 => root!(Add, MemoryIndirect(HL), RegisterImplied(A)),
964            0x87 => root!(Add, RegisterImplied(A), RegisterImplied(A)),
965            0x88 => root!(Adc, RegisterImplied(B), RegisterImplied(A)),
966            0x89 => root!(Adc, RegisterImplied(C), RegisterImplied(A)),
967            0x8A => root!(Adc, RegisterImplied(D), RegisterImplied(A)),
968            0x8B => root!(Adc, RegisterImplied(E), RegisterImplied(A)),
969            0x8C => root!(Adc, RegisterImplied(H), RegisterImplied(A)),
970            0x8D => root!(Adc, RegisterImplied(L), RegisterImplied(A)),
971            0x8E => root!(Adc, MemoryIndirect(HL), RegisterImplied(A)),
972            0x8F => root!(Adc, RegisterImplied(A), RegisterImplied(A)),
973            0x90 => root!(Sub, source: RegisterImplied(B)),
974            0x91 => root!(Sub, source: RegisterImplied(C)),
975            0x92 => root!(Sub, source: RegisterImplied(D)),
976            0x93 => root!(Sub, source: RegisterImplied(E)),
977            0x94 => root!(Sub, source: RegisterImplied(H)),
978            0x95 => root!(Sub, source: RegisterImplied(L)),
979            0x96 => root!(Sub, source: MemoryIndirect(HL)),
980            0x97 => root!(Sub, source: RegisterImplied(A)),
981            0x98 => root!(Sbc, RegisterImplied(B), RegisterImplied(A)),
982            0x99 => root!(Sbc, RegisterImplied(C), RegisterImplied(A)),
983            0x9A => root!(Sbc, RegisterImplied(D), RegisterImplied(A)),
984            0x9B => root!(Sbc, RegisterImplied(E), RegisterImplied(A)),
985            0x9C => root!(Sbc, RegisterImplied(H), RegisterImplied(A)),
986            0x9D => root!(Sbc, RegisterImplied(L), RegisterImplied(A)),
987            0x9E => root!(Sbc, MemoryIndirect(HL), RegisterImplied(A)),
988            0x9F => root!(Sbc, RegisterImplied(A), RegisterImplied(A)),
989            0xA0 => root!(And, source: RegisterImplied(B)),
990            0xA1 => root!(And, source: RegisterImplied(C)),
991            0xA2 => root!(And, source: RegisterImplied(D)),
992            0xA3 => root!(And, source: RegisterImplied(E)),
993            0xA4 => root!(And, source: RegisterImplied(H)),
994            0xA5 => root!(And, source: RegisterImplied(L)),
995            0xA6 => root!(And, source: MemoryIndirect(HL)),
996            0xA7 => root!(And, source: RegisterImplied(A)),
997            0xA8 => root!(Xor, source: RegisterImplied(B)),
998            0xA9 => root!(Xor, source: RegisterImplied(C)),
999            0xAA => root!(Xor, source: RegisterImplied(D)),
1000            0xAB => root!(Xor, source: RegisterImplied(E)),
1001            0xAC => root!(Xor, source: RegisterImplied(H)),
1002            0xAD => root!(Xor, source: RegisterImplied(L)),
1003            0xAE => root!(Xor, source: MemoryIndirect(HL)),
1004            0xAF => root!(Xor, source: RegisterImplied(A)),
1005            0xB0 => root!(Or, source: RegisterImplied(B)),
1006            0xB1 => root!(Or, source: RegisterImplied(C)),
1007            0xB2 => root!(Or, source: RegisterImplied(D)),
1008            0xB3 => root!(Or, source: RegisterImplied(E)),
1009            0xB4 => root!(Or, source: RegisterImplied(H)),
1010            0xB5 => root!(Or, source: RegisterImplied(L)),
1011            0xB6 => root!(Or, source: MemoryIndirect(HL)),
1012            0xB7 => root!(Or, source: RegisterImplied(A)),
1013            0xB8 => root!(Cp, source: RegisterImplied(B)),
1014            0xB9 => root!(Cp, source: RegisterImplied(C)),
1015            0xBA => root!(Cp, source: RegisterImplied(D)),
1016            0xBB => root!(Cp, source: RegisterImplied(E)),
1017            0xBC => root!(Cp, source: RegisterImplied(H)),
1018            0xBD => root!(Cp, source: RegisterImplied(L)),
1019            0xBE => root!(Cp, source: MemoryIndirect(HL)),
1020            0xBF => root!(Cp, source: RegisterImplied(A)),
1021            0xC0 => root!(Ret(Some(FlagNotSet(Flag::Z)))),
1022            0xC1 => root!(Pop, destination: RegisterPairImplied(BC)),
1023            0xC2 => root!(Jp(Some(FlagNotSet(Flag::Z))), source: DoubletImmediate(next_doublet!())),
1024            0xC3 => root!(Jp(None), source: DoubletImmediate(next_doublet!())),
1025            0xC4 => root!(Call(Some(FlagNotSet(Flag::Z))), source: DoubletImmediate(next_doublet!())),
1026            0xC5 => root!(Push, source: RegisterPairImplied(BC)),
1027            0xC6 => root!(Add, OctetImmediate(next_byte!()), RegisterImplied(A)),
1028            0xC7 => root!(Rst(0x00)),
1029            0xC8 => root!(Ret(Some(FlagSet(Flag::Z)))),
1030            0xC9 => root!(Ret(None)),
1031            0xCA => root!(Jp(Some(FlagSet(Flag::Z))), source: DoubletImmediate(next_doublet!())),
1032            0xCB => decode_bit_instruction(bytes, None)?,
1033            0xCC => root!(Call(Some(FlagSet(Flag::Z))), source: DoubletImmediate(next_doublet!())),
1034            0xCD => root!(Call(None), source: DoubletImmediate(next_doublet!())),
1035            0xCE => root!(Adc, OctetImmediate(next_byte!()), RegisterImplied(A)),
1036            0xCF => root!(Rst(0x08)),
1037            0xD0 => root!(Ret(Some(FlagNotSet(Flag::C)))),
1038            0xD1 => root!(Pop, destination: RegisterPairImplied(DE)),
1039            0xD2 => root!(Jp(Some(FlagNotSet(Flag::C))), source: DoubletImmediate(next_doublet!())),
1040            0xD3 => root!(Out, RegisterImplied(A), PortDirect(next_byte!())),
1041            0xD4 => root!(Call(Some(FlagNotSet(Flag::C))), source: DoubletImmediate(next_doublet!())),
1042            0xD5 => root!(Push, source: RegisterPairImplied(DE)),
1043            0xD6 => root!(Sub, source: OctetImmediate(next_byte!())),
1044            0xD7 => root!(Rst(0x10)),
1045            0xD8 => root!(Ret(Some(FlagSet(Flag::C)))),
1046            0xD9 => root!(Exx),
1047            0xDA => root!(Jp(Some(FlagSet(Flag::C))), source: DoubletImmediate(next_doublet!())),
1048            0xDB => root!(In, PortDirect(next_byte!()), RegisterImplied(A)),
1049            0xDC => root!(Call(Some(FlagSet(Flag::C))), source: DoubletImmediate(next_doublet!())),
1050            0xDD => decode_index_instruction(bytes, IX)?,
1051            0xDE => root!(Sbc, OctetImmediate(next_byte!()), RegisterImplied(A)),
1052            0xDF => root!(Rst(0x18)),
1053            0xE0 => root!(Ret(Some(FlagNotSet(Flag::PV)))),
1054            0xE1 => root!(Pop, destination: RegisterPairImplied(HL)),
1055            0xE2 => root!(Jp(Some(FlagNotSet(Flag::PV))), source: DoubletImmediate(next_doublet!())),
1056            0xE3 => root!(Ex, RegisterPairImplied(HL), MemoryIndirect(SP)),
1057            0xE4 => root!(Call(Some(FlagNotSet(Flag::PV))), source: DoubletImmediate(next_doublet!())),
1058            0xE5 => root!(Push, source: RegisterPairImplied(HL)),
1059            0xE6 => root!(And, source: OctetImmediate(next_byte!())),
1060            0xE7 => root!(Rst(0x20)),
1061            0xE8 => root!(Ret(Some(FlagSet(Flag::PV)))),
1062            0xE9 => root!(Jp(None), source: RegisterPairImplied(HL)),
1063            0xEA => root!(Jp(Some(FlagSet(Flag::PV))), source: DoubletImmediate(next_doublet!())),
1064            0xEB => root!(Ex, RegisterPairImplied(HL), RegisterPairImplied(DE)),
1065            0xEC => root!(Call(Some(FlagSet(Flag::PV))), source: DoubletImmediate(next_doublet!())),
1066            0xED => decode_extended_instruction(bytes)?,
1067            0xEE => root!(Xor, source: OctetImmediate(next_byte!())),
1068            0xEF => root!(Rst(0x28)),
1069            0xF0 => root!(Ret(Some(FlagNotSet(Flag::S)))),
1070            0xF1 => root!(Pop, destination: RegisterPairImplied(AF)),
1071            0xF2 => root!(Jp(Some(FlagNotSet(Flag::S))), source: DoubletImmediate(next_doublet!())),
1072            0xF3 => root!(Di),
1073            0xF4 => root!(Call(Some(FlagNotSet(Flag::S))), source: DoubletImmediate(next_doublet!())),
1074            0xF5 => root!(Push, source: RegisterPairImplied(AF)),
1075            0xF6 => root!(Or, source: OctetImmediate(next_byte!())),
1076            0xF7 => root!(Rst(0x30)),
1077            0xF8 => root!(Ret(Some(FlagSet(Flag::S)))),
1078            0xF9 => root!(Ld, RegisterPairImplied(HL), RegisterPairImplied(SP)),
1079            0xFA => root!(Jp(Some(FlagSet(Flag::S))), source: DoubletImmediate(next_doublet!())),
1080            0xFB => root!(Ei),
1081            0xFC => root!(Call(Some(FlagSet(Flag::S))), source: DoubletImmediate(next_doublet!())),
1082            0xFD => decode_index_instruction(bytes, IY)?,
1083            0xFE => root!(Cp, source: OctetImmediate(next_byte!())),
1084            0xFF => root!(Rst(0x38)),
1085        };
1086
1087        Ok(instruction)
1088    }
1089
1090    /// Decodes a single instruction from a source, or `None` if one cannot be decoded.
1091    /// This is a thin wrapper around `Instruction::decode_one_inner()`, which does not require
1092    /// the caller to convert its source to a `Peekable<Bytes<R>>` to simplify usage.
1093    pub fn decode_one<R: Read>(source: &mut R) -> Result<Instruction, DecodingState> {
1094        let mut bytes = source.bytes().peekable();
1095
1096        Instruction::decode_one_inner(&mut bytes)
1097    }
1098
1099    /// Decodes a sequence of instructions, until the end of the stream or an error is reached.
1100    pub fn decode_all<R: Read>(source: &mut R) -> Vec<Instruction> {
1101        let mut instructions = Vec::new();
1102
1103        while let Ok(instruction) = Instruction::decode_one(source) {
1104            instructions.push(instruction);
1105        }
1106
1107        instructions
1108    }
1109}
1110
1111impl Default for Instruction {
1112    fn default() -> Self {
1113        Instruction {
1114            ignored_prefixes: Vec::new(),
1115            opcode: Opcode { prefix: None, value: 0x00 },
1116            r#type: InstructionType::Nop,
1117            source: None,
1118            destination: None,
1119        }
1120    }
1121}
1122
1123/// Formats instructions by disassembling their raw byte representation.
1124impl fmt::Display for Instruction {
1125    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1126        use InstructionType::*;
1127        use OpcodePrefix::*;
1128
1129        match self.r#type {
1130            // Invalid instructions are commented out to make reassembly easier.
1131            // Any invalid prefix is folded into the printed opcodes in order.
1132            Inva => write!(
1133                f,
1134                ";{}{}",
1135                self.ignored_prefixes
1136                    .iter()
1137                    .fold(String::new(), |string, &prefix| string + &prefix.to_string() + " "),
1138                self.opcode
1139            ),
1140            _ => {
1141                match (self.source, self.destination) {
1142                    (Some(src), Some(dst)) => match self.opcode {
1143                        // 0xED71 is a special case, and some assemblers do not support hexadecimal representation for it.
1144                        Opcode { prefix: Some(Extended), value: 0x71 } => {
1145                            write!(f, "{} {}, 0", self.r#type, dst)
1146                        }
1147                        _ => write!(f, "{} {}, {}", self.r#type, dst, src),
1148                    },
1149                    (Some(operand), None) | (None, Some(operand)) => match self.r#type {
1150                        // Conditional instructions are written with a separator
1151                        // between the condition and the operand.
1152                        Call(Some(_)) | Jp(Some(_)) | Jr(Some(_)) | Ret(Some(_)) => match operand {
1153                            Operand::RegisterPairImplied(_) => {
1154                                write!(f, "{}, ({})", self.r#type, operand)
1155                            }
1156                            _ => write!(f, "{}, {}", self.r#type, operand),
1157                        },
1158                        Jp(None) | Jr(None) => match operand {
1159                            Operand::RegisterPairImplied(_) => {
1160                                write!(f, "{} ({})", self.r#type, operand)
1161                            }
1162                            _ => write!(f, "{} {}", self.r#type, operand),
1163                        },
1164                        _ => write!(f, "{} {}", self.r#type, operand),
1165                    },
1166                    (None, None) => write!(f, "{}", self.r#type),
1167                }?;
1168
1169                // Print any ignored (invalid) prefixes as comments.
1170                if !self.ignored_prefixes.is_empty() {
1171                    write!(
1172                        f,
1173                        " ;invalid prefix:{}",
1174                        self.ignored_prefixes.iter().fold(String::new(), |string, &prefix| string
1175                            + " "
1176                            + &prefix.to_string())
1177                    )
1178                } else {
1179                    Ok(())
1180                }
1181            }
1182        }
1183    }
1184}
1185
1186#[cfg(test)]
1187mod tests {
1188    use super::*;
1189
1190    #[test]
1191    fn format_opcode_prefix_doublet() {
1192        let indexed_bit_ix = OpcodePrefix::IndexedBitwise(RegisterPairType::IX);
1193        assert_eq!("DD CB", format!("{}", indexed_bit_ix));
1194    }
1195
1196    #[test]
1197    fn decode_instruction() {
1198        let inc_b = Instruction::decode_one(&mut [0x04].as_ref()).unwrap();
1199        assert_eq!(None, inc_b.source);
1200        assert_eq!(Some(Operand::RegisterImplied(SingleRegisterType::B)), inc_b.destination);
1201        assert_eq!(InstructionType::Inc, inc_b.r#type);
1202    }
1203
1204    #[test]
1205    fn decode_incomplete_instruction() {
1206        let ld_b = Instruction::decode_one(&mut [0x06].as_ref());
1207        assert_eq!(Err(DecodingState::RootOperand), ld_b);
1208    }
1209
1210    #[test]
1211    fn decode_instruction_default() {
1212        let nop = Instruction::decode_one(&mut [0x00].as_ref()).unwrap();
1213        assert_eq!(Instruction::default(), nop);
1214    }
1215
1216    #[test]
1217    fn decode_instruction_cb() {
1218        for opcode in 0x00..=0xFF {
1219            let cb_instruction = Instruction::decode_one(&mut [0xCB, opcode].as_ref());
1220            assert!(cb_instruction.is_ok());
1221        }
1222    }
1223
1224    #[test]
1225    fn decode_instruction_bit() {
1226        for opcode in 0x40..=0xFF {
1227            let bit_instruction = Instruction::decode_one(&mut [0xCB, opcode].as_ref()).unwrap();
1228            let offset = 0x40 * (opcode / 0x40);
1229
1230            let expected_instruction = match offset {
1231                0x40 => InstructionType::Bit,
1232                0x80 => InstructionType::Res,
1233                0xC0 => InstructionType::Set,
1234                _ => unreachable!(),
1235            };
1236            let actual_instruction = bit_instruction.r#type;
1237
1238            let expected_bit = (opcode - offset) / 8;
1239            let actual_bit = match bit_instruction.destination.unwrap() {
1240                Operand::RegisterImpliedBit(_, val) | Operand::MemoryIndirectBit(_, val) => val,
1241                _ => panic!("Unexpected decoded operand"),
1242            };
1243
1244            assert_eq!(expected_instruction, actual_instruction);
1245            assert_eq!(expected_bit, actual_bit);
1246        }
1247    }
1248
1249    #[test]
1250    fn display_instruction() {
1251        let ld_bc_bytes = &mut [0x01, 0xF0, 0x0F].as_ref();
1252        let ld_bc = Instruction::decode_one(ld_bc_bytes).unwrap();
1253        assert_eq!("LD BC, 0x0ff0", ld_bc.to_string());
1254    }
1255
1256    #[test]
1257    fn decode_instruction_sequence() {
1258        let nop_sequence_bytes = &mut [0x00, 0x00, 0x00].as_ref();
1259        let mut nop_sequence = Instruction::decode_all(nop_sequence_bytes);
1260        assert_eq!(3, nop_sequence.len());
1261
1262        while let Some(nop) = nop_sequence.pop() {
1263            assert_eq!(Instruction::default(), nop);
1264        }
1265    }
1266
1267    #[test]
1268    fn decode_incomplete_instruction_sequence() {
1269        let instruction_sequence_bytes = &mut [0x00, 0x00, 0x06].as_ref();
1270        let mut instruction_sequence = Instruction::decode_all(instruction_sequence_bytes);
1271        assert_eq!(2, instruction_sequence.len());
1272
1273        while let Some(nop) = instruction_sequence.pop() {
1274            assert_eq!(Instruction::default(), nop);
1275        }
1276    }
1277
1278    #[test]
1279    fn format_invalid_extended_instruction() {
1280        let invalid = Instruction::decode_one(&mut [0xED, 0x04].as_ref()).unwrap();
1281        assert_eq!(";ED 04", format!("{}", invalid));
1282    }
1283
1284    #[test]
1285    fn format_invalid_indexed_instruction() {
1286        use OpcodePrefix::*;
1287        use RegisterPairType::*;
1288
1289        let invalid =
1290            Instruction::decode_one(&mut [0xDD, 0xFD, 0xDD, 0xFD, 0xFD, 0x00].as_ref()).unwrap();
1291        assert_eq!(
1292            vec![Indexed(IX), Indexed(IY), Indexed(IX), Indexed(IY), Indexed(IY)],
1293            invalid.ignored_prefixes
1294        );
1295        assert_eq!(None, invalid.opcode.prefix);
1296        assert_eq!("NOP ;invalid prefix: DD FD DD FD FD", format!("{}", invalid));
1297    }
1298
1299    #[test]
1300    fn format_invalid_indexed_final_instruction() {
1301        let invalid = Instruction::decode_one(&mut [0xDD, 0xFD].as_ref());
1302        assert_eq!(Err(DecodingState::IndexedOpcode), invalid);
1303    }
1304
1305    #[test]
1306    fn format_invalid_extended_instruction_with_ignored_prefix() {
1307        let invalid = Instruction::decode_one(&mut [0xDD, 0xED, 0x04].as_ref()).unwrap();
1308        assert_eq!(";DD ED 04", format!("{}", invalid));
1309    }
1310
1311    #[test]
1312    fn format_implied_octet() {
1313        let result = Instruction::decode_one(&mut [0xED, 0x71].as_ref());
1314        assert_eq!("OUT (C), 0", result.unwrap().to_string());
1315    }
1316
1317    #[test]
1318    fn invalid_indexed_instruction_to_bytes() {
1319        let instruction_sequence_bytes = [0xDD, 0xFD, 0x00];
1320        let invalid = Instruction::decode_all(&mut instruction_sequence_bytes.as_ref());
1321        assert_eq!(instruction_sequence_bytes, invalid[0].to_bytes().as_slice());
1322    }
1323
1324    #[test]
1325    fn get_instruction_bytes() {
1326        // Single byte instructions
1327        for opcode in 0x00_u8..=0xFF_u8 {
1328            let result = Instruction::decode_one(&mut [opcode].as_ref());
1329            if let Ok(instruction) = result {
1330                assert_eq!(vec![opcode], instruction.to_bytes());
1331            }
1332        }
1333
1334        // Four byte IX bitwise instructions
1335        for opcode in 0xDDCB_0000_u32..=0xDDCB_FFFF_u32 {
1336            let bytes = opcode.to_be_bytes();
1337            let instruction = Instruction::decode_one(&mut bytes.as_ref()).unwrap();
1338            assert_eq!(bytes.to_vec(), instruction.to_bytes());
1339        }
1340    }
1341}