1use 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#[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#[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 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#[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, 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, Sra,
203 Srl,
204 Sub,
205 Xor,
206}
207
208impl fmt::Display for InstructionType {
209 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211 use InstructionType::*;
212
213 let type_upper = <&'static str>::from(self).to_ascii_uppercase();
215 write!(f, "{}", type_upper)?;
216
217 match self {
219 Im(val) => write!(f, " {}", val),
221 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"), Flag::S => write!(f, " M"), _ => write!(f, " {}", flag),
227 },
228 Condition::FlagNotSet(flag) => match flag {
229 Flag::PV => write!(f, " PO"), Flag::S => write!(f, " P"), _ => write!(f, " N{}", flag),
232 },
233 _ => Ok(()),
234 },
235 Rst(val) => write!(f, " 0x{:02x}", val),
237 _ => Ok(()),
238 }
239 }
240}
241
242#[derive(Clone, Copy, Debug, PartialEq)]
244#[repr(u8)]
245pub enum OpcodePrefix {
246 Bitwise, Extended, Indexed(RegisterPairType), IndexedBitwise(RegisterPairType), }
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 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#[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 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#[derive(Clone, Debug, PartialEq)]
306pub enum DecodingState {
307 RootOpcode,
309 RootOperand,
311 RootDisplacement,
313 ExtendedOpcode,
315 ExtendedOperand,
317 IndexedOpcode,
319 IndexedDisplacement,
321 IndexedOperand,
323 BitwiseOpcode,
325 IndexedBitwiseDisplacement,
327 IndexedBitwiseOpcode,
329}
330
331#[derive(Clone, Debug, PartialEq)]
333pub struct Instruction {
334 pub ignored_prefixes: Vec<OpcodePrefix>,
339 pub opcode: Opcode,
341 pub r#type: InstructionType,
343 pub source: Option<Operand>,
345 pub destination: Option<Operand>,
347}
348
349impl Instruction {
350 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 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 #[allow(clippy::cognitive_complexity)]
405 #[rustfmt::skip]
406 fn decode_one_inner<R: Read>(bytes: &mut Peekable<Bytes<R>>) -> Result<Self, DecodingState> {
407 fn next_byte<R: Read>(bytes: &mut Peekable<Bytes<R>>) -> Option<u8> {
410 bytes.next()?.ok()
411 }
412
413 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 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 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 macro_rules! next_doublet {
447 () => { next_doublet(bytes).ok_or(DecodingState::ExtendedOperand)? };
448 }
449
450 let instruction = match opcode {
451 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)), 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)), 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 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 0xA0 => extended!(Ldi),
517 0xA1 => extended!(Cpi),
518 0xA2 => extended!(Ini),
519 0xA3 => extended!(Outi),
520 0xA8 => extended!(Ldd),
522 0xA9 => extended!(Cpd),
523 0xAA => extended!(Ind),
524 0xAB => extended!(Outd),
525 0xB0 => extended!(Ldir),
527 0xB1 => extended!(Cpir),
528 0xB2 => extended!(Inir),
529 0xB3 => extended!(Otir),
530 0xB8 => extended!(Lddr),
532 0xB9 => extended!(Cpdr),
533 0xBA => extended!(Indr),
534 0xBB => extended!(Otdr),
535 _ => extended!(Inva),
537 };
538
539 Ok(instruction)
540 }
541
542 fn decode_bit_instruction<R: Read>(
545 bytes: &mut Peekable<Bytes<R>>,
546 index_register: Option<RegisterPairType>,
547 ) -> Result<Instruction, DecodingState> {
548 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 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 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 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 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 0x09 => indexed!(Add, RegisterPairImplied(BC), RegisterPairImplied(idx)),
689 0x19 => indexed!(Add, RegisterPairImplied(DE), RegisterPairImplied(idx)),
691 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 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 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 0x39 => indexed!(Add, RegisterPairImplied(SP), RegisterPairImplied(idx)),
711 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 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 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 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 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 0x77 => indexed!(Ld, RegisterImplied(A), MemoryIndexed(idx, next_displacement!())),
752 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 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 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 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 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 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 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 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 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 0xCB => decode_bit_instruction(bytes, Some(idx))?,
790 0xE1 => indexed!(Pop, destination: RegisterPairImplied(idx)),
792 0xE3 => indexed!(Ex, RegisterPairImplied(idx), MemoryIndirect(SP)),
794 0xE5 => indexed!(Push, source: RegisterPairImplied(idx)),
796 0xE9 => indexed!(Jp(None), source: RegisterPairImplied(idx)),
798 0xF9 => indexed!(Ld, RegisterPairImplied(idx), RegisterPairImplied(SP)),
800 _ => unreachable!(),
802 };
803
804 Ok(instruction)
805 }
806 }
807 }
808
809 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 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 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 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
1123impl 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 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 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 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 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 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 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}