use super::PpcVector;
use core::convert::TryInto;
use gdbstub::arch::Registers;
#[derive(Debug, Default, Clone, PartialEq)]
pub struct PowerPcCommonRegs {
pub r: [u32; 32],
pub f: [f64; 32],
pub pc: u32,
pub msr: u32,
pub cr: u32,
pub lr: u32,
pub ctr: u32,
pub xer: u32,
pub fpscr: u32,
pub vr: [PpcVector; 32],
pub vscr: u32,
pub vrsave: u32,
}
impl Registers for PowerPcCommonRegs {
type ProgramCounter = u32;
fn pc(&self) -> Self::ProgramCounter {
self.pc
}
fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
macro_rules! write_bytes {
($bytes:expr) => {
for b in $bytes {
write_byte(Some(*b))
}
};
}
macro_rules! write_regs {
($($reg:ident),*) => {
$(
write_bytes!(&self.$reg.to_be_bytes());
)*
}
}
for reg in &self.r {
write_bytes!(®.to_be_bytes());
}
for reg in &self.f {
write_bytes!(®.to_be_bytes());
}
write_regs!(pc, msr, cr, lr, ctr, xer, fpscr);
for ® in &self.vr {
let reg: u128 = reg;
write_bytes!(®.to_be_bytes());
}
write_regs!(vscr, vrsave);
}
fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
if bytes.len() < 0x3a4 {
return Err(());
}
let mut regs = bytes[0..0x80]
.chunks_exact(4)
.map(|x| u32::from_be_bytes(x.try_into().unwrap()));
for reg in &mut self.r {
*reg = regs.next().ok_or(())?;
}
let mut regs = bytes[0x80..0x180]
.chunks_exact(8)
.map(|x| f64::from_be_bytes(x.try_into().unwrap()));
for reg in &mut self.f {
*reg = regs.next().ok_or(())?;
}
macro_rules! parse_regs {
($start:literal..$end:literal, $($reg:ident),*) => {
let mut regs = bytes[$start..$end]
.chunks_exact(4)
.map(|x| u32::from_be_bytes(x.try_into().unwrap()));
$(
self.$reg = regs.next().ok_or(())?;
)*
}
}
parse_regs!(0x180..0x19c, pc, msr, cr, lr, ctr, xer, fpscr);
let mut regs = bytes[0x19c..0x39c]
.chunks_exact(0x10)
.map(|x| u128::from_be_bytes(x.try_into().unwrap()));
for reg in &mut self.vr {
*reg = regs.next().ok_or(())?;
}
parse_regs!(0x39c..0x3a4, vscr, vrsave);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ppc_core_round_trip() {
let regs_before = PowerPcCommonRegs {
r: [1; 32],
pc: 2,
msr: 3,
cr: 4,
lr: 5,
ctr: 6,
xer: 7,
fpscr: 8,
f: [9.0; 32],
vr: [52; 32],
vrsave: 10,
vscr: 11,
};
let mut data = vec![];
regs_before.gdb_serialize(|x| {
data.push(x.unwrap_or(b'x'));
});
assert_eq!(data.len(), 0x3a4);
let mut regs_after = PowerPcCommonRegs::default();
regs_after.gdb_deserialize(&data).unwrap();
assert_eq!(regs_before, regs_after);
}
}