1use std::fmt;
2
3#[derive(Copy, Clone, Debug, PartialEq)]
4#[repr(u8)]
5pub enum RegisterType {
6 Zero = 0,
7 At,
8 V0,
9 V1,
10 A0,
11 A1,
12 A2,
13 A3,
14 T0,
15 T1,
16 T2,
17 T3,
18 T4,
19 T5,
20 T6,
21 T7,
22 S0,
23 S1,
24 S2,
25 S3,
26 S4,
27 S5,
28 S6,
29 S7,
30 T8,
31 T9,
32 K0,
33 K1,
34 Gp,
35 Sp,
36 Fp,
37 Ra,
38 Pc,
39 Hi,
40 Lo,
41}
42
43const REG_TYPES: [RegisterType; 35] = [
44 RegisterType::Zero,
45 RegisterType::At,
46 RegisterType::V0,
47 RegisterType::V1,
48 RegisterType::A0,
49 RegisterType::A1,
50 RegisterType::A2,
51 RegisterType::A3,
52 RegisterType::T0,
53 RegisterType::T1,
54 RegisterType::T2,
55 RegisterType::T3,
56 RegisterType::T4,
57 RegisterType::T5,
58 RegisterType::T6,
59 RegisterType::T7,
60 RegisterType::S0,
61 RegisterType::S1,
62 RegisterType::S2,
63 RegisterType::S3,
64 RegisterType::S4,
65 RegisterType::S5,
66 RegisterType::S6,
67 RegisterType::S7,
68 RegisterType::T8,
69 RegisterType::T9,
70 RegisterType::K0,
71 RegisterType::K1,
72 RegisterType::Gp,
73 RegisterType::Sp,
74 RegisterType::Fp,
75 RegisterType::Ra,
76 RegisterType::Pc,
77 RegisterType::Hi,
78 RegisterType::Lo,
79];
80
81pub const ALL_REG_NAMES: [&str; 35] = [
82 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
83 "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp",
84 "ra", "pc", "hi", "lo",
85];
86
87impl From<u8> for RegisterType {
88 fn from(value: u8) -> Self {
89 REG_TYPES[value as usize]
90 }
91}
92
93impl fmt::Display for RegisterType {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 f.write_str(ALL_REG_NAMES[*self as usize])
96 }
97}
98
99pub struct Registers {
100 pub(crate) general_regs: [u32; 32],
101 pub(crate) pc: u32,
102 pub(crate) hi: u32,
103 pub(crate) lo: u32,
104
105 load_delay_slot_running: Option<(u8, u32)>,
108 load_delay_slot_committing: Option<(u8, u32)>,
111}
112
113impl Registers {
114 pub(crate) fn new() -> Self {
115 Self {
116 general_regs: [0; 32],
117 load_delay_slot_running: None,
118 load_delay_slot_committing: None,
119
120 pc: 0xBFC00000,
121 hi: 0,
122 lo: 0,
123 }
124 }
125
126 #[inline]
127 pub fn read(&self, ty: RegisterType) -> u32 {
128 match ty {
129 RegisterType::Zero => 0,
130 RegisterType::Pc => self.pc,
131 RegisterType::Hi => self.hi,
132 RegisterType::Lo => self.lo,
133 _ => self.read_general(ty as u8),
134 }
135 }
136
137 #[inline]
138 pub fn write(&mut self, ty: RegisterType, data: u32) {
139 match ty {
140 RegisterType::Zero => {}
141 RegisterType::Pc => self.pc = data,
142 RegisterType::Hi => self.hi = data,
143 RegisterType::Lo => self.lo = data,
144 _ => self.write_general(ty as u8, data),
145 }
146 }
147
148 #[inline]
149 pub(crate) fn read_general(&self, idx: u8) -> u32 {
150 assert!(idx < 32);
151 if let Some((i, _)) = self.load_delay_slot_committing {
152 if idx == i {
153 log::warn!(
154 "Reg `{}` is still in the load delay slot, reading old value, could be a bug",
155 REG_TYPES[idx as usize]
156 );
157 }
158 }
159 self.general_regs[idx as usize]
160 }
161
162 #[inline]
165 pub(crate) fn read_general_latest(&self, idx: u8) -> u32 {
166 assert!(idx < 32);
167 if let Some((i, d)) = self.load_delay_slot_committing {
168 if idx == i {
169 return d;
170 }
171 }
172 self.general_regs[idx as usize]
173 }
174
175 #[inline]
176 pub(crate) fn write_general(&mut self, idx: u8, data: u32) {
177 assert!(idx < 32);
178 self.general_regs[idx as usize] = data;
179 self.general_regs[0] = 0;
180
181 if let Some((i, _)) = self.load_delay_slot_committing {
184 if i == idx {
185 self.load_delay_slot_committing = None;
186 }
187 }
188 }
189
190 #[inline]
191 pub(crate) fn write_delayed(&mut self, idx: u8, data: u32) {
192 assert!(idx < 32);
193 assert!(self.load_delay_slot_running.is_none());
194 if let Some((i, _)) = self.load_delay_slot_committing {
196 if i == idx {
197 self.load_delay_slot_committing = None;
198 }
199 }
200 self.load_delay_slot_running = Some((idx, data));
201 }
202
203 #[inline]
204 pub(crate) fn handle_delayed_load(&mut self) {
205 if let Some((idx, data)) = self.load_delay_slot_committing.take() {
206 self.write_general(idx, data);
207 }
208 self.load_delay_slot_committing = self.load_delay_slot_running.take();
209 }
210
211 #[inline]
212 pub(crate) fn flush_delayed_load(&mut self) {
213 self.handle_delayed_load();
214 self.handle_delayed_load();
215 }
216
217 #[inline]
220 pub(crate) fn write_ra(&mut self, data: u32) {
221 self.write_general(RegisterType::Ra as u8, data);
223 }
224}
225
226impl std::fmt::Debug for Registers {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 writeln!(f, "Registers:")?;
229
230 writeln!(
232 f,
233 "pc: {:08X}\t{:>4}: {:08X}",
234 self.pc,
235 RegisterType::from(1),
236 self.general_regs[1]
237 )?;
238 writeln!(f, "hi: {:08X}\tlo: {:08X}", self.hi, self.lo)?;
240
241 for i in 2..32 / 2 {
243 writeln!(
244 f,
245 "{:>4}: {:08X}\t{:>4}: {:08X}",
246 RegisterType::from(i),
247 self.general_regs[i as usize],
248 RegisterType::from(i + 32 / 2 - 2),
250 self.general_regs[(i + 32 / 2 - 2) as usize]
251 )?;
252 }
253 writeln!(
255 f,
256 "{:>4}: {:08X}\t{:>4}: {:08X}",
257 RegisterType::from(30),
258 self.general_regs[30],
259 RegisterType::from(31),
260 self.general_regs[31]
261 )
262 }
263}