#![doc = include_str!("../README.md")]
#![forbid(future_incompatible)]
#![warn(missing_docs, missing_debug_implementations, bare_trait_objects)]
pub mod error;
pub mod opcode;
pub mod operand;
use std::io::Read;
pub use crate::{
error::{Error, Result},
opcode::{
AccessType,
DataType,
DataValue,
ReadDataValue,
WriteDataValue,
Instruction,
Opcode,
},
operand::{IndexedOperand, Operand, ReadOperand, Register},
};
pub trait ReadMacro32: Read {
fn disassemble(&mut self) -> Result<Instruction> {
let mut buf = [0; 2];
self.read_exact(&mut buf[0..1])?;
let opcode = match buf[0] {
0xFD..=0xFF => {
self.read_exact(&mut buf[1..2])?;
let opcode = u16::from_le_bytes(buf);
Opcode::try_from(opcode)?
}
opcode => Opcode::try_from(opcode as u16)?,
};
let mut instruction = Instruction::from(opcode);
let operands = instruction.operands_mut();
for (index, (access, size)) in opcode.operand_specs().iter().enumerate() {
operands[index] = self.read_operand(*access, *size)?;
}
Ok(instruction)
}
}
impl<R: Read + ?Sized> ReadMacro32 for R {}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! test_disassembly {
($input: expr, $output: expr) => {
let mut reader = std::io::Cursor::new($input);
let output = reader.disassemble().unwrap();
assert_eq!(&format!("{}", output), $output);
}
}
#[test]
fn simple_tests() {
test_disassembly!([0x00], "HALT");
test_disassembly!([0x01], "NOP");
test_disassembly!([0x02], "REI");
test_disassembly!([0x03], "BPT");
test_disassembly!([0x05], "RSB");
test_disassembly!([0x10, 20], "BSBB 20");
test_disassembly!([0x11, 128], "BRB -128");
}
}