yaxpeax_sm83/
lib.rs

1extern crate core;
2
3use core::fmt;
4
5use yaxpeax_arch::AddressDiff;
6use yaxpeax_arch::Arch;
7use yaxpeax_arch::Decoder;
8use yaxpeax_arch::LengthedInstruction;
9use yaxpeax_arch::Reader;
10use yaxpeax_arch::StandardDecodeError;
11
12#[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))]
13#[derive(Debug)]
14pub struct SM83;
15
16impl Arch for SM83 {
17    type Address = u16;
18    type Word = u8;
19    type Instruction = Instruction;
20    type DecodeError = StandardDecodeError;
21    type Decoder = InstDecoder;
22    type Operand = Operand;
23}
24
25#[derive(Debug, Copy, Clone)]
26pub struct Instruction {
27    opcode: Opcode,
28    operands: [Operand; 2],
29    length: u8,
30}
31
32impl Instruction {
33    pub fn opcode(&self) -> Opcode {
34        self.opcode
35    }
36
37    pub fn operands(&self) -> &[Operand; 2] {
38        &self.operands
39    }
40
41    pub fn length(&self) -> u8 {
42        self.length
43    }
44}
45
46impl Default for Instruction {
47    fn default() -> Instruction {
48        Instruction {
49            opcode: Opcode::NOP,
50            operands: [Operand::Nothing, Operand::Nothing],
51            length: 1,
52        }
53    }
54}
55
56impl fmt::Display for Instruction {
57    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58        write!(f, "{}", self.opcode())?;
59        let ops = self.operands();
60        if ops[0] != Operand::Nothing {
61            write!(f, " {}", ops[0])?;
62        }
63        if ops[1] != Operand::Nothing {
64            write!(f, ", {}", ops[1])?;
65        }
66        Ok(())
67    }
68}
69
70impl LengthedInstruction for Instruction {
71    type Unit = AddressDiff<<SM83 as Arch>::Address>;
72    fn min_size() -> Self::Unit {
73        AddressDiff::from_const(1)
74    }
75    fn len(&self) -> Self::Unit {
76        AddressDiff::from_const(self.length as u16)
77    }
78}
79
80impl yaxpeax_arch::Instruction for Instruction {
81    // only decode well-formed instructions (for now???)
82    fn well_defined(&self) -> bool { true }
83}
84
85#[derive(Debug, Copy, Clone, PartialEq, Eq)]
86pub enum Operand {
87    A,
88    B,
89    C,
90    D,
91    E,
92    H,
93    L,
94    AF,
95    BC,
96    DE,
97    HL,
98    SP,
99    DerefHL,
100    DerefBC,
101    DerefDE,
102    DerefDecHL,
103    DerefIncHL,
104    DerefHighC,
105    DerefHighD8(u8),
106    SPWithOffset(i8),
107    Bit(u8),
108    D8(u8),
109    I8(i8),
110    R8(i8),
111    A16(u16),
112    D16(u16),
113
114    CondC,
115    CondNC,
116    CondZ,
117    CondNZ,
118
119    Nothing,
120}
121
122impl fmt::Display for Operand {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        match self {
125            Operand::A => write!(f, "a"),
126            Operand::B => write!(f, "b"),
127            Operand::C => write!(f, "c"),
128            Operand::D => write!(f, "d"),
129            Operand::E => write!(f, "e"),
130            Operand::H => write!(f, "h"),
131            Operand::L => write!(f, "l"),
132            Operand::AF => write!(f, "af"),
133            Operand::BC => write!(f, "bc"),
134            Operand::DE => write!(f, "de"),
135            Operand::HL => write!(f, "hl"),
136            Operand::SP => write!(f, "sp"),
137            Operand::DerefHL => write!(f, "[hl]"),
138            Operand::DerefBC => write!(f, "[bc]"),
139            Operand::DerefDE => write!(f, "[de]"),
140            Operand::DerefDecHL => write!(f, "[hl-]"),
141            Operand::DerefIncHL => write!(f, "[hl+]"),
142            Operand::DerefHighC => write!(f, "[0xff00 + c]"),
143            Operand::DerefHighD8(imm) => write!(f, "[$ff00 + ${:02x}]", imm),
144            Operand::SPWithOffset(imm) => {
145                if *imm == -128 {
146                    write!(f, "[sp - $80]")
147                } else if *imm >= 0 {
148                    write!(f, "[sp + ${:02x}]", imm)
149                } else {
150                    write!(f, "[sp - ${:02x}]", -imm)
151                }
152            }
153            Operand::Bit(imm) => write!(f, "{}", imm),
154            Operand::D8(imm) => write!(f, "${:02x}", imm),
155            Operand::D16(imm) => write!(f, "${:04x}", imm),
156            Operand::I8(imm) => {
157                if *imm == -128 {
158                    write!(f, "-0x80")
159                } else if *imm >= 0 {
160                    write!(f, "${:02x}", imm)
161                } else {
162                    write!(f, "-${:02x}", -imm)
163                }
164            }
165            Operand::R8(imm) => {
166                if *imm == -128 {
167                    write!(f, "$-0x80")
168                } else if *imm >= 0 {
169                    write!(f, "$+${:02x}", imm)
170                } else {
171                    write!(f, "$-${:02x}", -imm)
172                }
173            }
174            Operand::A16(addr) => write!(f, "[${:4x}]", addr),
175
176            Operand::CondC => write!(f, "C"),
177            Operand::CondNC => write!(f, "nC"),
178            Operand::CondZ => write!(f, "Z"),
179            Operand::CondNZ => write!(f, "nZ"),
180
181            Operand::Nothing => write!(f, "nothing (BUG: should not be shown)"),
182        }
183    }
184}
185
186#[derive(Debug, Copy, Clone)]
187enum OperandSpec {
188    A,
189    B,
190    C,
191    D,
192    E,
193    H,
194    L,
195    AF,
196    BC,
197    DE,
198    HL,
199    SP,
200    DerefHL,
201    DerefBC,
202    DerefDE,
203    DerefDecHL,
204    DerefIncHL,
205    DerefHighC,
206    DerefHighD8,
207    SPWithOffset,
208    D8,
209    R8,
210    I8,
211    A16,
212    D16,
213
214    CondC,
215    CondNC,
216    CondZ,
217    CondNZ,
218
219    Bit(u8),
220    Imm(u8),
221
222    Nothing,
223}
224
225#[derive(Debug, Copy, Clone)]
226pub enum Opcode {
227    NOP,
228
229    LD,
230
231    DEC,
232    INC,
233
234    ADC,
235    ADD,
236    SBC,
237    SUB,
238
239    AND,
240    XOR,
241    OR,
242    CP,
243
244    POP,
245    PUSH,
246
247    JP,
248    JR,
249    CALL,
250    RET,
251    RETI,
252    HALT,
253    RST,
254    STOP,
255
256    RLCA,
257    RRCA,
258    RLA,
259    RRA,
260
261    DAA,
262    CPL,
263    SCF,
264    CCF,
265
266    DI,
267    EI,
268
269    LDH,
270
271    RLC,
272    RRC,
273    RL,
274    RR,
275    SLA,
276    SRA,
277    SWAP,
278    SRL,
279    BIT,
280    RES,
281    SET,
282}
283
284impl fmt::Display for Opcode {
285    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286        match self {
287            Opcode::NOP => write!(f, "nop"),
288
289            Opcode::LD => write!(f, "ld"),
290
291            Opcode::DEC => write!(f, "dec"),
292            Opcode::INC => write!(f, "inc"),
293
294            Opcode::ADC => write!(f, "adc"),
295            Opcode::ADD => write!(f, "add"),
296            Opcode::SBC => write!(f, "sbc"),
297            Opcode::SUB => write!(f, "sub"),
298
299            Opcode::AND => write!(f, "and"),
300            Opcode::XOR => write!(f, "xor"),
301            Opcode::OR => write!(f, "or"),
302            Opcode::CP => write!(f, "cp"),
303
304            Opcode::POP => write!(f, "pop"),
305            Opcode::PUSH => write!(f, "push"),
306
307            Opcode::JP => write!(f, "jp"),
308            Opcode::JR => write!(f, "jr"),
309            Opcode::CALL => write!(f, "call"),
310            Opcode::RET => write!(f, "ret"),
311            Opcode::RETI => write!(f, "reti"),
312            Opcode::HALT => write!(f, "halt"),
313            Opcode::RST => write!(f, "rst"),
314            Opcode::STOP => write!(f, "stop"),
315
316            Opcode::RLCA => write!(f, "rlca"),
317            Opcode::RRCA => write!(f, "rrca"),
318            Opcode::RLA => write!(f, "rla"),
319            Opcode::RRA => write!(f, "rra"),
320
321            Opcode::DAA => write!(f, "daa"),
322            Opcode::CPL => write!(f, "cpl"),
323            Opcode::SCF => write!(f, "scf"),
324            Opcode::CCF => write!(f, "ccf"),
325
326            Opcode::DI => write!(f, "di"),
327            Opcode::EI => write!(f, "ei"),
328
329            Opcode::LDH => write!(f, "ldh"),
330
331            Opcode::RLC => write!(f, "rlc"),
332            Opcode::RRC => write!(f, "rrc"),
333            Opcode::RL => write!(f, "rl"),
334            Opcode::RR => write!(f, "rr"),
335            Opcode::SLA => write!(f, "sla"),
336            Opcode::SRA => write!(f, "sra"),
337            Opcode::SWAP => write!(f, "swap"),
338            Opcode::SRL => write!(f, "srl"),
339            Opcode::BIT => write!(f, "bit"),
340            Opcode::RES => write!(f, "res"),
341            Opcode::SET => write!(f, "set"),
342        }
343    }
344}
345
346#[derive(Debug)]
347pub struct InstDecoder { }
348
349impl Default for InstDecoder {
350    fn default() -> Self {
351        InstDecoder { }
352    }
353}
354
355// main operand map is used for ld, arithmetic, and $CB-prefixed instructions
356const OPMAP: [OperandSpec; 8] = [
357    OperandSpec::B,
358    OperandSpec::C,
359    OperandSpec::D,
360    OperandSpec::E,
361    OperandSpec::H,
362    OperandSpec::L,
363    OperandSpec::DerefHL,
364    OperandSpec::A,
365];
366
367const UPPER_INSTRUCTIONS: [(Option<Opcode>, [OperandSpec; 2]); 64] = [
368    // 0xc0
369    (Some(Opcode::RET), [OperandSpec::CondNZ, OperandSpec::Nothing]),
370    (Some(Opcode::POP), [OperandSpec::BC, OperandSpec::Nothing]),
371    (Some(Opcode::JP), [OperandSpec::CondNZ, OperandSpec::D16]),
372    (Some(Opcode::JP), [OperandSpec::D16, OperandSpec::Nothing]),
373    (Some(Opcode::CALL), [OperandSpec::CondNZ, OperandSpec::D16]),
374    (Some(Opcode::PUSH), [OperandSpec::BC, OperandSpec::Nothing]),
375    (Some(Opcode::ADD), [OperandSpec::D8, OperandSpec::Nothing]),
376    (Some(Opcode::RST), [OperandSpec::Imm(0x00), OperandSpec::Nothing]),
377    // 0xc8
378    (Some(Opcode::RET), [OperandSpec::CondZ, OperandSpec::Nothing]),
379    (Some(Opcode::RET), [OperandSpec::Nothing, OperandSpec::Nothing]),
380    (Some(Opcode::JP), [OperandSpec::CondNC, OperandSpec::D16]),
381    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
382    (Some(Opcode::CALL), [OperandSpec::CondZ, OperandSpec::D16]),
383    (Some(Opcode::CALL), [OperandSpec::D16, OperandSpec::Nothing]),
384    (Some(Opcode::ADC), [OperandSpec::D8, OperandSpec::Nothing]),
385    (Some(Opcode::RST), [OperandSpec::Imm(0x08), OperandSpec::Nothing]),
386    // 0xd0
387    (Some(Opcode::RET), [OperandSpec::CondNC, OperandSpec::Nothing]),
388    (Some(Opcode::POP), [OperandSpec::DE, OperandSpec::Nothing]),
389    (Some(Opcode::JP), [OperandSpec::CondNC, OperandSpec::D16]),
390    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
391    (Some(Opcode::CALL), [OperandSpec::CondNC, OperandSpec::D16]),
392    (Some(Opcode::PUSH), [OperandSpec::DE, OperandSpec::Nothing]),
393    (Some(Opcode::SUB), [OperandSpec::D8, OperandSpec::Nothing]),
394    (Some(Opcode::RST), [OperandSpec::Imm(0x10), OperandSpec::Nothing]),
395    // 0xd8
396    (Some(Opcode::RET), [OperandSpec::CondC, OperandSpec::Nothing]),
397    (Some(Opcode::RETI), [OperandSpec::Nothing, OperandSpec::Nothing]),
398    (Some(Opcode::JP), [OperandSpec::CondC, OperandSpec::D16]),
399    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
400    (Some(Opcode::CALL), [OperandSpec::CondC, OperandSpec::D16]),
401    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
402    (Some(Opcode::SBC), [OperandSpec::D8, OperandSpec::Nothing]),
403    (Some(Opcode::RST), [OperandSpec::Imm(0x18), OperandSpec::Nothing]),
404    // 0xe0
405    (Some(Opcode::LDH), [OperandSpec::DerefHighD8, OperandSpec::A]),
406    (Some(Opcode::POP), [OperandSpec::HL, OperandSpec::Nothing]),
407    (Some(Opcode::LDH), [OperandSpec::DerefHighC, OperandSpec::A]),
408    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
409    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
410    (Some(Opcode::PUSH), [OperandSpec::HL, OperandSpec::Nothing]),
411    (Some(Opcode::AND), [OperandSpec::D8, OperandSpec::Nothing]),
412    (Some(Opcode::RST), [OperandSpec::Imm(0x20), OperandSpec::Nothing]),
413    // 0xe8
414    (Some(Opcode::ADD), [OperandSpec::SP, OperandSpec::I8]),
415    (Some(Opcode::JP), [OperandSpec::HL, OperandSpec::Nothing]),
416    (Some(Opcode::LD), [OperandSpec::A16, OperandSpec::A]),
417    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
418    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
419    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
420    (Some(Opcode::XOR), [OperandSpec::D8, OperandSpec::Nothing]),
421    (Some(Opcode::RST), [OperandSpec::Imm(0x28), OperandSpec::Nothing]),
422    // 0xf0
423    (Some(Opcode::LDH), [OperandSpec::A, OperandSpec::DerefHighD8]),
424    (Some(Opcode::POP), [OperandSpec::AF, OperandSpec::Nothing]),
425    (Some(Opcode::LDH), [OperandSpec::A, OperandSpec::DerefHighC]),
426    (Some(Opcode::DI), [OperandSpec::Nothing, OperandSpec::Nothing]),
427    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
428    (Some(Opcode::PUSH), [OperandSpec::AF, OperandSpec::Nothing]),
429    (Some(Opcode::OR), [OperandSpec::D8, OperandSpec::Nothing]),
430    (Some(Opcode::RST), [OperandSpec::Imm(0x30), OperandSpec::Nothing]),
431    // 0xf8
432    (Some(Opcode::LD), [OperandSpec::HL, OperandSpec::SPWithOffset]),
433    (Some(Opcode::LD), [OperandSpec::SP, OperandSpec::HL]),
434    (Some(Opcode::LD), [OperandSpec::A, OperandSpec::A16]),
435    (Some(Opcode::EI), [OperandSpec::Nothing, OperandSpec::Nothing]),
436    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
437    (None, [OperandSpec::Nothing, OperandSpec::Nothing]),
438    (Some(Opcode::CP), [OperandSpec::D8, OperandSpec::Nothing]),
439    (Some(Opcode::RST), [OperandSpec::Imm(0x38), OperandSpec::Nothing]),
440];
441
442impl Decoder<SM83> for InstDecoder {
443    fn decode_into<T: Reader<<SM83 as Arch>::Address, <SM83 as Arch>::Word>>(&self, inst: &mut Instruction, words: &mut T) -> Result<(), <SM83 as Arch>::DecodeError> {
444        let opc: u8 = words.next()?;
445        inst.length = 1;
446
447        let high = ((opc >> 3) & 0b111) as usize;
448        let low = (opc & 0b111) as usize;
449
450        // early part of the table is more varied, more special cases
451        if opc < 0x40 {
452            let (opcode, operands) = match low {
453                0 => {
454                    // special case on high
455                    match high {
456                        0 => { (Opcode::NOP, [OperandSpec::Nothing, OperandSpec::Nothing]) },
457                        1 => { (Opcode::LD, [OperandSpec::A16, OperandSpec::SP]) },
458                        2 => { (Opcode::STOP, [OperandSpec::Nothing, OperandSpec::Nothing]) },
459                        3 => { (Opcode::JR, [OperandSpec::R8, OperandSpec::Nothing]) },
460                        4 => { (Opcode::JR, [OperandSpec::CondNZ, OperandSpec::R8]) },
461                        5 => { (Opcode::JR, [OperandSpec::CondZ, OperandSpec::R8]) },
462                        6 => { (Opcode::JR, [OperandSpec::CondNC, OperandSpec::R8]) },
463                        7 => { (Opcode::JR, [OperandSpec::CondC, OperandSpec::R8]) },
464                        _ => { unreachable!("impossible bit pattern"); }
465                    }
466                }
467                1 => {
468                    // also special case, but fewer
469                    if high & 1 == 0 {
470                        let opcode = Opcode::LD;
471                        let ops = [[
472                            OperandSpec::BC,
473                            OperandSpec::DE,
474                            OperandSpec::HL,
475                            OperandSpec::SP,
476                        ][high as usize >> 1], OperandSpec::D16];
477                        (opcode, ops)
478                    } else {
479                        let opcode = Opcode::ADD;
480                        let ops = [OperandSpec::HL, [
481                            OperandSpec::BC,
482                            OperandSpec::DE,
483                            OperandSpec::HL,
484                            OperandSpec::SP,
485                        ][high as usize >> 1]];
486                        (opcode, ops)
487                    }
488                }
489                2 => {
490                    let op = Opcode::LD;
491                    if high & 1 == 0 {
492                        let op0 = [
493                            OperandSpec::DerefBC,
494                            OperandSpec::DerefDE,
495                            OperandSpec::DerefIncHL,
496                            OperandSpec::DerefDecHL,
497                        ][high as usize >> 1];
498                        (op, [op0, OperandSpec::A])
499                    } else {
500                        let op1 = [
501                            OperandSpec::DerefBC,
502                            OperandSpec::DerefDE,
503                            OperandSpec::DerefIncHL,
504                            OperandSpec::DerefDecHL,
505                        ][high as usize >> 1];
506                        (op, [OperandSpec::A, op1])
507                    }
508                }
509                3 => {
510                    if high & 1 == 0 {
511                        let op0 = [
512                            OperandSpec::BC,
513                            OperandSpec::DE,
514                            OperandSpec::HL,
515                            OperandSpec::SP,
516                        ][high as usize >> 1];
517                        (Opcode::INC, [op0, OperandSpec::Nothing])
518                    } else {
519                        let op0 = [
520                            OperandSpec::BC,
521                            OperandSpec::DE,
522                            OperandSpec::HL,
523                            OperandSpec::SP,
524                        ][high as usize >> 1];
525                        (Opcode::DEC, [op0, OperandSpec::Nothing])
526                    }
527                }
528                4 => {
529                    let op = Opcode::INC;
530                    let op0 = [
531                        OperandSpec::B,
532                        OperandSpec::C,
533                        OperandSpec::D,
534                        OperandSpec::E,
535                        OperandSpec::H,
536                        OperandSpec::L,
537                        OperandSpec::DerefHL,
538                        OperandSpec::A,
539                    ][high as usize];
540                    (op, [op0, OperandSpec::Nothing])
541                }
542                5 => {
543                    let op = Opcode::DEC;
544                    let op0 = [
545                        OperandSpec::B,
546                        OperandSpec::C,
547                        OperandSpec::D,
548                        OperandSpec::E,
549                        OperandSpec::H,
550                        OperandSpec::L,
551                        OperandSpec::DerefHL,
552                        OperandSpec::A,
553                    ][high as usize];
554                    (op, [op0, OperandSpec::Nothing])
555                }
556                6 => {
557                    let op = Opcode::LD;
558                    let op0 = [
559                        OperandSpec::B,
560                        OperandSpec::C,
561                        OperandSpec::D,
562                        OperandSpec::E,
563                        OperandSpec::H,
564                        OperandSpec::L,
565                        OperandSpec::DerefHL,
566                        OperandSpec::A,
567                    ][high as usize];
568                    (op, [op0, OperandSpec::D8])
569                }
570                7 => {
571                    // special cases here too
572                    let op = [
573                        Opcode::RLCA,
574                        Opcode::RRCA,
575                        Opcode::RLA,
576                        Opcode::RRA,
577                        Opcode::DAA,
578                        Opcode::CPL,
579                        Opcode::SCF,
580                        Opcode::CCF,
581                    ][high as usize];
582                    (op, [OperandSpec::Nothing, OperandSpec::Nothing])
583                }
584                _ => {
585                    unreachable!("impossible bit pattern");
586                }
587            };
588            inst.opcode = opcode;
589            interpret_operands(words, inst, operands)?;
590            return Ok(());
591        } else if opc < 0x80 {
592            if opc == 0x76 {
593                inst.opcode = Opcode::HALT;
594                inst.operands = [Operand::Nothing, Operand::Nothing];
595                return Ok(());
596            } else {
597                inst.opcode = Opcode::LD;
598                interpret_operands(words, inst, [OPMAP[high], OPMAP[low]])?;
599                return Ok(());
600            }
601        } else if opc < 0xc0 {
602            const OPCODES: [Opcode; 8] = [
603                Opcode::ADD,
604                Opcode::ADC,
605                Opcode::SUB,
606                Opcode::SBC,
607                Opcode::AND,
608                Opcode::XOR,
609                Opcode::OR,
610                Opcode::CP,
611            ];
612            inst.opcode = OPCODES[high];
613            let operands = [OPMAP[low], OperandSpec::Nothing];
614            interpret_operands(words, inst, operands)?;
615            return Ok(());
616        } else {
617            if opc == 0xcb {
618                // sm83 special CB-prefixed instructions
619                let opc: u8 = words.next()?;
620                inst.length += 1;
621                if opc < 0x40 {
622                    let high = (opc >> 3) & 0b111;
623                    let low = opc & 0b111;
624                    const LOW_OP: [OperandSpec; 8] = [
625                        OperandSpec::B,
626                        OperandSpec::C,
627                        OperandSpec::D,
628                        OperandSpec::E,
629                        OperandSpec::H,
630                        OperandSpec::L,
631                        OperandSpec::DerefHL,
632                        OperandSpec::A,
633                    ];
634                    let operands = [LOW_OP[low as usize], OperandSpec::Nothing];
635                    const OPCODES: [Opcode; 8] = [
636                        Opcode::RLC,
637                        Opcode::RRC,
638                        Opcode::RL,
639                        Opcode::RR,
640                        Opcode::SLA,
641                        Opcode::SRA,
642                        Opcode::SWAP,
643                        Opcode::SRL,
644                    ];
645                    inst.opcode = OPCODES[high as usize];
646                    interpret_operands(words, inst, operands)?;
647                    return Ok(());
648                } else {
649                    let bit = (opc >> 3) & 0b111;
650                    let low = opc & 0b111;
651                    const LOW_OP: [OperandSpec; 8] = [
652                        OperandSpec::B,
653                        OperandSpec::C,
654                        OperandSpec::D,
655                        OperandSpec::E,
656                        OperandSpec::H,
657                        OperandSpec::L,
658                        OperandSpec::DerefHL,
659                        OperandSpec::A,
660                    ];
661                    let operands = [OperandSpec::Bit(bit), LOW_OP[low as usize]];
662                    const OPCODES: [Opcode; 3] = [
663                        Opcode::BIT,
664                        Opcode::RES,
665                        Opcode::SET,
666                    ];
667                    inst.opcode = OPCODES[(opc >> 6) as usize - 1];
668                    interpret_operands(words, inst, operands)?;
669                    return Ok(());
670                }
671            } else {
672                // there is no special thing we can do here. do a table lookup.
673                let (maybe_opcode, operands) = UPPER_INSTRUCTIONS[opc as usize - 0xc0];
674                if let Some(opcode) = maybe_opcode {
675                    inst.opcode = opcode;
676                    interpret_operands(words, inst, operands)?;
677                    return Ok(());
678                } else {
679                    return Err(StandardDecodeError::InvalidOpcode);
680                }
681            }
682        }
683    }
684}
685
686fn interpret_operands<T: Reader<<SM83 as Arch>::Address, <SM83 as Arch>::Word>>(words: &mut T, inst: &mut Instruction, operands: [OperandSpec; 2]) -> Result<(), <SM83 as Arch>::DecodeError> {
687    inst.operands[0] = interpret_operand(words, inst, operands[0])?;
688    inst.operands[1] = interpret_operand(words, inst, operands[1])?;
689    Ok(())
690}
691
692fn interpret_operand<T: Reader<<SM83 as Arch>::Address, <SM83 as Arch>::Word>>(words: &mut T, inst: &mut Instruction, operand: OperandSpec) -> Result<Operand, <SM83 as Arch>::DecodeError> {
693    let operand = match operand {
694        OperandSpec::A => Operand::A,
695        OperandSpec::B => Operand::B,
696        OperandSpec::C => Operand::C,
697        OperandSpec::D => Operand::D,
698        OperandSpec::E => Operand::E,
699        OperandSpec::H => Operand::H,
700        OperandSpec::L => Operand::L,
701        OperandSpec::AF => Operand::AF,
702        OperandSpec::BC => Operand::BC,
703        OperandSpec::DE => Operand::DE,
704        OperandSpec::HL => Operand::HL,
705        OperandSpec::SP => Operand::SP,
706        OperandSpec::DerefHL => Operand::DerefHL,
707        OperandSpec::DerefBC => Operand::DerefBC,
708        OperandSpec::DerefDE => Operand::DerefDE,
709        OperandSpec::DerefDecHL => Operand::DerefDecHL,
710        OperandSpec::DerefIncHL => Operand::DerefIncHL,
711        OperandSpec::D8 => {
712            let imm = words.next()?;
713            inst.length += 1;
714            Operand::D8(imm)
715        }
716        OperandSpec::DerefHighC => {
717            Operand::DerefHighC
718        }
719        OperandSpec::DerefHighD8 => {
720            let imm = words.next()?;
721            inst.length += 1;
722            Operand::DerefHighD8(imm)
723        }
724        OperandSpec::R8 => {
725            let imm = words.next()?;
726            inst.length += 1;
727            Operand::R8(imm as i8)
728        }
729        OperandSpec::I8 => {
730            let imm = words.next()?;
731            inst.length += 1;
732            Operand::I8(imm as i8)
733        }
734        OperandSpec::A16 => {
735            let imm =
736                 (words.next()? as u16) |
737                ((words.next()? as u16) << 8);
738            inst.length += 2;
739            Operand::A16(imm as u16)
740        }
741        OperandSpec::D16 => {
742            let imm =
743                 (words.next()? as u16) |
744                ((words.next()? as u16) << 8);
745            inst.length += 2;
746            Operand::D16(imm as u16)
747        }
748        OperandSpec::SPWithOffset => {
749            let imm = words.next()?;
750            inst.length += 1;
751            Operand::SPWithOffset(imm as i8)
752        }
753
754        OperandSpec::Imm(u) => {
755            Operand::D8(u)
756        }
757        OperandSpec::Bit(u) => {
758            Operand::Bit(u)
759        }
760
761        OperandSpec::CondC => Operand::CondC,
762        OperandSpec::CondNC => Operand::CondNC,
763        OperandSpec::CondZ => Operand::CondZ,
764        OperandSpec::CondNZ => Operand::CondNZ,
765
766        OperandSpec::Nothing => Operand::Nothing,
767    };
768    Ok(operand)
769}