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