93 lines
3.5 KiB
Rust
93 lines
3.5 KiB
Rust
//! Wraps the [boy] [Insn]-disassembler and extends it to disassemble entire instructions, rather than just single words
|
|
|
|
use boy::cpu::disasm::{Insn, Prefixed};
|
|
use std::iter::{Enumerate, Peekable};
|
|
|
|
pub trait Disassemble: Iterator<Item = u8> + Sized {
|
|
fn disassemble(self) -> Disassembler<Self>;
|
|
}
|
|
|
|
impl<T: Iterator<Item = u8> + Sized> Disassemble for T {
|
|
fn disassemble(self) -> Disassembler<Self> {
|
|
Disassembler::new(self)
|
|
}
|
|
}
|
|
|
|
/// An iterator over some bytes, which prints the disassembly to stdout
|
|
// TODO: parameterize this over a Writer
|
|
pub struct Disassembler<I: Iterator<Item = u8>> {
|
|
bytes: Peekable<Enumerate<I>>,
|
|
}
|
|
|
|
impl<I: Iterator<Item = u8>> Iterator for Disassembler<I> {
|
|
type Item = (usize, String);
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let (index, insn) = self.bytes.next()?;
|
|
Some((index, self.print(insn.into())?))
|
|
}
|
|
}
|
|
|
|
impl<I: Iterator<Item = u8>> Disassembler<I> {
|
|
pub fn new(bytes: I) -> Self {
|
|
Disassembler { bytes: bytes.enumerate().peekable() }
|
|
}
|
|
|
|
pub fn index(&mut self) -> Option<usize> {
|
|
self.bytes.peek().map(|v| v.0)
|
|
}
|
|
|
|
pub fn imm8(&mut self) -> Option<u8> {
|
|
self.bytes.next().map(|v| v.1)
|
|
}
|
|
|
|
pub fn smm8(&mut self) -> Option<i8> {
|
|
self.imm8().map(|b| b as i8)
|
|
}
|
|
|
|
pub fn imm16(&mut self) -> Option<u16> {
|
|
let low = self.imm8()? as u16;
|
|
let high = self.imm8()? as u16;
|
|
Some(high << 8 | low)
|
|
}
|
|
|
|
pub fn smm16(&mut self) -> Option<i16> {
|
|
self.imm16().map(|w| w as i16)
|
|
}
|
|
|
|
pub fn print(&mut self, insn: Insn) -> Option<String> {
|
|
Some(match insn {
|
|
Insn::LdImm(reg) => format!("ld\t{reg}, {:02x}", self.imm8()?),
|
|
Insn::LdImm16(reg) => format!("ld\t{reg}, {:04x}", self.imm16()?),
|
|
Insn::LdAbs => format!("ld\ta, [{:04x}]", self.imm16()?),
|
|
Insn::StAbs => format!("ld\t[{:04x}], a", self.imm16()?),
|
|
Insn::StSpAbs => format!("ld\t[{:04x}], sp", self.imm16()?),
|
|
Insn::LdHlSpRel => format!("ld\thl, sp + {:02x}", self.imm8()?),
|
|
Insn::Ldh => format!("ldh\ta, [ff{:02x}]", self.imm8()?),
|
|
Insn::Sth => format!("ldh\t[ff{:02x}], a", self.imm8()?),
|
|
Insn::Add16SpI => format!("add\tsp, {:02x}", self.imm8()?),
|
|
Insn::AddI => format!("add\ta, {:02x}", self.imm8()?),
|
|
Insn::AdcI => format!("adc\ta, {:02x}", self.imm8()?),
|
|
Insn::SubI => format!("sub\ta, {:02x}", self.imm8()?),
|
|
Insn::SbcI => format!("sbc\ta, {:02x}", self.imm8()?),
|
|
Insn::AndI => format!("and\ta, {:02x}", self.imm8()?),
|
|
Insn::XorI => format!("xor\ta, {:02x}", self.imm8()?),
|
|
Insn::OrI => format!("or\ta, {:02x}", self.imm8()?),
|
|
Insn::CpI => format!("cp\ta, {:02x}", self.imm8()?),
|
|
Insn::Jr => format!("jr\t{0:02x} ({0:02})", self.smm8()?),
|
|
Insn::Jrc(cond) => format!("jr\t{cond}, {:02x} ({0:02})", self.smm8()?),
|
|
Insn::Jp => format!("jp\t{:04x}", self.imm16()?),
|
|
Insn::Jpc(cond) => format!("jp\t{cond}, {:04x}", self.imm16()?),
|
|
Insn::Call => format!("call\t{:04x}", self.imm16()?),
|
|
Insn::Callc(cond) => format!("call\t{cond}, {:04x}", self.imm16()?),
|
|
Insn::PrefixCB => self.print_prefix_cb()?,
|
|
_ => format!("{insn}"),
|
|
})
|
|
}
|
|
|
|
pub fn print_prefix_cb(&mut self) -> Option<String> {
|
|
let prefixed: Prefixed = self.imm8()?.into();
|
|
Some(format!("{prefixed}"))
|
|
}
|
|
}
|