]> Witch of Git - jade-mouse/blob - toolchain/src/inst/decode.rs
Implement instruction decoder
[jade-mouse] / toolchain / src / inst / decode.rs
1 use crate::inst::{Addr, Cond, Half, Inst, LdSt, Op1, Op2, OpC, Reg, Size, I5, I7, U4, U7};
2 use bitmatch::bitmatch;
3 use std::{
4 convert::TryInto,
5 fmt::Debug,
6 io::{self, Read},
7 };
8
9 pub trait Decode {
10 fn decode(code: &mut impl Read) -> io::Result<Inst>;
11 }
12
13 impl Decode for Inst {
14 #[bitmatch]
15 fn decode(code: &mut impl Read) -> io::Result<Inst> {
16 use Inst::*;
17 let x = read_1_byte(code)?;
18 Ok(
19 #[bitmatch]
20 match x {
21 "0000_0000" => Halt,
22 "0000_0001" => Nope,
23 "000?_????" => return Err(reserved()),
24 "0ooo_aabb" => Alu2(reg(a), op2(o), reg(b)),
25 "1000_aabb" if a == b => Jalr(reg(a)),
26 "1000_aabb" => Move(reg(a), reg(b)),
27 "1001_aaoo" => Alu1(reg(a), op1(o)),
28 "101f_aabb" => Mem(ldst(f), reg(a), Addr::Reg(reg(b))),
29 "11??_????" => {
30 let y = read_1_byte(code).map_err(reject_eof)?;
31 #[bitmatch]
32 match bitpack!("xxxx_xxxx yyyy_yyyy") {
33 "00_0000 iiii_iiii" => JumpI(i as i8),
34 "01_aabb fiii_iiii" if a == b => Mem(ldst(f), reg(a), fixed(i)),
35 "0o_aabb oiii_iiii" => Branch(cond(o, a, b), i7(i)),
36 "10_aa00 iiii_iiii" => AddI(reg(a), i as i8),
37 "10_aa01 oooo_iiii" => AluCompact(reg(a), op_c(o), U4(i as u8)),
38 "10_aa10 iiii_iiii" => LdImm(Half::Low, reg(a), i as u8),
39 "10_aa11 iiii_iiii" => LdImm(Half::High, reg(a), i as u8),
40 "11_aabb wpsi_iiii" => Mem(
41 ldst(w),
42 reg(a),
43 Addr::Extended {
44 base: reg(b),
45 offset: i5(i),
46 stack: p != 0,
47 size: size(s),
48 },
49 ),
50 }
51 }
52 },
53 )
54 }
55 }
56
57 fn fixed(x: u16) -> Addr {
58 Addr::Fixed(U7(x as u8))
59 }
60
61 fn i7(x: u16) -> I7 {
62 I7(((x as i8) << 1) >> 1)
63 }
64
65 fn i5(x: u16) -> I5 {
66 I5(((x as i8) << 3) >> 3)
67 }
68
69 fn read_1_byte(r: &mut impl Read) -> io::Result<u8> {
70 let mut result = [0];
71 r.read_exact(&mut result[..])?;
72 Ok(result[0])
73 }
74
75 fn reject_eof(err: io::Error) -> io::Error {
76 if err.kind() == io::ErrorKind::UnexpectedEof {
77 io::Error::new(
78 io::ErrorKind::InvalidInput,
79 "instruction missing second byte",
80 )
81 } else {
82 err
83 }
84 }
85
86 fn reg(r: impl TryInto<u8, Error = impl Debug>) -> Reg {
87 match r.try_into().unwrap() & 3 {
88 0 => Reg::R0,
89 1 => Reg::R1,
90 2 => Reg::R2,
91 _ => Reg::R3,
92 }
93 }
94
95 fn cond(o: u16, a: u16, b: u16) -> Cond {
96 let (a, b) = (reg(a), reg(b));
97 debug_assert_ne!(a, b);
98 match (o, a < b) {
99 (0, true) => Cond::Eql(a, b),
100 (0, false) => Cond::Neq(a, b),
101 (1, true) => Cond::Test(a, b),
102 (1, false) => Cond::TestNot(a, b),
103 (2, _) => Cond::Lt(a, b),
104 (3, _) => Cond::Ult(a, b),
105 _ => unreachable!("invalid op"),
106 }
107 }
108
109 fn ldst(l: impl TryInto<u8, Error = impl Debug>) -> LdSt {
110 match l.try_into().unwrap() & 1 {
111 0 => LdSt::Ld,
112 _ => LdSt::St,
113 }
114 }
115
116 fn op1(o: u8) -> Op1 {
117 match o {
118 0 => Op1::Inc,
119 1 => Op1::Dec,
120 2 => Op1::Neg,
121 3 => Op1::Compl,
122 _ => unreachable!("invalid Op1 value"),
123 }
124 }
125
126 fn op2(o: u8) -> Op2 {
127 match o {
128 2 => Op2::Add,
129 3 => Op2::Sub,
130 4 => Op2::AddPc,
131 5 => Op2::And,
132 6 => Op2::Or,
133 7 => Op2::Xor,
134 _ => unreachable!("invalid Op2 value"),
135 }
136 }
137
138 fn op_c(c: u16) -> OpC {
139 match c & 7 {
140 0 => OpC::Lsl,
141 1 => OpC::Lsr,
142 2 => OpC::Asr,
143 3 => OpC::Rol,
144 4 => OpC::Clr,
145 5 => OpC::Set,
146 6 => OpC::Tog,
147 _ => OpC::Ext,
148 }
149 }
150
151 fn size(u: u16) -> Size {
152 match u & 1 {
153 0 => Size::Byte,
154 _ => Size::Word,
155 }
156 }
157
158 fn reserved() -> io::Error {
159 io::Error::new(io::ErrorKind::InvalidInput, "reserved instruction")
160 }