vax_disassembler/lib.rs
1#![doc = include_str!("../README.md")]
2#![forbid(future_incompatible)]
3#![warn(missing_docs, missing_debug_implementations, bare_trait_objects)]
4
5pub mod error;
6pub mod opcode;
7pub mod operand;
8
9use std::io::Read;
10pub use crate::{
11 error::{Error, Result},
12 opcode::{
13 AccessType,
14 DataType,
15 DataValue,
16 ReadDataValue,
17 WriteDataValue,
18 Instruction,
19 Opcode,
20 },
21 operand::{IndexedOperand, Operand, ReadOperand, Register},
22};
23
24/// Extends [`Read`] with a method to read a VAX instruction ([`Instruction`]).
25///
26/// # Examples
27///
28/// ```rust
29/// use vax_disassembler::ReadMacro32;
30/// use std::io::Cursor;
31///
32/// macro_rules! disassemble {
33/// ($buf: expr, $text: expr) => {
34/// let instruction = Cursor::new($buf).disassemble().unwrap();
35/// assert_eq!(&format!("{}", instruction), $text);
36/// };
37/// }
38///
39/// disassemble!([0x05], "RSB");
40/// disassemble!([0xE9, 0x50, 0x15], "BLBC R0, 21");
41/// disassemble!([0xDE, 0x44, 0xC4, 0x00, 0xFE, 0x55], "MOVAL W^-512(R4)[R4], R5");
42/// disassemble!([0xCB, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x50, 0x53], "BICL3 #16777215, R0, R3");
43/// disassemble!([0x28, 0x8F, 0x00, 0x02, 0x61, 0xC1, 0x00, 0xFE], "MOVC3 #512, (R1), W^-512(R1)");
44/// ```
45pub trait ReadMacro32: Read {
46 /// Read VAX MACRO32 machine code from a reader and disassemble it into a single
47 /// [`Instruction`].
48 ///
49 /// # Examples
50 ///
51 /// ```rust
52 /// use vax_disassembler::ReadMacro32;
53 /// use std::io::Cursor;
54 ///
55 /// macro_rules! disassemble {
56 /// ($buf: expr, $text: expr) => {
57 /// let instruction = Cursor::new($buf).disassemble().unwrap();
58 /// assert_eq!(&format!("{}", instruction), $text);
59 /// };
60 /// }
61 ///
62 /// disassemble!([0x01], "NOP");
63 /// disassemble!([0x30, 0x00, 0xFE], "BSBW -512");
64 /// disassemble!([0xDE, 0x44, 0x64, 0x55], "MOVAL (R4)[R4], R5");
65 /// disassemble!([0xEF, 0x0C, 0x14, 0x56, 0x57], "EXTZV S^#12, S^#20, R6, R7");
66 /// disassemble!([0x2C, 0x50, 0x61, 0x20, 0x52, 0x63], "MOVC5 R0, (R1), S^#32, R2, (R3)");
67 /// ```
68 fn disassemble(&mut self) -> Result<Instruction> {
69 let mut buf = [0; 2];
70 self.read_exact(&mut buf[0..1])?;
71 let opcode = match buf[0] {
72 0xFD..=0xFF => {
73 self.read_exact(&mut buf[1..2])?;
74 let opcode = u16::from_le_bytes(buf);
75 Opcode::try_from(opcode)?
76 }
77 opcode => Opcode::try_from(opcode as u16)?,
78 };
79 let mut instruction = Instruction::from(opcode);
80 let operands = instruction.operands_mut();
81 for (index, (access, size)) in opcode.operand_specs().iter().enumerate() {
82 operands[index] = self.read_operand(*access, *size)?;
83 }
84 Ok(instruction)
85 }
86}
87
88/// All types that implement `Read` get methods defined in `ReadMacro32` for free.
89impl<R: Read + ?Sized> ReadMacro32 for R {}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 macro_rules! test_disassembly {
96 ($input: expr, $output: expr) => {
97 let mut reader = std::io::Cursor::new($input);
98 let output = reader.disassemble().unwrap();
99 assert_eq!(&format!("{}", output), $output);
100 }
101 }
102
103 #[test]
104 fn simple_tests() {
105 test_disassembly!([0x00], "HALT");
106 test_disassembly!([0x01], "NOP");
107 test_disassembly!([0x02], "REI");
108 test_disassembly!([0x03], "BPT");
109 test_disassembly!([0x05], "RSB");
110 test_disassembly!([0x10, 20], "BSBB 20");
111 test_disassembly!([0x11, 128], "BRB -128");
112 }
113}