1use crate::address;
7use crate::registers;
8
9use alloc::vec::Vec;
10use core::convert::From;
11use core::hash::Hash;
12use derive_more::{From, Into};
13
14#[derive(Debug, PartialEq, Eq)]
15pub struct ParseError(u8);
17
18#[derive(PartialEq, Eq, Debug, Copy, Clone)]
22pub struct OpcodePosition {
23    pub mask: u8,
25    pub shift: u8,
27}
28
29pub trait EmbeddableParam: Sized {
31    fn extract(value: u8) -> Result<Self, ParseError>;
33    fn embed(&self) -> u8;
35
36    fn extract_from_opcode(opcode: u8, pos: OpcodePosition) -> Result<Self, ParseError> {
38        <Self as EmbeddableParam>::extract((opcode & pos.mask) >> pos.shift)
39    }
40
41    fn embed_to_opcode(&self, opcode: u8, pos: OpcodePosition) -> u8 {
43        let rest_of_opcode = opcode & !pos.mask;
44        let embed_value = self.embed() << pos.shift;
45        rest_of_opcode | embed_value
46    }
47}
48
49impl EmbeddableParam for u8 {
50    fn extract(value: u8) -> Result<u8, ParseError> {
51        Ok(value)
52    }
53
54    fn embed(&self) -> u8 {
55        *self
56    }
57}
58
59pub trait AppendableParam {
60    fn as_bytes(&self) -> Vec<u8>;
61}
62
63impl AppendableParam for u8 {
64    fn as_bytes(&self) -> Vec<u8> {
65        self.to_le_bytes().iter().copied().collect()
66    }
67}
68
69impl AppendableParam for u16 {
70    fn as_bytes(&self) -> Vec<u8> {
71        self.to_le_bytes().iter().copied().collect()
72    }
73}
74
75impl AppendableParam for i8 {
76    fn as_bytes(&self) -> Vec<u8> {
77        self.to_le_bytes().iter().copied().collect()
78    }
79}
80
81impl AppendableParam for address::LiteralAddress {
82    fn as_bytes(&self) -> Vec<u8> {
83        u16::from(*self).as_bytes()
84    }
85}
86
87impl AppendableParam for address::AddressOffset {
88    fn as_bytes(&self) -> Vec<u8> {
89        u8::from(*self).as_bytes()
90    }
91}
92
93impl AppendableParam for address::HighAddress {
94    fn as_bytes(&self) -> Vec<u8> {
95        u8::from(*self).as_bytes()
96    }
97}
98
99#[derive(PartialEq, Eq, Debug, Copy, Clone)]
100pub enum Condition {
102    NonZero,
104    Zero,
106    NoCarry,
108    Carry,
110}
111
112impl EmbeddableParam for Condition {
113    fn extract(value: u8) -> Result<Condition, ParseError> {
114        match value {
115            0b00 => Ok(Condition::NonZero),
116            0b01 => Ok(Condition::Zero),
117            0b10 => Ok(Condition::NoCarry),
118            0b11 => Ok(Condition::Carry),
119            _ => Err(ParseError(value)),
120        }
121    }
122
123    fn embed(&self) -> u8 {
124        match self {
125            Condition::NonZero => 0b00,
126            Condition::Zero => 0b01,
127            Condition::NoCarry => 0b10,
128            Condition::Carry => 0b11,
129        }
130    }
131}
132
133#[derive(PartialEq, Eq, Debug, Copy, Clone)]
134pub enum Carry {
138    Carry,
139    NoCarry,
140}
141
142impl EmbeddableParam for Carry {
143    fn extract(value: u8) -> Result<Carry, ParseError> {
144        match value {
145            0 => Ok(Carry::Carry),
146            1 => Ok(Carry::NoCarry),
147            _ => Err(ParseError(value)),
148        }
149    }
150
151    fn embed(&self) -> u8 {
152        match self {
153            Carry::Carry => 0,
154            Carry::NoCarry => 1,
155        }
156    }
157}
158
159#[derive(PartialEq, Eq, Debug, Copy, Clone)]
160pub enum RotateDirection {
162    Left,
163    Right,
164}
165
166impl EmbeddableParam for RotateDirection {
167    fn extract(value: u8) -> Result<RotateDirection, ParseError> {
168        match value {
169            0 => Ok(RotateDirection::Left),
170            1 => Ok(RotateDirection::Right),
171            _ => Err(ParseError(value)),
172        }
173    }
174
175    fn embed(&self) -> u8 {
176        match self {
177            RotateDirection::Left => 0,
178            RotateDirection::Right => 1,
179        }
180    }
181}
182
183#[derive(PartialEq, Eq, Debug, Copy, Clone)]
184pub enum Increment {
187    Increment,
188    Decrement,
189}
190
191impl EmbeddableParam for Increment {
192    fn extract(value: u8) -> Result<Increment, ParseError> {
193        match value {
194            0 => Ok(Increment::Increment),
195            1 => Ok(Increment::Decrement),
196            _ => Err(ParseError(value)),
197        }
198    }
199
200    fn embed(&self) -> u8 {
201        match self {
202            Increment::Increment => 0,
203            Increment::Decrement => 1,
204        }
205    }
206}
207
208#[derive(PartialEq, Eq, Debug, Copy, Clone)]
209pub enum ALOp {
211    Add,
212    AddCarry,
213    Sub,
214    SubCarry,
215    And,
216    Xor,
217    Or,
218    Compare,
219}
220
221impl EmbeddableParam for ALOp {
222    fn extract(value: u8) -> Result<ALOp, ParseError> {
223        match value {
224            0b000 => Ok(ALOp::Add),
225            0b001 => Ok(ALOp::AddCarry),
226            0b010 => Ok(ALOp::Sub),
227            0b011 => Ok(ALOp::SubCarry),
228            0b100 => Ok(ALOp::And),
229            0b101 => Ok(ALOp::Xor),
230            0b110 => Ok(ALOp::Or),
231            0b111 => Ok(ALOp::Compare),
232            _ => Err(ParseError(value)),
233        }
234    }
235
236    fn embed(&self) -> u8 {
237        match self {
238            ALOp::Add => 0b000,
239            ALOp::AddCarry => 0b001,
240            ALOp::Sub => 0b010,
241            ALOp::SubCarry => 0b011,
242            ALOp::And => 0b100,
243            ALOp::Xor => 0b101,
244            ALOp::Or => 0b110,
245            ALOp::Compare => 0b111,
246        }
247    }
248}
249
250#[derive(PartialEq, Eq, Debug, Copy, Clone)]
254pub enum ByteRegisterTarget {
255    A,
256    B,
257    C,
258    D,
259    E,
260    H,
261    L,
262    HLIndirect,
263}
264
265impl EmbeddableParam for ByteRegisterTarget {
266    fn extract(value: u8) -> Result<ByteRegisterTarget, ParseError> {
267        match value {
268            0b000 => Ok(ByteRegisterTarget::B),
269            0b001 => Ok(ByteRegisterTarget::C),
270            0b010 => Ok(ByteRegisterTarget::D),
271            0b011 => Ok(ByteRegisterTarget::E),
272            0b100 => Ok(ByteRegisterTarget::H),
273            0b101 => Ok(ByteRegisterTarget::L),
274            0b110 => Ok(ByteRegisterTarget::HLIndirect),
275            0b111 => Ok(ByteRegisterTarget::A),
276            _ => Err(ParseError(value)),
277        }
278    }
279
280    fn embed(&self) -> u8 {
281        match self {
282            ByteRegisterTarget::B => 0b000,
283            ByteRegisterTarget::C => 0b001,
284            ByteRegisterTarget::D => 0b010,
285            ByteRegisterTarget::E => 0b011,
286            ByteRegisterTarget::H => 0b100,
287            ByteRegisterTarget::L => 0b101,
288            ByteRegisterTarget::HLIndirect => 0b110,
289            ByteRegisterTarget::A => 0b111,
290        }
291    }
292}
293
294#[derive(Debug, PartialEq, Eq, Copy, Clone)]
295pub enum AccRegister {
303    BC,
304    DE,
305    HL,
306    AF,
307}
308
309impl EmbeddableParam for AccRegister {
310    fn extract(value: u8) -> Result<AccRegister, ParseError> {
311        match value {
312            0b00 => Ok(AccRegister::BC),
313            0b01 => Ok(AccRegister::DE),
314            0b10 => Ok(AccRegister::HL),
315            0b11 => Ok(AccRegister::AF),
316            _ => Err(ParseError(value)),
317        }
318    }
319
320    fn embed(&self) -> u8 {
321        match self {
322            AccRegister::BC => 0b00,
323            AccRegister::DE => 0b01,
324            AccRegister::HL => 0b10,
325            AccRegister::AF => 0b11,
326        }
327    }
328}
329
330#[derive(Debug, PartialEq, Eq, Copy, Clone)]
331pub enum StackRegister {
338    BC,
339    DE,
340    HL,
341    SP,
342}
343
344impl EmbeddableParam for StackRegister {
345    fn extract(value: u8) -> Result<StackRegister, ParseError> {
346        match value {
347            0b00 => Ok(StackRegister::BC),
348            0b01 => Ok(StackRegister::DE),
349            0b10 => Ok(StackRegister::HL),
350            0b11 => Ok(StackRegister::SP),
351            _ => Err(ParseError(value)),
352        }
353    }
354
355    fn embed(&self) -> u8 {
356        match self {
357            StackRegister::BC => 0b00,
358            StackRegister::DE => 0b01,
359            StackRegister::HL => 0b10,
360            StackRegister::SP => 0b11,
361        }
362    }
363}
364
365#[derive(PartialEq, Eq, Debug, Copy, Clone)]
368pub enum InnerParam {
369    ALOp,
370    Increment,
371    RotateDirection,
372    Carry,
373    Condition,
374    ByteRegisterTarget,
375    AccRegister,
376    StackRegister,
377    Literal8,
378}
379
380#[derive(PartialEq, Eq, Debug, Copy, Clone)]
383pub enum AppendedParam {
384    LiteralAddress,
385    HighAddress,
386    AddressOffset,
387    Literal16,
388    Literal8,
389    LiteralSigned8,
390}
391
392#[derive(PartialEq, Eq, Debug, Copy, Clone, From, Into)]
393pub struct ByteRegisterOffset(pub(crate) registers::ByteRegister);
394
395#[derive(PartialEq, Eq, Debug, Copy, Clone)]
396pub enum ConstantParam {
398    ByteRegister(registers::ByteRegister),
399    WordRegister(registers::WordRegister),
400    ByteRegisterOffset(registers::ByteRegister),
401    LiteralAddress(address::LiteralAddress),
402}
403
404#[derive(PartialEq, Eq, Debug, Copy, Clone)]
416pub enum ParamType {
417    Appended(AppendedParam),
418    Inner { pos: OpcodePosition, ty: InnerParam },
419    Constant(ConstantParam),
420}
421
422#[derive(PartialEq, Eq, Debug, Copy, Clone)]
429pub enum ExtensionType {
430    None,
431    Extended,
432}
433
434#[derive(PartialEq, Hash, Eq, Debug, Copy, Clone)]
435pub enum ParamPosition {
437    Dest,
438    Src,
439    Single,
440    AddSrc,
441}
442
443#[derive(PartialEq, Eq, Debug, Copy, Clone)]
444pub struct ParamDefinition {
446    pub param_type: ParamType,
447    pub pos: ParamPosition,
448}
449
450#[derive(PartialEq, Eq, Debug, Clone)]
451pub struct InstructionDefinition {
452    pub opcodes: &'static [u8],
453    pub label: &'static str,
454    pub extension_type: ExtensionType,
455    pub params: &'static [ParamDefinition],
456}
457
458pub trait InstructionOpcode {
462    type FullInstruction: Instruction;
463    fn definition() -> &'static InstructionDefinition
464    where
465        Self: Sized;
466    fn from_opcode(opcode: u8) -> Self
467    where
468        Self: Sized;
469    fn build_instruction(&self, data: &mut dyn Iterator<Item = u8>) -> Self::FullInstruction;
470}
471
472pub trait Instruction {
473    fn definition() -> &'static InstructionDefinition
474    where
475        Self: Sized;
476    fn numeric_opcode(&self) -> u8;
477    fn trailing_bytes(&self) -> Vec<u8>;
478}
479
480pub trait SerializableInstruction {
481    fn as_bytes(&self) -> Vec<u8>;
482}
483
484impl<T: Instruction> SerializableInstruction for T {
485    fn as_bytes(&self) -> Vec<u8> {
486        let mut bytes = Vec::new();
487        if T::definition().extension_type == ExtensionType::Extended {
488            bytes.push(0xCB);
489        }
490        bytes.push(self.numeric_opcode());
491        bytes.extend(self.trailing_bytes());
492        bytes
493    }
494}
495
496#[cfg(test)]
497mod test {
498    use super::*;
499    use alloc::vec;
500
501    #[test]
502    fn embed_u8() {
503        assert_eq!(EmbeddableParam::embed(&0x23), 0x23);
504    }
505
506    #[test]
507    fn extract_condition() {
508        assert_eq!(Condition::extract(0), Ok(Condition::NonZero));
509        assert_eq!(Condition::extract(1), Ok(Condition::Zero));
510        assert_eq!(Condition::extract(2), Ok(Condition::NoCarry));
511        assert_eq!(Condition::extract(3), Ok(Condition::Carry));
512        assert_eq!(Condition::extract(4), Err(ParseError(4)));
513    }
514
515    #[test]
516    fn embed_condition() {
517        assert_eq!(Condition::NonZero.embed(), 0);
518        assert_eq!(Condition::Zero.embed(), 1);
519        assert_eq!(Condition::NoCarry.embed(), 2);
520        assert_eq!(Condition::Carry.embed(), 3);
521    }
522
523    #[test]
524    fn extract_carry() {
525        assert_eq!(Carry::extract(0), Ok(Carry::Carry));
526        assert_eq!(Carry::extract(1), Ok(Carry::NoCarry));
527        assert_eq!(Carry::extract(4), Err(ParseError(4)));
528    }
529
530    #[test]
531    fn embed_carry() {
532        assert_eq!(Carry::Carry.embed(), 0);
533        assert_eq!(Carry::NoCarry.embed(), 1);
534    }
535
536    #[test]
537    fn extract_rotate_direction() {
538        assert_eq!(RotateDirection::extract(0), Ok(RotateDirection::Left));
539        assert_eq!(RotateDirection::extract(1), Ok(RotateDirection::Right));
540        assert_eq!(RotateDirection::extract(4), Err(ParseError(4)));
541    }
542
543    #[test]
544    fn embed_rotate_direction() {
545        assert_eq!(RotateDirection::Left.embed(), 0);
546        assert_eq!(RotateDirection::Right.embed(), 1);
547    }
548
549    #[test]
550    fn extract_increment() {
551        assert_eq!(Increment::extract(0), Ok(Increment::Increment));
552        assert_eq!(Increment::extract(1), Ok(Increment::Decrement));
553        assert_eq!(Increment::extract(4), Err(ParseError(4)));
554    }
555
556    #[test]
557    fn embed_increment() {
558        assert_eq!(Increment::Increment.embed(), 0);
559        assert_eq!(Increment::Decrement.embed(), 1);
560    }
561
562    #[test]
563    fn extract_alop() {
564        assert_eq!(ALOp::extract(0), Ok(ALOp::Add));
565        assert_eq!(ALOp::extract(1), Ok(ALOp::AddCarry));
566        assert_eq!(ALOp::extract(2), Ok(ALOp::Sub));
567        assert_eq!(ALOp::extract(3), Ok(ALOp::SubCarry));
568        assert_eq!(ALOp::extract(4), Ok(ALOp::And));
569        assert_eq!(ALOp::extract(5), Ok(ALOp::Xor));
570        assert_eq!(ALOp::extract(6), Ok(ALOp::Or));
571        assert_eq!(ALOp::extract(7), Ok(ALOp::Compare));
572        assert_eq!(ALOp::extract(9), Err(ParseError(9)));
573    }
574
575    #[test]
576    fn embed_alop() {
577        assert_eq!(ALOp::Add.embed(), 0);
578        assert_eq!(ALOp::AddCarry.embed(), 1);
579        assert_eq!(ALOp::Sub.embed(), 2);
580        assert_eq!(ALOp::SubCarry.embed(), 3);
581        assert_eq!(ALOp::And.embed(), 4);
582        assert_eq!(ALOp::Xor.embed(), 5);
583        assert_eq!(ALOp::Or.embed(), 6);
584        assert_eq!(ALOp::Compare.embed(), 7);
585    }
586
587    #[test]
588    fn extract_byte_register_lookup() {
589        assert_eq!(ByteRegisterTarget::extract(0), Ok(ByteRegisterTarget::B));
590        assert_eq!(ByteRegisterTarget::extract(1), Ok(ByteRegisterTarget::C));
591        assert_eq!(ByteRegisterTarget::extract(2), Ok(ByteRegisterTarget::D));
592        assert_eq!(ByteRegisterTarget::extract(3), Ok(ByteRegisterTarget::E));
593        assert_eq!(ByteRegisterTarget::extract(4), Ok(ByteRegisterTarget::H));
594        assert_eq!(ByteRegisterTarget::extract(5), Ok(ByteRegisterTarget::L));
595        assert_eq!(
596            ByteRegisterTarget::extract(6),
597            Ok(ByteRegisterTarget::HLIndirect)
598        );
599        assert_eq!(ByteRegisterTarget::extract(7), Ok(ByteRegisterTarget::A));
600        assert_eq!(ByteRegisterTarget::extract(9), Err(ParseError(9)));
601    }
602
603    #[test]
604    fn embed_byte_register_lookup() {
605        assert_eq!(ByteRegisterTarget::B.embed(), 0);
606        assert_eq!(ByteRegisterTarget::C.embed(), 1);
607        assert_eq!(ByteRegisterTarget::D.embed(), 2);
608        assert_eq!(ByteRegisterTarget::E.embed(), 3);
609        assert_eq!(ByteRegisterTarget::H.embed(), 4);
610        assert_eq!(ByteRegisterTarget::L.embed(), 5);
611        assert_eq!(ByteRegisterTarget::HLIndirect.embed(), 6);
612        assert_eq!(ByteRegisterTarget::A.embed(), 7);
613    }
614
615    #[test]
616    fn extract_acc_register() {
617        assert_eq!(AccRegister::extract(0), Ok(AccRegister::BC));
618        assert_eq!(AccRegister::extract(1), Ok(AccRegister::DE));
619        assert_eq!(AccRegister::extract(2), Ok(AccRegister::HL));
620        assert_eq!(AccRegister::extract(3), Ok(AccRegister::AF));
621        assert_eq!(AccRegister::extract(9), Err(ParseError(9)));
622    }
623
624    #[test]
625    fn embed_acc_register() {
626        assert_eq!(AccRegister::BC.embed(), 0);
627        assert_eq!(AccRegister::DE.embed(), 1);
628        assert_eq!(AccRegister::HL.embed(), 2);
629        assert_eq!(AccRegister::AF.embed(), 3);
630    }
631
632    #[test]
633    fn extract_stack_register() {
634        assert_eq!(StackRegister::extract(0), Ok(StackRegister::BC));
635        assert_eq!(StackRegister::extract(1), Ok(StackRegister::DE));
636        assert_eq!(StackRegister::extract(2), Ok(StackRegister::HL));
637        assert_eq!(StackRegister::extract(3), Ok(StackRegister::SP));
638        assert_eq!(StackRegister::extract(9), Err(ParseError(9)));
639    }
640
641    #[test]
642    fn embed_stack_register() {
643        assert_eq!(StackRegister::BC.embed(), 0);
644        assert_eq!(StackRegister::DE.embed(), 1);
645        assert_eq!(StackRegister::HL.embed(), 2);
646        assert_eq!(StackRegister::SP.embed(), 3);
647    }
648
649    #[test]
650    fn embed_to_opcode() {
651        assert_eq!(
652            AccRegister::DE.embed_to_opcode(
653                0x30,
654                OpcodePosition {
655                    mask: 0x0C,
656                    shift: 2
657                }
658            ),
659            0x34
660        );
661    }
662
663    #[test]
664    fn append_i8() {
665        assert_eq!(AppendableParam::as_bytes(&-1i8), vec![0xFF]);
666    }
667
668    #[test]
669    fn append_u8() {
670        assert_eq!(AppendableParam::as_bytes(&0x33u8), vec![0x33]);
671    }
672
673    #[test]
674    fn append_u16() {
675        assert_eq!(AppendableParam::as_bytes(&0x2333u16), vec![0x33, 0x23]);
676    }
677
678    #[test]
679    fn append_literal_address() {
680        assert_eq!(
681            AppendableParam::as_bytes(&address::LiteralAddress(0x2333)),
682            vec![0x33, 0x23]
683        );
684    }
685
686    #[test]
687    fn append_high_address() {
688        assert_eq!(
689            AppendableParam::as_bytes(&address::HighAddress(0x23)),
690            vec![0x23]
691        );
692    }
693
694    #[test]
695    fn append_address_offset() {
696        assert_eq!(
697            AppendableParam::as_bytes(&address::AddressOffset(-16i8)),
698            vec![0xF0]
699        );
700    }
701}