| 6 | use crate::error::VmError; |
| 7 | |
| 8 | pub fn writeback( |
| 9 | result: MemResult, |
| 10 | regs: &mut Registers, |
| 11 | csrs: &mut CsrFile, |
| 12 | ) -> Result<u64, VmError> { |
| 13 | match result { |
| 14 | MemResult::WriteInt { rd, val, next_pc } => { |
| 15 | regs.write_x(rd, val); |
| 16 | Ok(next_pc) |
| 17 | } |
| 18 | MemResult::WriteFp { rd, bits, next_pc } => { |
| 19 | regs.write_f_bits(rd, bits); |
| 20 | Ok(next_pc) |
| 21 | } |
| 22 | MemResult::WriteIntFlags { |
| 23 | rd, |
| 24 | val, |
| 25 | fflags, |
| 26 | next_pc, |
| 27 | } => { |
| 28 | csrs.accumulate_fflags(fflags); |
| 29 | regs.write_x(rd, val); |
| 30 | Ok(next_pc) |
| 31 | } |
| 32 | MemResult::WriteFpFlags { |
| 33 | rd, |
| 34 | bits, |
| 35 | fflags, |
| 36 | next_pc, |
| 37 | } => { |
| 38 | csrs.accumulate_fflags(fflags); |
| 39 | regs.write_f_bits(rd, bits); |
| 40 | Ok(next_pc) |
| 41 | } |
| 42 | MemResult::Jump { next_pc } => Ok(next_pc), |
| 43 | MemResult::Fence { next_pc } => Ok(next_pc), |
| 44 | MemResult::FenceI { next_pc } => Ok(next_pc), |
| 45 | MemResult::Csr { |
| 46 | funct3, |
| 47 | rd, |
| 48 | rs1_uimm, |
| 49 | csr, |
| 50 | operand, |
| 51 | old_val: _, |
| 52 | next_pc, |
| 53 | } => { |
| 54 | // Re-read CSR at WB time for architectural correctness (e.g. instret |
| 55 | // increments between EX and WB; old_val is used only for forwarding). |
| 56 | let old = csrs.read(csr)?; |
| 57 | |
| 58 | let (new_val, do_write) = match funct3 { |
| 59 | 1 => (operand, true), // CSRRW |
| 60 | 2 => (old | operand, rs1_uimm != 0), // CSRRS |
| 61 | 3 => (old & !operand, rs1_uimm != 0), // CSRRC |
| 62 | 5 => (operand, true), // CSRRWI |
| 63 | 6 => (old | operand, rs1_uimm != 0), // CSRRSI |
| 64 | 7 => (old & !operand, rs1_uimm != 0), // CSRRCI |
| 65 | _ => return Err(VmError::IllegalInstruction(funct3 as u32)), |