]> Witch of Git - jade-rose/blob - toolchain/src/inst/decode.rs
Add decoding with proptest round-trip test
[jade-rose] / toolchain / src / inst / decode.rs
1 use super::{AddImm, AluI, Data, Inst, Op1, OpI3, OpR, Reg, Special, Target, U3};
2 use std::io::{self, Read};
3
4 pub trait Decode: Sized {
5 fn decode(reader: &mut impl Read) -> io::Result<Self>;
6 }
7
8 fn reg(x: u8) -> Reg {
9 Reg::new(x & 0x7).unwrap()
10 }
11
12 fn special(x: u8) -> io::Result<Special> {
13 match x {
14 0b000 => Ok(Special::Data(Data::D1)),
15 0b001 => Ok(Special::Data(Data::D2)),
16 0b010 => Ok(Special::Code),
17 0b011 => Err(io::Error::new(
18 io::ErrorKind::Other,
19 "Reserved special register",
20 )),
21 _ => Err(io::Error::new(
22 io::ErrorKind::Other,
23 "Invalid special register",
24 )),
25 }
26 }
27
28 fn op1(x: u8) -> Op1 {
29 match x {
30 0b000 => Op1::Zero,
31 0b001 => Op1::Lsl1,
32 0b010 => Op1::Lsr1,
33 0b011 => Op1::Asr1,
34 0b100 => Op1::Incr,
35 0b101 => Op1::Decr,
36 0b110 => Op1::Comp,
37 0b111 => Op1::Negt,
38 _ => unreachable!(),
39 }
40 }
41
42 fn op_r(x: u8) -> OpR {
43 match x & 7 {
44 0b000 => OpR::Add,
45 0b001 => OpR::Sub,
46 0b010 => OpR::And,
47 0b011 => OpR::Ior,
48 0b100 => OpR::Xor,
49 0b101 => OpR::Lsl,
50 0b110 => OpR::Lsr,
51 0b111 => OpR::Asr,
52 _ => unreachable!(),
53 }
54 }
55
56 fn flag(x: u8) -> bool {
57 x & 2 != 0
58 }
59
60 fn op_compact(x: u8) -> OpI3 {
61 match (x >> 3) & 7 {
62 0b000 => OpI3::Rol,
63 0b001 => OpI3::Lsl,
64 0b010 => OpI3::Lsr,
65 0b011 => OpI3::Asr,
66 0b100 => OpI3::Clr,
67 0b101 => OpI3::Set,
68 0b110 => OpI3::Tog,
69 0b111 => OpI3::Ext,
70 _ => unreachable!(),
71 }
72 }
73
74 impl Decode for Inst {
75 fn decode(reader: &mut impl Read) -> io::Result<Self> {
76 use Data::*;
77 let mut op_byte = [0];
78 reader.read_exact(&mut op_byte)?;
79 Ok(match (op_byte[0] >> 3, op_byte[0] & 7) {
80 (0b0000_0, 0..=2) => Inst::Trap,
81 (0b0000_0, 0b100) => Inst::Jump(Target::Abs),
82 (0b0000_0, 0b101) => Inst::Call(Target::Abs),
83 (0b0000_0, 0b110) => Inst::Jump(Target::Off),
84 (0b0000_0, 0b111) => Inst::Call(Target::Off),
85 (0b0000_1, r) => Inst::Swap(reg(r)),
86 (0b0001_0, r) => Inst::GetR(reg(r)),
87 (0b0001_1, r) => Inst::SetR(reg(r)),
88 (0b0010_0, s) => Inst::Get(special(s)?),
89 (0b0010_1, s) => Inst::Set(special(s)?),
90 (0b0011_0, o) => Inst::Alu1(op1(o)),
91 (0b0011_1, r) => Inst::IsLt(reg(r)),
92 (o @ 0b0100_0..=0b0111_1, r) => Inst::AluR(op_r(o), reg(r)),
93 (o @ 0b1000_0, r) | (o @ 0b1001_0, r) => Inst::LdD(D1, reg(r), flag(o)),
94 (o @ 0b1000_1, r) | (o @ 0b1001_1, r) => Inst::StD(D1, reg(r), flag(o)),
95 (o @ 0b1010_0, r) | (o @ 0b1011_0, r) => Inst::LdD(D2, reg(r), flag(o)),
96 (o @ 0b1010_1, r) | (o @ 0b1011_1, r) => Inst::StD(D2, reg(r), flag(o)),
97 (0b1111_0..=0b1111_1, _) => {
98 let mut imm_byte = [0];
99 reader.read_exact(&mut imm_byte)?;
100 let imm = imm_byte[0];
101 match op_byte[0] & 0xf {
102 0b0000 => Inst::AluI(AluI::And(imm)),
103 0b0001 => Inst::AluI(AluI::Ior(imm)),
104 0b0010 => Inst::AluI(AluI::Xor(imm)),
105 0b0011 => match imm >> 6 {
106 0b00 | 0b01 | 0b11 => Inst::AluI(AluI::Add(AddImm::new(imm as i8).unwrap())),
107 0b10 => {
108 let imm3 = U3::new(imm & 7).unwrap();
109 Inst::AluI(AluI::Compact(op_compact(imm), imm3))
110 }
111 _ => unreachable!(),
112 },
113 0b0100 => Inst::BEzI(imm as i8),
114 0b0101 => Inst::Trap, /* reserved branch */
115 0b0110 => Inst::Jump(Target::OffImm(imm as i8)),
116 0b0111 => Inst::Call(Target::OffImm(imm as i8)),
117 _ => Inst::Trap, /* reserved with immediate */
118 }
119 }
120 _ => Inst::Trap,
121 })
122 }
123 }