1 use super::PpcVector;
2 use core::convert::TryInto;
3 use gdbstub::arch::Registers;
4 
5 /// 32-bit PowerPC core registers, FPU registers, and AltiVec SIMD registers.
6 ///
7 /// Sources:
8 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/powerpc-altivec32.xml>
9 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/power-core.xml>
10 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/power-fpu.xml>
11 /// * <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/rs6000/power-altivec.xml>
12 #[derive(Debug, Default, Clone, PartialEq)]
13 pub struct PowerPcCommonRegs {
14     /// General purpose registers
15     pub r: [u32; 32],
16     /// Floating Point registers
17     pub f: [f64; 32],
18     /// Program counter
19     pub pc: u32,
20     /// Machine state
21     pub msr: u32,
22     /// Condition register
23     pub cr: u32,
24     /// Link register
25     pub lr: u32,
26     /// Count register
27     pub ctr: u32,
28     /// Integer exception register
29     pub xer: u32,
30     /// Floating-point status and control register
31     pub fpscr: u32,
32     /// Vector registers
33     pub vr: [PpcVector; 32],
34     /// Vector status and control register
35     pub vscr: u32,
36     /// Vector context save register
37     pub vrsave: u32,
38 }
39 
40 impl Registers for PowerPcCommonRegs {
41     type ProgramCounter = u32;
42 
pc(&self) -> Self::ProgramCounter43     fn pc(&self) -> Self::ProgramCounter {
44         self.pc
45     }
46 
gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>))47     fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
48         macro_rules! write_bytes {
49             ($bytes:expr) => {
50                 for b in $bytes {
51                     write_byte(Some(*b))
52                 }
53             };
54         }
55 
56         macro_rules! write_regs {
57             ($($reg:ident),*) => {
58                 $(
59                     write_bytes!(&self.$reg.to_be_bytes());
60                 )*
61             }
62         }
63 
64         for reg in &self.r {
65             write_bytes!(&reg.to_be_bytes());
66         }
67 
68         for reg in &self.f {
69             write_bytes!(&reg.to_be_bytes());
70         }
71 
72         write_regs!(pc, msr, cr, lr, ctr, xer, fpscr);
73 
74         for &reg in &self.vr {
75             let reg: u128 = reg;
76             write_bytes!(&reg.to_be_bytes());
77         }
78 
79         write_regs!(vscr, vrsave);
80     }
81 
gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()>82     fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
83         if bytes.len() < 0x3a4 {
84             return Err(());
85         }
86 
87         let mut regs = bytes[0..0x80]
88             .chunks_exact(4)
89             .map(|x| u32::from_be_bytes(x.try_into().unwrap()));
90 
91         for reg in &mut self.r {
92             *reg = regs.next().ok_or(())?;
93         }
94 
95         let mut regs = bytes[0x80..0x180]
96             .chunks_exact(8)
97             .map(|x| f64::from_be_bytes(x.try_into().unwrap()));
98 
99         for reg in &mut self.f {
100             *reg = regs.next().ok_or(())?;
101         }
102 
103         macro_rules! parse_regs {
104             ($start:literal..$end:literal, $($reg:ident),*) => {
105                 let mut regs = bytes[$start..$end]
106                     .chunks_exact(4)
107                     .map(|x| u32::from_be_bytes(x.try_into().unwrap()));
108                 $(
109                     self.$reg = regs.next().ok_or(())?;
110                 )*
111             }
112         }
113 
114         parse_regs!(0x180..0x19c, pc, msr, cr, lr, ctr, xer, fpscr);
115 
116         let mut regs = bytes[0x19c..0x39c]
117             .chunks_exact(0x10)
118             .map(|x| u128::from_be_bytes(x.try_into().unwrap()));
119 
120         for reg in &mut self.vr {
121             *reg = regs.next().ok_or(())?;
122         }
123 
124         parse_regs!(0x39c..0x3a4, vscr, vrsave);
125 
126         Ok(())
127     }
128 }
129 
130 #[cfg(test)]
131 mod tests {
132     use super::*;
133 
134     #[test]
ppc_core_round_trip()135     fn ppc_core_round_trip() {
136         let regs_before = PowerPcCommonRegs {
137             r: [1; 32],
138             pc: 2,
139             msr: 3,
140             cr: 4,
141             lr: 5,
142             ctr: 6,
143             xer: 7,
144             fpscr: 8,
145             f: [9.0; 32],
146             vr: [52; 32],
147             vrsave: 10,
148             vscr: 11,
149         };
150 
151         let mut data = vec![];
152 
153         regs_before.gdb_serialize(|x| {
154             data.push(x.unwrap_or(b'x'));
155         });
156 
157         assert_eq!(data.len(), 0x3a4);
158 
159         let mut regs_after = PowerPcCommonRegs::default();
160         regs_after.gdb_deserialize(&data).unwrap();
161 
162         assert_eq!(regs_before, regs_after);
163     }
164 }
165