1 use core::num::NonZeroUsize;
2 use gdbstub::arch::RegId;
3 
4 /// TI-MSP430 register identifier.
5 ///
6 /// GDB does not provide a XML file for the MSP430.
7 /// The best file to reference is [msp430-tdep.c](https://github.com/bminor/binutils-gdb/blob/master/gdb/msp430-tdep.c).
8 #[derive(Debug, Clone, Copy)]
9 #[non_exhaustive]
10 pub enum Msp430RegId<U> {
11     /// Program Counter (R0)
12     Pc,
13     /// Stack Pointer (R1)
14     Sp,
15     /// Status Register (R2)
16     Sr,
17     /// Constant Generator (R3)
18     Cg,
19     /// General Purpose Registers (R4-R15)
20     Gpr(u8),
21     #[doc(hidden)]
22     _Size(core::marker::PhantomData<U>),
23 }
24 
from_raw_id<U>(id: usize) -> Option<(Msp430RegId<U>, Option<NonZeroUsize>)>25 fn from_raw_id<U>(id: usize) -> Option<(Msp430RegId<U>, Option<NonZeroUsize>)> {
26     let reg = match id {
27         0 => Msp430RegId::Pc,
28         1 => Msp430RegId::Sp,
29         2 => Msp430RegId::Sr,
30         3 => Msp430RegId::Cg,
31         4..=15 => Msp430RegId::Gpr((id as u8) - 4),
32         _ => return None,
33     };
34 
35     let ptrsize = core::mem::size_of::<U>();
36     Some((reg, Some(NonZeroUsize::new(ptrsize)?)))
37 }
38 
39 impl RegId for Msp430RegId<u16> {
from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)>40     fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
41         from_raw_id::<u16>(id)
42     }
43 }
44 
45 impl RegId for Msp430RegId<u32> {
from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)>46     fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
47         from_raw_id::<u32>(id)
48     }
49 }
50 
51 #[cfg(test)]
52 mod tests {
53     use gdbstub::arch::RegId;
54     use gdbstub::arch::Registers;
55 
test<Rs: Registers, RId: RegId>()56     fn test<Rs: Registers, RId: RegId>() {
57         // Obtain the data length written by `gdb_serialize` by passing a custom
58         // closure.
59         let mut serialized_data_len = 0;
60         let counter = |b: Option<u8>| {
61             if b.is_some() {
62                 serialized_data_len += 1;
63             }
64         };
65         Rs::default().gdb_serialize(counter);
66 
67         // The `Msp430Regs` implementation does not increment the size for
68         // the CG register since it will always be the constant zero.
69         serialized_data_len += RId::from_raw_id(3).unwrap().1.unwrap().get();
70 
71         // Accumulate register sizes returned by `from_raw_id`.
72         let mut i = 0;
73         let mut sum_reg_sizes = 0;
74         while let Some((_, size)) = RId::from_raw_id(i) {
75             sum_reg_sizes += size.unwrap().get();
76             i += 1;
77         }
78 
79         assert_eq!(serialized_data_len, sum_reg_sizes);
80     }
81 
82     #[test]
test_msp430()83     fn test_msp430() {
84         test::<crate::msp430::reg::Msp430Regs<u16>, crate::msp430::reg::id::Msp430RegId<u16>>()
85     }
86 
87     #[test]
test_msp430x()88     fn test_msp430x() {
89         test::<crate::msp430::reg::Msp430Regs<u32>, crate::msp430::reg::id::Msp430RegId<u32>>()
90     }
91 }
92