1 use core::num::NonZeroUsize;
2 use gdbstub::arch::RegId;
3 
4 /// MIPS register identifier.
5 #[derive(Debug, Clone, Copy)]
6 #[non_exhaustive]
7 pub enum MipsRegId<U> {
8     /// General purpose registers (R0-R31)
9     Gpr(u8),
10     /// Status register
11     Status,
12     /// Low register
13     Lo,
14     /// High register
15     Hi,
16     /// Bad Virtual Address register
17     Badvaddr,
18     /// Exception Cause register
19     Cause,
20     /// Program Counter
21     Pc,
22     /// Floating point registers (F0-F31)
23     Fpr(u8),
24     /// Floating-point Control Status register
25     Fcsr,
26     /// Floating-point Implementation Register
27     Fir,
28     /// High 1 register
29     Hi1,
30     /// Low 1 register
31     Lo1,
32     /// High 2 register
33     Hi2,
34     /// Low 2 register
35     Lo2,
36     /// High 3 register
37     Hi3,
38     /// Low 3 register
39     Lo3,
40     /// DSP Control register
41     Dspctl,
42     /// Restart register
43     Restart,
44     #[doc(hidden)]
45     _Size(core::marker::PhantomData<U>),
46 }
47 
from_raw_id<U>(id: usize) -> Option<(MipsRegId<U>, Option<NonZeroUsize>)>48 fn from_raw_id<U>(id: usize) -> Option<(MipsRegId<U>, Option<NonZeroUsize>)> {
49     let reg = match id {
50         0..=31 => MipsRegId::Gpr(id as u8),
51         32 => MipsRegId::Status,
52         33 => MipsRegId::Lo,
53         34 => MipsRegId::Hi,
54         35 => MipsRegId::Badvaddr,
55         36 => MipsRegId::Cause,
56         37 => MipsRegId::Pc,
57         38..=69 => MipsRegId::Fpr((id as u8) - 38),
58         70 => MipsRegId::Fcsr,
59         71 => MipsRegId::Fir,
60         72 => MipsRegId::Hi1,
61         73 => MipsRegId::Lo1,
62         74 => MipsRegId::Hi2,
63         75 => MipsRegId::Lo2,
64         76 => MipsRegId::Hi3,
65         77 => MipsRegId::Lo3,
66         // `MipsRegId::Dspctl` is the only register that will always be 4 bytes wide
67         78 => return Some((MipsRegId::Dspctl, Some(NonZeroUsize::new(4)?))),
68         79 => MipsRegId::Restart,
69         _ => return None,
70     };
71 
72     let ptrsize = core::mem::size_of::<U>();
73     Some((reg, Some(NonZeroUsize::new(ptrsize)?)))
74 }
75 
76 impl RegId for MipsRegId<u32> {
from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)>77     fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
78         from_raw_id::<u32>(id)
79     }
80 }
81 
82 impl RegId for MipsRegId<u64> {
from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)>83     fn from_raw_id(id: usize) -> Option<(Self, Option<NonZeroUsize>)> {
84         from_raw_id::<u64>(id)
85     }
86 }
87 
88 #[cfg(test)]
89 mod tests {
90     use gdbstub::arch::RegId;
91     use gdbstub::arch::Registers;
92 
test<Rs: Registers, RId: RegId>()93     fn test<Rs: Registers, RId: RegId>() {
94         // Obtain the data length written by `gdb_serialize` by passing a custom
95         // closure.
96         let mut serialized_data_len = 0;
97         let counter = |b: Option<u8>| {
98             if b.is_some() {
99                 serialized_data_len += 1;
100             }
101         };
102         Rs::default().gdb_serialize(counter);
103 
104         // Accumulate register sizes returned by `from_raw_id`.
105         let mut i = 0;
106         let mut sum_reg_sizes = 0;
107         while let Some((_, size)) = RId::from_raw_id(i) {
108             sum_reg_sizes += size.unwrap().get();
109             i += 1;
110         }
111 
112         assert_eq!(serialized_data_len, sum_reg_sizes);
113     }
114 
115     #[test]
test_mips32()116     fn test_mips32() {
117         test::<crate::mips::reg::MipsCoreRegsWithDsp<u32>, crate::mips::reg::id::MipsRegId<u32>>()
118     }
119 
120     #[test]
test_mips64()121     fn test_mips64() {
122         test::<crate::mips::reg::MipsCoreRegsWithDsp<u64>, crate::mips::reg::id::MipsRegId<u64>>()
123     }
124 }
125