diff --git a/disasm/src/disasm.rs b/disasm/src/disasm.rs index e3f1a9d..fbda4ad 100644 --- a/disasm/src/disasm.rs +++ b/disasm/src/disasm.rs @@ -354,7 +354,7 @@ impl ParsedIns { /// Returns an iterator over the arguments of the instruction, /// stopping at the first [Argument::None]. #[inline] - pub fn args_iter(&self) -> impl Iterator { + pub fn args_iter(&self) -> impl Iterator { self.args.iter().take_while(|x| !matches!(x, Argument::None)) } } @@ -405,3 +405,40 @@ impl LowerHex for SignedHexLiteral { } } } + +pub struct InsIter<'a> { + address: u32, + data: &'a [u8], +} + +impl<'a> InsIter<'a> { + pub fn new(data: &'a [u8], address: u32) -> Self { + Self { address, data } + } + + pub fn address(&self) -> u32 { + self.address + } + + pub fn data(&self) -> &'a [u8] { + self.data + } +} + +impl<'a> Iterator for InsIter<'a> { + type Item = (u32, Ins); + + fn next(&mut self) -> Option { + if self.data.len() < 4 { + return None; + } + + // SAFETY: The slice is guaranteed to be at least 4 bytes long. + let chunk = unsafe { *(self.data.as_ptr() as *const [u8; 4]) }; + let ins = Ins::new(u32::from_be_bytes(chunk)); + let addr = self.address; + self.address += 4; + self.data = &self.data[4..]; + Some((addr, ins)) + } +} diff --git a/disasm/src/lib.rs b/disasm/src/lib.rs index a22b800..96176c5 100644 --- a/disasm/src/lib.rs +++ b/disasm/src/lib.rs @@ -3,7 +3,7 @@ mod disasm; mod generated; pub use disasm::{ - Argument, BranchDest, CRBit, CRField, Ins, Offset, OpaqueU, ParsedIns, Simm, Uimm, FPR, GPR, - GQR, SPR, SR, + Argument, BranchDest, CRBit, CRField, Ins, InsIter, Offset, OpaqueU, ParsedIns, Simm, Uimm, + FPR, GPR, GQR, SPR, SR, }; pub use generated::{Arguments, Opcode}; diff --git a/disasm/tests/test_disasm.rs b/disasm/tests/test_disasm.rs index 7c0666f..7ea9427 100644 --- a/disasm/tests/test_disasm.rs +++ b/disasm/tests/test_disasm.rs @@ -1,4 +1,4 @@ -use ppc750cl::{Argument, Ins, Opcode, FPR, GPR}; +use ppc750cl::{Argument, Ins, InsIter, Opcode, FPR, GPR}; macro_rules! assert_asm { ($ins:ident, $disasm:literal) => {{ @@ -1137,3 +1137,11 @@ fn test_ins_xori() { fn test_ins_xoris() { assert_asm!(0x6E3D8000, "xoris r29, r17, 0x8000"); } + +#[test] +fn test_ins_iter() { + let mut iter = InsIter::new(&[0x7C, 0x43, 0x22, 0x14, 0x7E, 0x1A, 0x02, 0xA6, 0xFF], 0); + assert_eq!(iter.next(), Some((0, Ins::new(0x7C432214)))); + assert_eq!(iter.next(), Some((4, Ins::new(0x7E1A02A6)))); + assert_eq!(iter.next(), None); +}