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
75
76
77
78
79
80
81
82
use enum_primitive::FromPrimitive;

use types::*;

error_chain! {
    errors {
        BasicOp(val: u16) {
            description("invalid basic opcode")
            display("invalid basic opcode: {:#x}", val)
        }
        SpecialOp(val: u16) {
            description("invalid special opcode")
            display("invalid special opcode: {:#x}", val)
        }
    }
}

impl Instruction<u16> {
    pub fn decode(data: &[u16; 3]) -> Result<(u16, Instruction<u16>)> {
        let op_bin = data[0] & MASK_OP;
        let a_bin = data[0] >> SHIFT_A;
        let b_bin = (data[0] >> SHIFT_B) & MASK_B;

        if op_bin == 0 {
            let op = try!(SpecialOp::decode(b_bin));
            let (used, a) = Value::decode(a_bin, data[1], true);
            Ok((1 + used, Instruction::SpecialOp(op, a)))
        } else {
            let op = try!(BasicOp::decode(op_bin));
            let (used_a, a) = Value::decode(a_bin, data[1], true);
            let (used_b, b) = Value::decode(b_bin, data[(1 + used_a) as usize], false);
            Ok((1 + used_a + used_b, Instruction::BasicOp(op, b, a)))
        }
    }
}

impl Value<u16> {
    pub fn decode(val: u16, next: u16, is_a: bool) -> (u16, Value<u16>) {
        match val {
            x if x <= 0x17 => {
                let reg = Register::from_u16(x % 0x8).expect("Invalid reg id");
                if x <= 0x07 {
                    (0, Value::Reg(reg))
                } else if x <= 0x0f {
                    (0, Value::AtReg(reg))
                } else {
                    (1, Value::AtRegPlus(reg, next))
                }
            },
            0x18 => (0, Value::Push),
            0x19 => (0, Value::Peek),
            0x1a => (1, Value::Pick(next)),
            0x1b => (0, Value::SP),
            0x1c => (0, Value::PC),
            0x1d => (0, Value::EX),
            0x1e => (1, Value::AtAddr(next)),
            0x1f => (1, Value::Litteral(next)),
            x if is_a &&
                 x >= 0x20 &&
                 x <= 0x3f => (0, Value::Litteral(x.wrapping_sub(0x21))),
            _ => unreachable!()
        }
    }
}

impl BasicOp {
    pub fn decode(op: u16) -> Result<BasicOp> {
        match BasicOp::from_u16(op) {
            Some(o) => Ok(o),
            None => try!(Err(ErrorKind::BasicOp(op))),
        }
    }
}

impl SpecialOp {
    pub fn decode(op: u16) -> Result<SpecialOp> {
        match SpecialOp::from_u16(op) {
            Some(o) => Ok(o),
            None => try!(Err(ErrorKind::SpecialOp(op))),
        }
    }
}