1#![allow(dead_code)]
2use std::fmt::{Display, Formatter, Result as FmtResult};
3
4#[inline]
5fn sign_extend(x: i16, b: i16) -> i16 {
6 ((x & ((1 << b) - 1)) ^ (1 << (b - 1))) - (1 << (b - 1))
7}
8
9macro_rules! extract_bits {
10 ($data:ident[$offset:expr]) => {
11 (($data >> $offset) & 1) as i16
12 };
13 ($data:ident[$start:expr; $end:expr]) => {
14 (((1 << ($start - $end + 1)) - 1) & ($data >> $end)) as i16
15 };
16 (@extend $data:ident[$start:expr; $end:expr]) => {
17 sign_extend(
18 (((1 << ($start - $end + 1)) - 1) & ($data >> $end)) as i16,
19 $start - $end + 1,
20 )
21 };
22}
23
24#[derive(Clone, Debug, PartialEq)]
29pub struct Condition {
30 pub n: bool,
31 pub z: bool,
32 pub p: bool,
33}
34
35impl Condition {
36 pub fn satisfies(&self, machine_cond: &Condition) -> bool {
37 (self.n && machine_cond.n) || (self.z && machine_cond.z) || (self.p && machine_cond.p)
38 }
39}
40
41impl Default for Condition {
42 fn default() -> Condition {
43 Condition {
44 n: true,
45 z: false,
46 p: false,
47 }
48 }
49}
50
51impl Eq for Condition {}
52
53#[derive(Debug, PartialEq)]
57pub enum Instruction {
58 ADD { dst: i16, src1: i16, src2: i16 },
59 ADDi { dst: i16, src: i16, immd: i16 },
60 AND { dst: i16, src1: i16, src2: i16 },
61 ANDi { dst: i16, src: i16, immd: i16 },
62 BR { cond: Condition, offset: i16 },
63 JMP { base: i16 },
64 JSR { offset: i16 },
65 JSRR { base: i16 },
66 LD { dst: i16, offset: i16 },
67 LDI { dst: i16, offset: i16 },
68 LDR { dst: i16, base: i16, offset: i16 },
69 LEA { dst: i16, offset: i16 },
70 NOT { dst: i16, src: i16 },
71 RTI,
72 ST { src: i16, offset: i16 },
73 STI { src: i16, offset: i16 },
74 STR { src: i16, base: i16, offset: i16 },
75 RESERVED,
76 TRAP { vect: i16 },
77}
78
79impl Instruction {
80 pub fn from_u16(data: u16) -> Instruction {
86 match data >> 12 {
87 0b0000 => Instruction::BR {
88 cond: Condition {
89 n: extract_bits!(data[11]) > 0,
90 z: extract_bits!(data[10]) > 0,
91 p: extract_bits!(data[9]) > 0,
92 },
93 offset: extract_bits!(@extend data[8;0]),
94 },
95 0b0001 => {
96 if extract_bits!(data[5]) > 0 {
97 Instruction::ADDi {
98 dst: extract_bits!(data[11;9]),
99 src: extract_bits!(data[8;6]),
100 immd: extract_bits!(@extend data[4;0]),
101 }
102 } else {
103 Instruction::ADD {
104 dst: extract_bits!(data[11;9]),
105 src1: extract_bits!(data[8;6]),
106 src2: extract_bits!(data[2;0]),
107 }
108 }
109 }
110 0b0010 => Instruction::LD {
111 dst: extract_bits!(data[11;9]),
112 offset: extract_bits!(@extend data[8;0]),
113 },
114 0b0011 => Instruction::ST {
115 src: extract_bits!(data[11;9]),
116 offset: extract_bits!(@extend data[8;0]),
117 },
118 0b0100 => {
119 if extract_bits!(data[11]) > 0 {
120 Instruction::JSR {
121 offset: extract_bits!(@extend data[10;0]),
122 }
123 } else {
124 Instruction::JSRR {
125 base: extract_bits!(data[8;6]),
126 }
127 }
128 }
129 0b0101 => {
130 if extract_bits!(data[5]) > 0 {
131 Instruction::ANDi {
132 dst: extract_bits!(data[11;9]),
133 src: extract_bits!(data[8;6]),
134 immd: extract_bits!(@extend data[4;0]),
135 }
136 } else {
137 Instruction::AND {
138 dst: extract_bits!(data[11;9]),
139 src1: extract_bits!(data[8;6]),
140 src2: extract_bits!(data[2;0]),
141 }
142 }
143 }
144 0b0110 => Instruction::LDR {
145 dst: extract_bits!(data[11;9]),
146 base: extract_bits!(data[8;6]),
147 offset: extract_bits!(@extend data[5;0]),
148 },
149 0b0111 => Instruction::STR {
150 src: extract_bits!(data[11;9]),
151 base: extract_bits!(data[8;6]),
152 offset: extract_bits!(@extend data[5;0]),
153 },
154 0b1000 => Instruction::RTI,
155 0b1001 => Instruction::NOT {
156 dst: extract_bits!(data[11;9]),
157 src: extract_bits!(data[8;6]),
158 },
159 0b1010 => Instruction::LDI {
160 dst: extract_bits!(data[11;9]),
161 offset: extract_bits!(@extend data[8;0]),
162 },
163 0b1011 => Instruction::STI {
164 src: extract_bits!(data[11;9]),
165 offset: extract_bits!(@extend data[8;0]),
166 },
167 0b1100 => Instruction::JMP {
168 base: extract_bits!(data[8;6]),
169 },
170 0b1101 => Instruction::RESERVED,
171 0b1110 => Instruction::LEA {
172 dst: extract_bits!(data[11;9]),
173 offset: extract_bits!(@extend data[8;0]),
174 },
175 0b1111 => Instruction::TRAP {
176 vect: extract_bits!(data[7;0]),
177 },
178 _ => unreachable!(),
179 }
180 }
181}
182
183impl Display for Instruction {
184 fn fmt(&self, f: &mut Formatter) -> FmtResult {
185 match self {
186 Instruction::ADD { dst, src1, src2 } => write!(f, "ADD r{}, r{}, r{}", dst, src1, src2),
187 Instruction::ADDi { dst, src, immd } => write!(f, "ADD r{}, r{}, #{}", dst, src, immd),
188 Instruction::AND { dst, src1, src2 } => write!(f, "AND r{}, r{}, r{}", dst, src1, src2),
189 Instruction::ANDi { dst, src, immd } => write!(f, "AND r{}, r{}, #{}", dst, src, immd),
190 Instruction::BR { cond, offset } => write!(
191 f,
192 "BR{}{}{} #{}",
193 if cond.n { "n" } else { "" },
194 if cond.z { "z" } else { "" },
195 if cond.p { "p" } else { "" },
196 offset
197 ),
198 Instruction::JMP { base } => write!(f, "JMP r{}", base),
199 Instruction::JSR { offset } => write!(f, "JSR #{}", offset),
200 Instruction::JSRR { base } => write!(f, "JSRR r{}", base),
201 Instruction::LD { dst, offset } => write!(f, "LD r{}, #{}", dst, offset),
202 Instruction::LDI { dst, offset } => write!(f, "LDI r{}, #{}", dst, offset),
203 Instruction::LDR { dst, base, offset } => {
204 write!(f, "LDR r{}, r{}, #{}", dst, base, offset)
205 }
206 Instruction::LEA { dst, offset } => write!(f, "LEA r{}, #{}", dst, offset),
207 Instruction::NOT { dst, src } => write!(f, "NOT r{}, r{}", dst, src),
208 Instruction::RTI => write!(f, "RTI"),
209 Instruction::ST { src, offset } => write!(f, "ST r{}, #{}", src, offset),
210 Instruction::STI { src, offset } => write!(f, "STI r{}, #{}", src, offset),
211 Instruction::STR { src, base, offset } => {
212 write!(f, "STR r{}, r{}, #{}", src, base, offset)
213 }
214 Instruction::RESERVED => write!(f, "RESERVED"),
215 Instruction::TRAP { vect } => write!(f, "TRAP x{:X}", vect),
216 }
217 }
218}
219
220impl Eq for Instruction {}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn test_sign_extend() {
228 assert_eq!(sign_extend(0b0000_0000_0000_0011 as i16, 2), -1);
229 assert_eq!(sign_extend(0b0000_0000_0000_0111 as i16, 3), -1);
230 assert_eq!(sign_extend(0b0000_0000_0000_0111 as i16, 4), 7);
231 assert_eq!(sign_extend(0b0000_0000_0001_0111 as i16, 4), 7);
232 assert_eq!(
233 sign_extend(0b0000_0000_0001_0111 as i16, 5),
234 0b1111_1111_1111_0111 as u16 as i16
235 );
236 }
237
238 #[test]
239 fn test_extract_bits() {
240 let data: u16 = 0b0010_1101_0010_0011;
241 assert_eq!(extract_bits!(data[0]), 1);
242 assert_eq!(extract_bits!(data[3]), 0);
243 assert_eq!(extract_bits!(data[0;0]), 1);
244 assert_eq!(extract_bits!(data[1;0]), 3);
245 assert_eq!(extract_bits!(data[16;12]), 2);
246 assert_eq!(extract_bits!(@extend data[1;0]), -1);
247 assert_eq!(
248 extract_bits!(@extend data[5;1]),
249 0b1111_0001 as u8 as i8 as i16 );
251 assert_eq!(
252 extract_bits!(@extend data[13;8]),
253 0b1110_1101 as u8 as i8 as i16
254 );
255 assert_eq!(extract_bits!(@extend data[16;12]), 2);
256
257 let data1: u16 = 0xF025;
258 assert_eq!(extract_bits!(data1[7;0]), 37);
259 }
260
261 #[test]
263 fn test_instruction_parse() {
264 assert_eq!(
265 Instruction::from_u16(0x1406),
266 Instruction::ADD {
267 src1: 0,
268 src2: 6,
269 dst: 2,
270 }
271 );
272 assert_eq!(
273 Instruction::from_u16(0xF020),
274 Instruction::TRAP { vect: 32 }
275 );
276 assert_eq!(
277 Instruction::from_u16(0x0402),
278 Instruction::BR {
279 cond: Condition {
280 n: false,
281 z: true,
282 p: false,
283 },
284 offset: 2,
285 }
286 );
287 }
288
289 #[test]
290 fn test_instruction_fmt() {
291 assert_eq!(
292 format!(
293 "{}",
294 Instruction::ADD {
295 dst: 1,
296 src1: 0,
297 src2: 2
298 }
299 ),
300 "ADD r1, r0, r2"
301 );
302 assert_eq!(
303 format!(
304 "{}",
305 Instruction::ADDi {
306 dst: 1,
307 src: 0,
308 immd: -12,
309 }
310 ),
311 "ADD r1, r0, #-12"
312 );
313 assert_eq!(
314 format!(
315 "{}",
316 Instruction::AND {
317 dst: 1,
318 src1: 0,
319 src2: 2
320 }
321 ),
322 "AND r1, r0, r2"
323 );
324 assert_eq!(
325 format!(
326 "{}",
327 Instruction::ANDi {
328 dst: 1,
329 src: 0,
330 immd: -12,
331 }
332 ),
333 "AND r1, r0, #-12"
334 );
335 assert_eq!(
336 format!(
337 "{}",
338 Instruction::BR {
339 cond: Condition {
340 n: true,
341 z: true,
342 p: false
343 },
344 offset: -231,
345 },
346 ),
347 "BRnz #-231"
348 );
349 assert_eq!(format!("{}", Instruction::JMP { base: 3 }), "JMP r3");
350 assert_eq!(format!("{}", Instruction::JSR { offset: 142 }), "JSR #142");
351 assert_eq!(format!("{}", Instruction::JSRR { base: 4 }), "JSRR r4");
352 assert_eq!(
353 format!(
354 "{}",
355 Instruction::LD {
356 dst: 2,
357 offset: -24
358 }
359 ),
360 "LD r2, #-24"
361 );
362 assert_eq!(
363 format!("{}", Instruction::LDI { dst: 2, offset: 32 }),
364 "LDI r2, #32"
365 );
366 assert_eq!(
367 format!(
368 "{}",
369 Instruction::LDR {
370 dst: 2,
371 base: 3,
372 offset: 24
373 }
374 ),
375 "LDR r2, r3, #24"
376 );
377 assert_eq!(
378 format!("{}", Instruction::LEA { dst: 3, offset: 21 }),
379 "LEA r3, #21"
380 );
381 assert_eq!(
382 format!("{}", Instruction::NOT { dst: 1, src: 0 }),
383 "NOT r1, r0"
384 );
385 assert_eq!(format!("{}", Instruction::RTI), "RTI");
386 assert_eq!(
387 format!(
388 "{}",
389 Instruction::ST {
390 src: 2,
391 offset: -24
392 }
393 ),
394 "ST r2, #-24"
395 );
396 assert_eq!(
397 format!("{}", Instruction::STI { src: 2, offset: 32 }),
398 "STI r2, #32"
399 );
400 assert_eq!(
401 format!(
402 "{}",
403 Instruction::STR {
404 src: 2,
405 base: 3,
406 offset: 24
407 }
408 ),
409 "STR r2, r3, #24"
410 );
411 assert_eq!(format!("{}", Instruction::RESERVED), "RESERVED");
412 assert_eq!(format!("{}", Instruction::TRAP { vect: 0x25 }), "TRAP x25");
413 }
414}