1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use types::*;

impl Instruction<u16> {
    pub fn encode(&self, output: &mut [u16]) -> u16 {
        match *self {
            Instruction::BasicOp(op, b, a) => {
                let mut i = 1;
                output[0] = op.encode();

                let (val, next) = a.encode(true);
                output[0] |= val << SHIFT_A;
                if let Some(n) = next {
                    output[i] = n;
                    i += 1;
                }

                let (val, next) = b.encode(false);
                output[0] |= val << SHIFT_B;
                if let Some(n) = next {
                    output[i] = n;
                    i += 1;
                }

                i as u16
            },
            Instruction::SpecialOp(op, v) => {
                let (a_bin, next) = v.encode(true);
                output[0] = op.encode() << SHIFT_B | (a_bin) << SHIFT_A;
                if let Some(n) = next {
                    output[1] = n;
                    2
                } else {
                    1
                }
            }
        }
    }
}

impl Value<u16> {
    pub fn encode(&self, is_a: bool) -> (u16, Option<u16>) {
        match *self {
            Value::Reg(r) => (r.offset(), None),
            Value::AtReg(r) => (0x08 + r.offset(), None),
            Value::AtRegPlus(r, v) => (0x10 + r.offset(), Some(v)),
            Value::Push => (0x18, None),
            Value::Peek => (0x19, None),
            Value::Pick(v) => (0x1a, Some(v)),
            Value::SP => (0x1b, None),
            Value::PC => (0x1c, None),
            Value::EX => (0x1d, None),
            Value::AtAddr(v) => (0x1e, Some(v)),
            Value::Litteral(v) => {
                if is_a && (v <= 0x1e || v == 0xffff) {
                    (0x20 + v.wrapping_add(1), None)
                } else {
                    (0x1f, Some(v))
                }
            }
        }
    }
}

impl BasicOp {
    pub fn encode(&self) -> u16 {
        *self as u16
    }
}

impl SpecialOp {
    pub fn encode(&self) -> u16 {
        *self as u16
    }
}