lemurs_8080/chip/execution/opcode/
mod.rs

1use crate::prelude::{*, convert::TryFrom, fmt::UpperHex};
2use crate::chip::access::{*, Byte::*, Register::*, Word::*, Double::*, Internal::*};
3
4/// A single action on the processor. See the 8080 Programmer's manual for details and operation effects.
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum Op {
7    NOP(raw::u8),
8    Add{from: Byte, carry: bool},
9    AddTo{value: u8, carry: bool},
10    And{from: Byte},
11    AndWith{value: u8},
12    Call{sub: u16},
13    CallIf(Test, u16),
14    CarryFlag(bool),
15    Compare{from: Byte},
16    CompareWith{value: u8},
17    ComplementAccumulator,
18    DecimalAddAdjust,
19    DecrementByte{register: Byte},
20    DecrementWord{register: Internal},
21    Interrupts(bool),
22    DoubleAdd{register: Internal},
23    ExchangeDoubleWithHilo, 
24    ExchangeTopWithHilo,
25    ExclusiveOr{ from: Byte },
26    ExclusiveOrWith{value: u8},
27    Halt,
28    In(raw::u8),
29    IncrementByte{register: Byte},
30    IncrementWord{register: Internal},
31    Jump{to: u16},
32    JumpIf(Test, u16),
33    LoadAccumulator{address: u16},
34    LoadAccumulatorIndirect{register: Double},
35    LoadExtendedWith{to: Internal, value: u16 },
36    LoadHilo{address: u16},
37    Move{to: Byte, from: Byte},
38    MoveData{value: u8, to: Byte},
39    Or{from: Byte},
40    OrWith{value: u8},
41    Out(raw::u8),
42    Pop(Word),
43    ProgramCounterFromHilo,
44    Push(Word),
45    Reset{vector: raw::u8},
46    Return,
47    ReturnIf(Test),
48    RotateLeftCarrying,
49    RotateRightCarrying,
50    RotateAccumulatorLeft,
51    RotateAccumulatorRight,
52    StackPointerFromHilo,
53    StoreAccumulator{address: u16},
54    StoreAccumulatorIndirect{register: Double},
55    StoreHilo{address: u16},
56    Subtract{from: Byte, carry: bool},
57    SubtractBy{value: u8, carry: bool},
58}
59
60impl From<raw::u8> for Internal {
61    fn from(value: raw::u8) -> Self {
62        match value & 0b00_11_0000 {
63            0b00_00_0000 => Wide(BC),
64            0b00_01_0000 => Wide(DE),
65            0b00_10_0000 => Wide(HL),
66            0b00_11_0000 => StackPointer,
67            _ => unreachable!(),
68        }
69    }
70}
71
72impl From<Word> for raw::u8 {
73    fn from(value: Word) -> Self {
74        match value {
75            Word::ProgramStatus | OnBoard(StackPointer) => 3,
76            OnBoard(Wide(pair)) => pair as raw::u8,
77            word => panic!("No bit encoding for location {word:?} in op."),
78        }
79    }
80}
81
82impl From<raw::u8> for Byte {
83    fn from(value: raw::u8) -> Self {
84        match value & 0b00_111_000 {
85            0b00_000_000 => Single(B),
86            0b00_001_000 => Single(C),
87            0b00_010_000 => Single(D),
88            0b00_011_000 => Single(E),
89            0b00_100_000 => Single(H),
90            0b00_101_000 => Single(L),
91            0b00_110_000 => Byte::Indirect,
92            0b00_111_000 => Single(A),
93            _ => unreachable!(),
94        }
95    }
96}
97
98impl From<Byte> for raw::u8 {
99    fn from(value: Byte) -> Self {
100        match value {
101            Byte::Indirect => 6,
102            Single(A) => 7,
103            #[cfg(target_endian="little")]
104            Single(reg) => reg as raw::u8,
105            #[cfg(target_endian="big")]
106            Single(reg) => reg as raw::u8 ^ 0x01,
107            Byte::RAM(_) => panic!("No encoding for direct RAM references"),
108        }
109    }
110}
111
112impl Byte {
113    fn split(value: raw::u8) -> (Self, Self) {
114        (Self::from(value), Self::from(value << 3))
115    }
116}
117
118#[repr(u8)]
119#[derive(Debug, Clone, Copy, PartialEq)]
120pub enum Flag {
121    Zero,
122    Carry,
123    EvenParity,
124    Negative,
125}
126
127#[repr(u8)]
128#[derive(Debug, Clone, Copy, PartialEq)]
129pub enum Test {
130    Not(Flag),
131    Is(Flag),
132}
133
134use Flag::*;
135use Test::*;
136
137impl Test {
138    pub fn approves(self, env: &super::State) -> bool {
139        match self {
140            Not(Zero) => !env.z,
141            Is(Zero) => env.z,
142            Not(Carry) => !env.c,
143            Is(Carry) => env.c,
144            Not(EvenParity) => !env.p,
145            Is(EvenParity) => env.p,
146            Not(Negative) => !env.m,
147            Is(Negative) => env.m,
148        }
149    }
150}
151
152impl From<raw::u8> for Test {
153    fn from(value: raw::u8) -> Self {
154        let test = match (value & 0b00_11_0_000) >> 4 {
155            0b00 => Zero,
156            0b01 => Carry,
157            0b10 => EvenParity,
158            0b11 => Negative,
159            _ => unreachable!()
160        };
161        match (value & 0b00_00_1_000) >> 3  {
162            0b0 => Not(test),
163            0b1 => Is(test),
164            _ => unreachable!()
165        }
166    }
167}
168
169impl From<Test> for raw::u8 {
170    fn from(value: Test) -> Self {
171        match value {
172            Not(Zero) => 0b00_00_0_000,
173            Is(Zero)  => 0b00_00_1_000,
174            Not(Carry) => 0b00_01_0_000,
175            Is(Carry)  => 0b00_01_1_000,
176            Not(EvenParity) => 0b00_10_0_000,
177            Is(EvenParity)  => 0b00_10_1_000,
178            Not(Negative) => 0b00_11_0_000,
179            Is(Negative)  => 0b00_11_1_000,
180        }
181    }
182}
183
184#[disclose]
185#[allow(non_upper_case_globals)]
186mod b11111111 {
187    use super::raw::u8;
188
189    const NoOp: u8 = 0b00000000;
190    const RotateLeftCarrying: u8        = 0b00000111;
191    const RotateRightCarrying: u8       = 0b00001111;
192    const RotateAccumulatorLeft: u8     = 0b00010111;
193    const RotateAccumulatorRight: u8    = 0b00011111;
194
195    const StoreAccumulatorDirect: u8    = 0b00110010;
196    const LoadAccumulatorDirect: u8 = 0b00111010;
197
198    const StoreHiloDirect: u8   = 0b00100010;
199    const LoadHiloDirect: u8    = 0b00101010;
200
201    const DecimalAddAdjust: u8      = 0b00100111;
202    const ComplementAccumulator: u8 = 0b00101111;
203
204    const SetCarry: u8          = 0b00110111;
205    const ComplementCarry: u8   = 0b00111111;
206
207    const Halt: u8      = 0b01110110;
208    const Return: u8    = 0b11001001;
209
210    const Output: u8    = 0b11010011;
211    const Input: u8     = 0b11011011;
212
213    const ExchangeTopWithHilo: u8       = 0b11100011;
214    const ProgramCounterFromHilo: u8    = 0b11101001;
215    const ExchangeDoubleWithHilo: u8    = 0b11101011;
216    const StackPointerFromHilo: u8      = 0b11111001;
217
218    const DisableInterrupts: u8 = 0b11110011;
219    const EnableInterrupts: u8  = 0b11111011;
220
221    const AndImmediate: u8  = 0b11100110;
222    const AddImmediate: u8  = 0b11000110;
223    const AddImmediateCarrying: u8  = 0b11001110;
224    const SubtractImmediate: u8     = 0b11010110;
225    const SubtractImmediateBorrowing: u8    = 0b11011110;
226    const ExclusiveOrImmediate: u8  = 0b11101110;
227    const OrImmediate: u8   = 0b11110110;
228    const CompareImmediate: u8   = 0b11111110;
229
230    const StoreHiLoDirect: u8   = 0b00100010;
231    const Jump: u8  = 0b11000011;
232    const Call: u8  = 0b11001101;
233}
234
235#[disclose]
236#[allow(non_upper_case_globals)]
237mod b11_00_1111 {
238    use super::raw::u8;
239
240    const LoadExtendedImmediate: u8 = 0b00_00_0001;
241    const IncrementExtended: u8 = 0b00_00_0011;
242    const DecrementExtended: u8 = 0b00_00_1011;
243    const DoubleAdd: u8 = 0b00_00_1001;
244    const Push: u8  = 0b11_00_0101;
245    const Pop: u8 = 0b11_00_0001;
246}
247
248#[disclose]
249#[allow(non_upper_case_globals)]
250mod b11_000_111 {
251    use super::raw::u8;
252    
253    const IncrementRegister: u8 = 0b00_000_100;
254    const DecrementRegister: u8 = 0b00_000_101;
255    const JumpIf: u8 = 0b11_000_010;
256    const Reset: u8 = 0b11_000_111;
257    const ReturnIf: u8 = 0b11_000_000;
258    const CallIf: u8 = 0b11_000_100;
259    const MoveImmediate: u8 = 0b00_000_110;
260}
261
262#[disclose]
263#[allow(non_upper_case_globals)]
264mod b11_111_000 {
265    use super::raw::u8;
266    
267    const AddToAccumulator: u8  = 0b10_000_000;
268    const AddCarryingToAccumulator : u8 = 0b10_001_000;
269    const SubtractFromAccumulator: u8   = 0b10_010_000;
270    const SubtractBorrowingFromAccumulator: u8  = 0b10_011_000;
271    const AndWithAccumulator: u8    = 0b10_100_000;
272    const ExclusiveOrWithAccumulator: u8    = 0b10_101_000;
273    const OrWithAccumulator: u8 = 0b10_110_000;
274    const CompareWithAccumulator: u8    = 0b10_111_000;
275}
276
277#[disclose]
278#[allow(non_upper_case_globals)]
279mod b11_000000 {
280    const Move: super::raw::u8  = 0b01_000000;
281}
282
283#[disclose]
284#[allow(non_upper_case_globals)]
285mod b111_0_1111 {
286    use super::raw::u8;
287    
288    const LoadAccumulatorIndirect: u8   = 0b000_0_1010;
289    const StoreAccumulatorIndirect: u8  = 0b000_0_0010;
290}
291
292#[derive(Debug)]
293pub struct OutOfRange;
294#[derive(Debug, Clone, Copy, PartialEq)]
295pub enum Error {
296    Unknown(u8),
297    NotUsable(Op),
298    Mismatch(Op, u8),
299    Invalid([u8;1]),
300    InvalidPair([u8;2]),
301    InvalidTriple([u8;3]),
302    NoData,
303}
304
305impl core::fmt::Display for OutOfRange {
306    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
307        write!(f, "value out of bounds")
308    }
309}
310
311impl core::error::Error for OutOfRange {}
312
313impl core::fmt::Display for Error {
314    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
315        write!(f, "{self:?}")
316    }
317}
318
319impl core::error::Error for self::Error {}
320
321impl UpperHex for Error {
322    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
323        match self {
324            Self::Mismatch(op, code) => write!(f, "Mismatch({op:?}, {code:X})"),
325            Self::Invalid([a]) => write!(f, "Invalid([{a:#04X}])"),
326            Self::InvalidPair([a, b]) => write!(f, "InvalidPair([{a:#04X}, {b:#04X}])"),
327            Self::InvalidTriple([a, b, c]) => write!(f, "InvalidTriple([{a:#04X}, {b:#04X}, {c:#04X}])"),
328            _ => write!(f, "{self:?}"),
329        }
330    }
331}
332
333impl TryFrom<[u8;1]> for Op {
334    type Error = [u8;1];
335    fn try_from(value: [u8;1]) -> Result<Self, Self::Error> {
336        {
337            use Op::*;
338            let value = value[0].0;
339            let value = match value & 0b11111111 {
340                b11111111::NoOp => return Ok(NOP(4)),
341                b11111111::ExchangeDoubleWithHilo => return Ok(ExchangeDoubleWithHilo),
342                b11111111::Halt => return Ok(Halt),
343                b11111111::Return => return Ok(Return),
344                b11111111::ExchangeTopWithHilo => return Ok(ExchangeTopWithHilo),
345                b11111111::RotateLeftCarrying => return Ok(RotateLeftCarrying),
346                b11111111::RotateRightCarrying => return Ok(RotateRightCarrying),
347                b11111111::RotateAccumulatorLeft => return Ok(RotateAccumulatorLeft),
348                b11111111::RotateAccumulatorRight => return Ok(RotateAccumulatorRight),
349                b11111111::SetCarry => return Ok(CarryFlag(true)),
350                b11111111::ComplementCarry => return Ok(CarryFlag(false)),
351                b11111111::DecimalAddAdjust => return  Ok(DecimalAddAdjust),
352                b11111111::ComplementAccumulator => return Ok(ComplementAccumulator),
353                b11111111::ProgramCounterFromHilo => return Ok(ProgramCounterFromHilo),
354                b11111111::StackPointerFromHilo => return Ok(StackPointerFromHilo),
355                b11111111::DisableInterrupts => return Ok(Interrupts(false)),
356                b11111111::EnableInterrupts => return Ok(Interrupts(true)),
357                _ => value
358            };
359            let _value = match value & 0b11_000_111 {
360                b11_000_111::Reset => return Ok(Reset{vector: value >> 3 & 0x07}),
361                b11_000_111::ReturnIf => return Ok(ReturnIf(Test::from(value))),
362                b11_000_111::IncrementRegister => return Ok(IncrementByte { register: Byte::from(value) }),
363                b11_000_111::DecrementRegister => return Ok(DecrementByte { register: Byte::from(value) }),
364                _ => value,
365            };
366            let _value = match value & 0b11_00_1111 {
367                b11_00_1111::DecrementExtended => return Ok(DecrementWord{register: Internal::from(value)}),
368                b11_00_1111::IncrementExtended => return Ok(IncrementWord { register: Internal::from(value) }),
369                b11_00_1111::DoubleAdd => return Ok(DoubleAdd{register: Internal::from(value)}),
370                b11_00_1111::Push => return Ok(Push(match Internal::from(value) { StackPointer => ProgramStatus, wide => OnBoard(wide)})),
371                b11_00_1111::Pop => return Ok(Pop(match Internal::from(value) { StackPointer => ProgramStatus, wide => OnBoard(wide)})),
372                _ => value,
373            };
374            let _value = match (value & 0b11_111_000, value << 3) {
375                (b11_111_000::AddToAccumulator, value) => return Ok(Add{from: Byte::from(value), carry: false}),
376                (b11_111_000::AddCarryingToAccumulator, value) => return Ok(Add{ from: Byte::from(value), carry: true}),
377                (b11_111_000::SubtractFromAccumulator, value) => return Ok(Subtract{ from: Byte::from(value), carry: false}),
378                (b11_111_000::SubtractBorrowingFromAccumulator, value) => return Ok(Subtract{ from: Byte::from(value), carry: true}),
379                (b11_111_000::AndWithAccumulator, value) => return Ok(And{from: Byte::from(value)}),
380                (b11_111_000::ExclusiveOrWithAccumulator, value) => return Ok(ExclusiveOr { from: Byte::from(value) }),
381                (b11_111_000::OrWithAccumulator, value) => return Ok(Or { from: Byte::from(value) }),
382                (b11_111_000::CompareWithAccumulator, value) => return Ok(Compare{from: Byte::from(value)}),
383                _ => value,
384            };
385            let _value = match value & 0b11_000000 {
386                b11_000000::Move => {
387                    let (to, from) = Byte::split(value);
388                    return Ok(Move{to, from});
389                }
390                _ => value,
391            };
392            let _value = match value & 0b111_0_1111 {
393                b111_0_1111::LoadAccumulatorIndirect => return Ok(LoadAccumulatorIndirect { 
394                    register: if value & 0b000_1_0000 != 0 { DE } else { BC }
395                }),
396                b111_0_1111::StoreAccumulatorIndirect => return Ok(StoreAccumulatorIndirect { 
397                    register: if value & 0b000_1_0000 != 0 { DE } else { BC }
398                }),
399                _ => value,
400            };
401        }
402        Err(value)
403    }
404}
405
406impl TryFrom<[u8;2]> for Op {
407    type Error = [u8;2];
408    fn try_from(code: [u8;2]) -> Result<Self, Self::Error> {
409        use Op::*;
410        let [action, value] = code;
411        let value = value;
412        let action = match action.0 {
413            b11111111::AddImmediate => return Ok(AddTo { value, carry: false }),
414            b11111111::AddImmediateCarrying => return Ok(AddTo{ value, carry: true }),
415            b11111111::SubtractImmediate => return Ok(SubtractBy{ value, carry: false }),
416            b11111111::SubtractImmediateBorrowing => return Ok(SubtractBy { value, carry: true }),
417            b11111111::AndImmediate => return Ok(AndWith { value }),
418            b11111111::ExclusiveOrImmediate => return Ok(ExclusiveOrWith{value}),
419            b11111111::OrImmediate => return Ok(OrWith{value}),
420            b11111111::CompareImmediate => return Ok(CompareWith{ value }),
421            b11111111::Output => return Ok(Out(code[1].0)),
422            b11111111::Input => return Ok(In(code[1].0)),
423            next => next,
424        };
425        let _action = match action & 0b11_000_111 {
426            b11_000_111::MoveImmediate => return Ok(MoveData{ value, to: Byte::from(action) }),
427            _next => action,
428        };
429        Err(code)
430    }
431}
432
433impl TryFrom<[u8;3]> for Op {
434    type Error = [u8;3];
435    fn try_from(value: [u8;3]) -> Result<Self, Self::Error> {
436        use Op::*;
437        let action = value[0].0;
438        let data = Wrapping(raw::u16::from_le_bytes([value[1].0, value[2].0]));
439        match action {
440            b11111111::LoadHiloDirect => return Ok(LoadHilo{address: data}),
441            b11111111::StoreHiloDirect => return Ok(StoreHilo{address: data}),
442            b11111111::LoadAccumulatorDirect => return Ok(LoadAccumulator { address: data }),
443            b11111111::StoreAccumulatorDirect => return Ok(StoreAccumulator { address: data }),
444            b11111111::Jump => return Ok(Jump{to: data}),
445            b11111111::Call => return Ok(Call{sub: data}),
446            _ => action,
447        };
448        match action & 0b11_00_1111 {
449            b11_00_1111::LoadExtendedImmediate => return Ok(LoadExtendedWith { to: Internal::from(action), value: data }),
450            _ => action,
451        };
452        match action & 0b11_000_111 {
453            b11_000_111::JumpIf => return Ok(JumpIf(Test::from(action), data)),
454            b11_000_111::CallIf => return Ok(CallIf(Test::from(action), data)),
455            _ => action,
456        };
457        Err(value)
458    }
459}
460
461impl Op {
462    pub fn len(&self) -> raw::u8 {
463        use Op::*;
464        match self {
465            Call{..} | CallIf(..) | Jump{..} | JumpIf(..) | LoadExtendedWith{..} | 
466            ReturnIf(..) | StoreAccumulator{..} | LoadAccumulator {..} | LoadHilo{..} | StoreHilo {..}
467                => 3,
468            AddTo{..} | AndWith{..} | ExclusiveOrWith{..} | OrWith{..} | SubtractBy{..} | CompareWith{..} | MoveData{..} |
469            Out(..) | In(..)
470                => 2,
471            NOP(..) | Push(..) | Reset{..} | ExchangeDoubleWithHilo | Return | Halt | Pop(..) | ExchangeTopWithHilo | 
472            Move{..} | RotateLeftCarrying | RotateRightCarrying | RotateAccumulatorLeft | RotateAccumulatorRight | 
473            IncrementByte {..} | DecrementByte {..} | Add{..}  | Subtract{..} | And{..} | ExclusiveOr{..} | Or{..} | 
474            Compare{..} | IncrementWord{..} | DecrementWord {..} | Interrupts(..) | 
475            LoadAccumulatorIndirect {..} | StoreAccumulatorIndirect{..} | 
476            DoubleAdd{..} | CarryFlag(..) | DecimalAddAdjust | ComplementAccumulator | ProgramCounterFromHilo | StackPointerFromHilo
477                => 1,
478        }
479    }
480
481    pub fn extract(feed: impl IntoIterator<Item = u8>) -> Result<(Op, usize), self::Error> {
482        let mut feed = feed.into_iter();
483        let code = match Op::try_from([feed.next().ok_or(Error::NoData)?]) {
484            Ok(op) => return Ok((op, 1)),
485            Err(code) => code,
486        };
487        match code[0].0 {
488            0xCB | 0xD9 => return Err(Error::Unknown(code[0])),
489            0xDD | 0xED | 0xFD => return Err(Error::Unknown(code[0])),
490            nop if nop & 0b11_000_111 == 0 => return Err(Error::Unknown(code[0])),
491            _ => ()
492        };
493        let code = match Op::try_from([code[0], feed.next().ok_or(Error::Invalid(code))?]) {
494            Ok(op) => return Ok((op, 2)),
495            Err(code) => code,
496        };
497        match Op::try_from([code[0], code[1], feed.next().ok_or(Error::InvalidPair(code))?]) {
498            Ok(op) => Ok((op, 3)),
499            Err(code) => Err(Error::InvalidTriple(code))
500        }
501    }
502}
503
504impl Into<[raw::u8;4]> for Op {
505    fn into(self) -> [raw::u8;4] {
506        use Op::*;
507        use raw::u8;
508        match self {
509            NOP(..) => [ 1, 0, 0, 0 ],
510            Add{ from, .. } | Subtract { from, .. } | And { from } | 
511            ExclusiveOr { from } | Or { from } | Compare { from }
512                => {
513                    let op = match self {
514                        Add{ carry: false, ..} => b11_111_000::AddToAccumulator,
515                        Add{ carry: true, ..}  => b11_111_000::AddCarryingToAccumulator,
516                        Subtract { carry: false, .. } => b11_111_000::SubtractFromAccumulator,
517                        Subtract { carry: true, .. }  => b11_111_000::SubtractBorrowingFromAccumulator,
518                        And { .. } => b11_111_000::AndWithAccumulator,
519                        ExclusiveOr { .. } => b11_111_000::ExclusiveOrWithAccumulator,
520                        Or { .. } => b11_111_000::OrWithAccumulator,
521                        Compare { .. } => b11_111_000::CompareWithAccumulator,
522                        _ => unreachable!(),
523                    };
524                    [ 1, op | raw::u8::from(from), 0, 0 ]
525                }
526            AddTo { value, .. } | SubtractBy { value, .. } | AndWith { value } |
527            ExclusiveOrWith { value } | OrWith { value } | CompareWith { value }
528                => {
529                    let op = match self {
530                        AddTo { carry: false, .. } => b11111111::AddImmediate,
531                        AddTo { carry: true, .. } => b11111111::AddImmediateCarrying,
532                        SubtractBy { carry: false, .. } => b11111111::SubtractImmediate,
533                        SubtractBy { carry: true, .. } => b11111111::SubtractImmediateBorrowing,
534                        AndWith { .. } => b11111111::AndImmediate,
535                        ExclusiveOrWith { .. } => b11111111::ExclusiveOrImmediate,
536                        OrWith { .. } => b11111111::OrImmediate,
537                        CompareWith { .. } => b11111111::CompareImmediate,
538                        _ => unreachable!()
539                    };
540                    [2, op, value.0, 0]
541                }
542            Call { sub } => { let address = sub.0.to_le_bytes(); [ 3, b11111111::Call, address[0], address[1] ]}
543            CallIf(test, sub) 
544                => { let address = sub.0.to_le_bytes(); [ 3, b11_000_111::CallIf | (u8::from(test) << 3), address[0], address[1] ]}
545            CarryFlag(set) => [ 1, if set { b11111111::SetCarry } else { b11111111::ComplementCarry }, 0, 0 ],
546            ComplementAccumulator => [ 1, b11111111::ComplementAccumulator, 0, 0 ],
547            DecimalAddAdjust => [ 1, b11111111::DecimalAddAdjust, 0, 0 ],
548            DecrementByte { register } => [ 1, b11_000_111::DecrementRegister | (u8::from(register) << 3), 0, 0 ],
549            DecrementWord { register } => [ 1, b11_00_1111::DecrementExtended | (u8::from(OnBoard(register)) << 4), 0, 0 ],
550            DoubleAdd { register } => [ 1, b11_00_1111::DoubleAdd | (u8::from(OnBoard(register)) << 4), 0, 0 ],
551            ExchangeDoubleWithHilo => [ 1, b11111111::ExchangeDoubleWithHilo, 0, 0 ],
552            ExchangeTopWithHilo => [ 1, b11111111::ExchangeTopWithHilo, 0, 0 ],
553            Halt => [ 1, b11111111::Halt, 0, 0 ],
554            In(port) => [ 2, b11111111::Input, port, 0 ],
555            IncrementByte { register } => [ 1, b11_000_111::IncrementRegister | (u8::from(register)) << 3, 0, 0 ],
556            IncrementWord { register } => [ 1, b11_00_1111::IncrementExtended | (u8::from(OnBoard(register)) << 4), 0, 0 ],
557            Interrupts(accepted) => [ 1, if accepted { b11111111:: EnableInterrupts } else { b11111111::DisableInterrupts }, 0, 0 ],
558            Jump { to } => { let bytes = to.0.to_le_bytes(); [ 3, b11111111::Jump, bytes[0], bytes[1] ] }
559            JumpIf(test, to) 
560                => { let bytes = to.0.to_le_bytes(); [ 3, b11_000_111::JumpIf | (u8::from(test) << 4), bytes[0], bytes[1] ]}
561            LoadAccumulator { address } => { let bytes = address.0.to_le_bytes(); [ 3, b11111111::LoadAccumulatorDirect, bytes[0], bytes[1] ] }
562            LoadAccumulatorIndirect { register } => [ 1, b111_0_1111::LoadAccumulatorIndirect | ((u8::from(OnBoard(Wide(register))) & 0x01) << 4), 0, 0 ],
563            LoadExtendedWith { to, value } 
564                => { let bytes = value.0.to_le_bytes(); [ 3, b11_00_1111::LoadExtendedImmediate | (u8::from(OnBoard(to)) << 4), bytes[0], bytes[1] ] }
565            LoadHilo { address } 
566                => { let bytes = address.0.to_le_bytes(); [3, b11111111::LoadHiloDirect, bytes[0], bytes[1] ] }
567            Move { to, from } => [ 1, b11_000000::Move | (u8::from(to) << 3) | raw::u8::from(from), 0, 0 ],
568            MoveData { value, to } => [ 2, b11_000_111::MoveImmediate | (u8::from(to) << 3), value.0, 0 ],
569            Out(port) => [ 2, b11111111::Output, port, 0 ],
570            Pop(target) => [ 1, b11_00_1111::Pop | (u8::from(target) << 4), 0, 0 ],
571            ProgramCounterFromHilo => [ 1, b11111111::ProgramCounterFromHilo, 0, 0 ], 
572            Push(source) => [ 1, b11_00_1111::Push | (u8::from(source) << 4), 0, 0 ],
573            Reset { vector } => [ 1, b11_000_111::Reset | (vector << 3), 0, 0 ],
574            Return => [ 1, b11111111::Return, 0, 0 ],
575            ReturnIf(test) => [ 1, b11_000_111::ReturnIf | (u8::from(test) << 3), 0, 0 ],
576            RotateAccumulatorLeft => [ 1, b11111111::RotateAccumulatorLeft, 0, 0 ],
577            RotateAccumulatorRight => [ 1, b11111111::RotateAccumulatorRight, 0, 0 ],
578            RotateLeftCarrying => [ 1, b11111111::RotateLeftCarrying, 0, 0 ],
579            RotateRightCarrying => [ 1, b11111111::RotateRightCarrying, 0, 0 ],
580            StackPointerFromHilo => [ 1, b11111111::StackPointerFromHilo, 0, 0 ],
581            StoreAccumulator { address } 
582                => { let bytes = address.0.to_le_bytes(); [ 3, b11111111::StoreAccumulatorDirect, bytes[0], bytes[1] ] }
583            StoreAccumulatorIndirect { register } 
584                => [ 1, b111_0_1111::StoreAccumulatorIndirect | ((u8::from(OnBoard(Wide(register))) & 0b01 ) << 4), 0, 0 ], 
585            StoreHilo { address } => { let bytes = address.0.to_le_bytes(); [ 3, b11111111::StoreHiLoDirect, bytes[0], bytes[1] ] }
586        }
587    }
588}
589
590#[cfg(test)]
591mod tests;