1use super::instruction_formats;
44use super::process_instruction;
45use super::{HartState, InstructionProcessor, MemAccessSize, Memory};
46use paste::paste;
47
48#[derive(Debug, PartialEq)]
50pub enum InstructionException {
51 IllegalInstruction(u32, u32),
53 FetchError(u32),
54 LoadAccessFault(u32),
55 StoreAccessFault(u32),
56 AlignmentFault(u32),
57}
58
59pub struct InstructionExecutor<'a, M: Memory> {
61 pub mem: &'a mut M,
63 pub hart_state: &'a mut HartState,
64}
65
66impl<'a, M: Memory> InstructionExecutor<'a, M> {
67 fn execute_reg_reg_op<F>(&mut self, dec_insn: instruction_formats::RType, op: F)
68 where
69 F: Fn(u32, u32) -> u32,
70 {
71 let a = self.hart_state.read_register(dec_insn.rs1);
72 let b = self.hart_state.read_register(dec_insn.rs2);
73 let result = op(a, b);
74 self.hart_state.write_register(dec_insn.rd, result);
75 }
76
77 fn execute_reg_imm_op<F>(&mut self, dec_insn: instruction_formats::IType, op: F)
78 where
79 F: Fn(u32, u32) -> u32,
80 {
81 let a = self.hart_state.read_register(dec_insn.rs1);
82 let b = dec_insn.imm as u32;
83 let result = op(a, b);
84 self.hart_state.write_register(dec_insn.rd, result);
85 }
86
87 fn execute_reg_imm_shamt_op<F>(&mut self, dec_insn: instruction_formats::ITypeShamt, op: F)
88 where
89 F: Fn(u32, u32) -> u32,
90 {
91 let a = self.hart_state.read_register(dec_insn.rs1);
92 let result = op(a, dec_insn.shamt);
93 self.hart_state.write_register(dec_insn.rd, result)
94 }
95
96 fn execute_branch<F>(&mut self, dec_insn: instruction_formats::BType, cond: F) -> bool
98 where
99 F: Fn(u32, u32) -> bool,
100 {
101 let a = self.hart_state.read_register(dec_insn.rs1);
102 let b = self.hart_state.read_register(dec_insn.rs2);
103
104 if cond(a, b) {
105 let new_pc = self.hart_state.pc.wrapping_add(dec_insn.imm as u32);
106 self.hart_state.pc = new_pc;
107 true
108 } else {
109 false
110 }
111 }
112
113 fn execute_load(
114 &mut self,
115 dec_insn: instruction_formats::IType,
116 size: MemAccessSize,
117 signed: bool,
118 ) -> Result<(), InstructionException> {
119 let addr = self
120 .hart_state
121 .read_register(dec_insn.rs1)
122 .wrapping_add(dec_insn.imm as u32);
123
124 let align_mask = match size {
127 MemAccessSize::Byte => 0x0,
128 MemAccessSize::HalfWord => 0x1,
129 MemAccessSize::Word => 0x3,
130 };
131
132 if (addr & align_mask) != 0x0 {
133 return Err(InstructionException::AlignmentFault(addr));
134 }
135
136 let mut load_data = match self.mem.read_mem(addr, size) {
138 Some(d) => d,
139 None => {
140 return Err(InstructionException::LoadAccessFault(addr));
141 }
142 };
143
144 if signed {
146 load_data = (match size {
147 MemAccessSize::Byte => (load_data as i8) as i32,
148 MemAccessSize::HalfWord => (load_data as i16) as i32,
149 MemAccessSize::Word => load_data as i32,
150 }) as u32;
151 }
152
153 self.hart_state.write_register(dec_insn.rd, load_data);
155 Ok(())
156 }
157
158 fn execute_store(
159 &mut self,
160 dec_insn: instruction_formats::SType,
161 size: MemAccessSize,
162 ) -> Result<(), InstructionException> {
163 let addr = self
164 .hart_state
165 .read_register(dec_insn.rs1)
166 .wrapping_add(dec_insn.imm as u32);
167 let data = self.hart_state.read_register(dec_insn.rs2);
168
169 let align_mask = match size {
170 MemAccessSize::Byte => 0x0,
171 MemAccessSize::HalfWord => 0x1,
172 MemAccessSize::Word => 0x3,
173 };
174
175 if (addr & align_mask) != 0x0 {
178 return Err(InstructionException::AlignmentFault(addr));
179 }
180
181 if self.mem.write_mem(addr, size, data) {
183 Ok(())
184 } else {
185 Err(InstructionException::StoreAccessFault(addr))
186 }
187 }
188
189 pub fn step(&mut self) -> Result<(), InstructionException> {
194 self.hart_state.last_register_write = None;
195
196 if let Some(next_insn) = self.mem.read_mem(self.hart_state.pc, MemAccessSize::Word) {
198 let step_result = process_instruction(self, next_insn);
200
201 match step_result {
202 Some(Ok(pc_updated)) => {
203 if !pc_updated {
204 self.hart_state.pc += 4;
206 }
207 Ok(())
208 }
209 Some(Err(e)) => Err(e),
211 None => Err(InstructionException::IllegalInstruction(
213 self.hart_state.pc,
214 next_insn,
215 )),
216 }
217 } else {
218 Err(InstructionException::FetchError(self.hart_state.pc))
220 }
221 }
222}
223
224fn sign_extend_u32(x: u32) -> i64 {
225 (x as i32) as i64
226}
227
228macro_rules! make_alu_op_reg_fn {
230 ($name:ident, $op_fn:expr) => {
231 paste! {
232 fn [<process_ $name>](
233 &mut self,
234 dec_insn: instruction_formats::RType
235 ) -> Self::InstructionResult {
236 self.execute_reg_reg_op(dec_insn, $op_fn);
237
238 Ok(false)
239 }
240 }
241 };
242}
243
244macro_rules! make_alu_op_imm_fn {
245 ($name:ident, $op_fn:expr) => {
246 paste! {
247 fn [<process_ $name i>](
248 &mut self,
249 dec_insn: instruction_formats::IType
250 ) -> Self::InstructionResult {
251 self.execute_reg_imm_op(dec_insn, $op_fn);
252
253 Ok(false)
254 }
255 }
256 };
257}
258
259macro_rules! make_alu_op_imm_shamt_fn {
260 ($name:ident, $op_fn:expr) => {
261 paste! {
262 fn [<process_ $name i>](
263 &mut self,
264 dec_insn: instruction_formats::ITypeShamt
265 ) -> Self::InstructionResult {
266 self.execute_reg_imm_shamt_op(dec_insn, $op_fn);
267
268 Ok(false)
269 }
270 }
271 };
272}
273
274macro_rules! make_alu_op_fns {
275 ($name:ident, $op_fn:expr) => {
276 make_alu_op_reg_fn! {$name, $op_fn}
277 make_alu_op_imm_fn! {$name, $op_fn}
278 };
279}
280
281macro_rules! make_shift_op_fns {
282 ($name:ident, $op_fn:expr) => {
283 make_alu_op_reg_fn! {$name, $op_fn}
284 make_alu_op_imm_shamt_fn! {$name, $op_fn}
285 };
286}
287
288macro_rules! make_branch_op_fn {
289 ($name:ident, $cond_fn:expr) => {
290 paste! {
291 fn [<process_ $name>](
292 &mut self,
293 dec_insn: instruction_formats::BType
294 ) -> Self::InstructionResult {
295 Ok(self.execute_branch(dec_insn, $cond_fn))
296 }
297 }
298 };
299}
300
301macro_rules! make_load_op_fn_inner {
302 ($name:ident, $size:ty, $signed: expr) => {
303 paste! {
304 fn [<process_ $name>](
305 &mut self,
306 dec_insn: instruction_formats::IType
307 ) -> Self::InstructionResult {
308 self.execute_load(dec_insn, $size, $signed)?;
309
310 Ok(false)
311 }
312 }
313 };
314}
315
316macro_rules! make_load_op_fn {
317 ($name:ident, $size:ty, signed) => {
318 make_load_op_fn_inner! {$name, $size, true}
319 };
320 ($name:ident, $size:ty, unsigned) => {
321 make_load_op_fn_inner! {$name, $size, false}
322 };
323}
324
325macro_rules! make_store_op_fn {
326 ($name:ident, $size:ty) => {
327 paste! {
328 fn [<process_ $name>](
329 &mut self,
330 dec_insn: instruction_formats::SType
331 ) -> Self::InstructionResult {
332 self.execute_store(dec_insn, $size)?;
333
334 Ok(false)
335 }
336 }
337 };
338}
339
340impl<'a, M: Memory> InstructionProcessor for InstructionExecutor<'a, M> {
341 type InstructionResult = Result<bool, InstructionException>;
345
346 make_alu_op_fns! {add, |a, b| a.wrapping_add(b)}
347 make_alu_op_reg_fn! {sub, |a, b| a.wrapping_sub(b)}
348 make_alu_op_fns! {slt, |a, b| if (a as i32) < (b as i32) {1} else {0}}
349 make_alu_op_fns! {sltu, |a, b| if a < b {1} else {0}}
350 make_alu_op_fns! {or, |a, b| a | b}
351 make_alu_op_fns! {and, |a, b| a & b}
352 make_alu_op_fns! {xor, |a, b| a ^ b}
353
354 make_shift_op_fns! {sll, |a, b| a << (b & 0x1f)}
355 make_shift_op_fns! {srl, |a, b| a >> (b & 0x1f)}
356 make_shift_op_fns! {sra, |a, b| ((a as i32) >> (b & 0x1f)) as u32}
357
358 fn process_lui(&mut self, dec_insn: instruction_formats::UType) -> Self::InstructionResult {
359 self.hart_state
360 .write_register(dec_insn.rd, dec_insn.imm as u32);
361
362 Ok(false)
363 }
364
365 fn process_auipc(&mut self, dec_insn: instruction_formats::UType) -> Self::InstructionResult {
366 let result = self.hart_state.pc.wrapping_add(dec_insn.imm as u32);
367 self.hart_state.write_register(dec_insn.rd, result);
368
369 Ok(false)
370 }
371
372 make_branch_op_fn! {beq, |a, b| a == b}
373 make_branch_op_fn! {bne, |a, b| a != b}
374 make_branch_op_fn! {blt, |a, b| (a as i32) < (b as i32)}
375 make_branch_op_fn! {bltu, |a, b| a < b}
376 make_branch_op_fn! {bge, |a, b| (a as i32) >= (b as i32)}
377 make_branch_op_fn! {bgeu, |a, b| a >= b}
378
379 make_load_op_fn! {lb, MemAccessSize::Byte, signed}
380 make_load_op_fn! {lbu, MemAccessSize::Byte, unsigned}
381 make_load_op_fn! {lh, MemAccessSize::HalfWord, signed}
382 make_load_op_fn! {lhu, MemAccessSize::HalfWord, unsigned}
383 make_load_op_fn! {lw, MemAccessSize::Word, unsigned}
384
385 make_store_op_fn! {sb, MemAccessSize::Byte}
386 make_store_op_fn! {sh, MemAccessSize::HalfWord}
387 make_store_op_fn! {sw, MemAccessSize::Word}
388
389 fn process_jal(&mut self, dec_insn: instruction_formats::JType) -> Self::InstructionResult {
390 let target_pc = self.hart_state.pc.wrapping_add(dec_insn.imm as u32);
391 self.hart_state
392 .write_register(dec_insn.rd, self.hart_state.pc + 4);
393 self.hart_state.pc = target_pc;
394
395 Ok(true)
396 }
397
398 fn process_jalr(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult {
399 let mut target_pc = self
400 .hart_state
401 .read_register(dec_insn.rs1)
402 .wrapping_add(dec_insn.imm as u32);
403 target_pc &= 0xfffffffe;
404
405 self.hart_state
406 .write_register(dec_insn.rd, self.hart_state.pc + 4);
407 self.hart_state.pc = target_pc;
408
409 Ok(true)
410 }
411
412 make_alu_op_reg_fn! {mul, |a, b| a.wrapping_mul(b)}
413 make_alu_op_reg_fn! {mulh, |a, b| (sign_extend_u32(a).wrapping_mul(sign_extend_u32(b)) >> 32) as u32}
414 make_alu_op_reg_fn! {mulhu, |a, b| (((a as u64).wrapping_mul(b as u64)) >> 32) as u32}
415 make_alu_op_reg_fn! {mulhsu, |a, b| (sign_extend_u32(a).wrapping_mul(b as i64) >> 32) as u32}
416
417 make_alu_op_reg_fn! {div, |a, b| if b == 0 {u32::MAX} else {((a as i32).wrapping_div(b as i32)) as u32}}
418 make_alu_op_reg_fn! {divu, |a, b| if b == 0 {u32::MAX} else {a / b}}
419 make_alu_op_reg_fn! {rem, |a, b| if b == 0 {a} else {((a as i32).wrapping_rem(b as i32)) as u32}}
420 make_alu_op_reg_fn! {remu, |a, b| if b == 0 {a} else {a % b}}
421
422 fn process_fence(&mut self, _dec_insn: instruction_formats::IType) -> Self::InstructionResult {
423 Ok(false)
424 }
425}