♻️ Simplified fp_instruction

This commit is contained in:
François Autin 2023-03-29 15:25:58 +02:00
parent 2e41758a52
commit 72f560f3ec
No known key found for this signature in database
GPG Key ID: 343F5D382E1DD77C

View File

@ -283,18 +283,18 @@ impl Machine {
// Treatment for: STORE INSTRUCTIONS // Treatment for: STORE INSTRUCTIONS
RISCV_ST => self.store_instruction(inst), RISCV_ST => self.store_instruction(inst),
// Treatment for: OPI INSTRUCTIONS
RISCV_OPI => self.opi_instruction(inst),
// Treatment for: OP INSTRUCTIONS // Treatment for: OP INSTRUCTIONS
RISCV_OP => self.op_instruction(inst), RISCV_OP => self.op_instruction(inst),
// Treatment for OPIW INSTRUCTIONS // Treatment for: OPI INSTRUCTIONS
RISCV_OPIW => self.opiw_instruction(inst), RISCV_OPI => self.opi_instruction(inst),
// Treatment for: OPW INSTRUCTIONS // Treatment for: OPW INSTRUCTIONS
RISCV_OPW => self.opw_instruction(inst), RISCV_OPW => self.opw_instruction(inst),
// Treatment for OPIW INSTRUCTIONS
RISCV_OPIW => self.opiw_instruction(inst),
// Treatment for: FLOATING POINT INSTRUCTIONS // Treatment for: FLOATING POINT INSTRUCTIONS
RISCV_FP => self.fp_instruction(inst), RISCV_FP => self.fp_instruction(inst),
@ -315,7 +315,7 @@ impl Machine {
RISCV_BR_BGE => |a, b| a >= b, RISCV_BR_BGE => |a, b| a >= b,
RISCV_BR_BLTU => |a, b| a < b, RISCV_BR_BLTU => |a, b| a < b,
RISCV_BR_BGEU => |a, b| a >= b, RISCV_BR_BGEU => |a, b| a >= b,
_ => unreachable!() _ => Err(format!("Unreachable in branch_instruction match! Instruction was {:?}", inst))?
}; };
let rs1 = self.int_reg.get_reg(inst.rs1); let rs1 = self.int_reg.get_reg(inst.rs1);
let rs2 = self.int_reg.get_reg(inst.rs2); let rs2 = self.int_reg.get_reg(inst.rs2);
@ -337,7 +337,7 @@ impl Machine {
RISCV_LD_LH | RISCV_LD_LHU => set_reg(inst.rd, 2), RISCV_LD_LH | RISCV_LD_LHU => set_reg(inst.rd, 2),
RISCV_LD_LW | RISCV_LD_LWU => set_reg(inst.rd, 4), RISCV_LD_LW | RISCV_LD_LWU => set_reg(inst.rd, 4),
RISCV_LD_LD => set_reg(inst.rd, 8), RISCV_LD_LD => set_reg(inst.rd, 8),
_ => Err(format!("In LD switch case, this should never happen... Instr was {}", inst.value).as_str())? _ => Err(format!("Unreachable in load_instruction match! Instruction was {:?}", inst))?
} }
} }
@ -356,7 +356,7 @@ impl Machine {
RISCV_ST_STH => store(2), RISCV_ST_STH => store(2),
RISCV_ST_STW => store(4), RISCV_ST_STW => store(4),
RISCV_ST_STD => store(8), RISCV_ST_STD => store(8),
_ => Err(format!("In ST switch case, this should never happen... Instr was {}", inst.value).as_str())? _ => Err(format!("Unreachable in store_instruction match! Instruction was {:?}", inst))?
} }
} }
@ -381,7 +381,7 @@ impl Machine {
} else { } else {
compute(&core::ops::Shr::shr, rs1, shamt) compute(&core::ops::Shr::shr, rs1, shamt)
} }
_ => Err(format!("In OPI switch case, this should never happen... Instr was %x\n {}", inst.value))? _ => Err(format!("Unreachable in opi_instruction match! Instruction was {:?}", inst))?
} }
} }
@ -412,7 +412,7 @@ impl Machine {
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64); self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64);
}, },
RISCV_OP_M_DIV => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) / self.int_reg.get_reg(inst.rs2)), RISCV_OP_M_DIV => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) / self.int_reg.get_reg(inst.rs2)),
_ => panic!("RISCV_OP : funct7 = 1 (Multiplication) :: Error\n") _ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
} }
} else { } else {
match inst.funct3 { match inst.funct3 {
@ -440,7 +440,7 @@ impl Machine {
RISCV_OP_SR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) >> self.int_reg.get_reg(inst.rs2)), // RISCV_OP_SR_SRL inaccessible RISCV_OP_SR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) >> self.int_reg.get_reg(inst.rs2)), // RISCV_OP_SR_SRL inaccessible
RISCV_OP_OR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) | self.int_reg.get_reg(inst.rs2)), RISCV_OP_OR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) | self.int_reg.get_reg(inst.rs2)),
RISCV_OP_AND => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) & self.int_reg.get_reg(inst.rs2)), RISCV_OP_AND => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) & self.int_reg.get_reg(inst.rs2)),
_ => panic!("RISCV_OP undefined case\n") _ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
} }
} }
Ok(()) Ok(())
@ -453,7 +453,7 @@ impl Machine {
RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64, RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64,
RISCV_OPIW_SLLIW => local_data << inst.shamt, RISCV_OPIW_SLLIW => local_data << inst.shamt,
RISCV_OPIW_SRW => (local_data >> inst.shamt) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.shamt as usize] as i64 } else { 1 }, RISCV_OPIW_SRW => (local_data >> inst.shamt) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.shamt as usize] as i64 } else { 1 },
_ => Err("In OPI switch case, this should never happen... Instr was {}\n")?, _ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
}; };
self.int_reg.set_reg(inst.rd, result); self.int_reg.set_reg(inst.rd, result);
Ok(()) Ok(())
@ -474,7 +474,7 @@ impl Machine {
RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned), RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned),
RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b), RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b),
RISCV_OPW_M_REMUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned % local_data_b_unsigned), RISCV_OPW_M_REMUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned % local_data_b_unsigned),
_ => panic!("this instruction ({}) doesn't exists", inst.value) _ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
} }
} else { // others rv64 OPW operations } else { // others rv64 OPW operations
let local_dataa = self.int_reg.get_reg(inst.rs1) & 0xffffffff; let local_dataa = self.int_reg.get_reg(inst.rs1) & 0xffffffff;
@ -492,82 +492,119 @@ impl Machine {
} else { // SRAW } else { // SRAW
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f)) self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f))
}, },
_ => panic!("this instruction ({}) doesn't exist", inst.value) _ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
} }
} }
Ok(()) Ok(())
} }
/// Executes simple RISC-V floating point instructions on the machine /// Executes simple RISC-V floating point instructions on the machine.
///
/// See Risc-V Spec v2.2 Chapter 8: “F” Standard Extension for Single-Precision Floating-Point, Version 2.0.
fn fp_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { fn fp_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
let mut set_reg = |operation: &dyn Fn (f32, f32) -> f32| {
let a = self.fp_reg.get_reg(inst.rs1);
let b = self.fp_reg.get_reg(inst.rs2);
self.fp_reg.set_reg(inst.rd, operation(a, b));
Ok(())
};
match inst.funct7 { match inst.funct7 {
RISCV_FP_ADD => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) + self.fp_reg.get_reg(inst.rs2)), RISCV_FP_ADD => set_reg(&core::ops::Add::add),
RISCV_FP_SUB => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) - self.fp_reg.get_reg(inst.rs2)), RISCV_FP_SUB => set_reg(&core::ops::Sub::sub),
RISCV_FP_MUL => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) * self.fp_reg.get_reg(inst.rs2)), RISCV_FP_MUL => set_reg(&core::ops::Mul::mul),
RISCV_FP_DIV => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) / self.fp_reg.get_reg(inst.rs2)), RISCV_FP_DIV => set_reg(&core::ops::Div::div),
RISCV_FP_SQRT => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1).sqrt()), RISCV_FP_SQRT => { self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1).sqrt()); Ok(()) },
RISCV_FP_FSGN => { RISCV_FP_FSGN => self.fp_fsgn_instruction(inst),
RISCV_FP_MINMAX => self.fp_minmax_instruction(inst),
RISCV_FP_FCVTW => self.fp_fcvtw_instruction(inst),
RISCV_FP_FCVTS => self.fp_fcvts_instruction(inst),
RISCV_FP_FMVW => self.fp_fmvw_instruction(inst),
RISCV_FP_FMVXFCLASS => self.fp_fmvxfclass_instruction(inst),
RISCV_FP_FCMP => self.fp_fcmp_instruction(inst),
_ => Err(format!("Unreachable in fp_instruction match! Instruction was {:?}", inst))?
}
}
/// Executes RISC-V sign-injection instruction on floating point values on the machine.
fn fp_fsgn_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
let local_float = self.fp_reg.get_reg(inst.rs1); let local_float = self.fp_reg.get_reg(inst.rs1);
match inst.funct3 { match inst.funct3 {
RISCV_FP_FSGN_J => if self.fp_reg.get_reg(inst.rs2) < 0f32 { RISCV_FP_FSGN_J => if self.fp_reg.get_reg(inst.rs2) < 0f32 {
self.fp_reg.set_reg(inst.rd, -local_float) self.fp_reg.set_reg(inst.rd, -local_float);
} else { } else {
self.fp_reg.set_reg(inst.rd, local_float) self.fp_reg.set_reg(inst.rd, local_float);
}, },
RISCV_FP_FSGN_JN => if self.fp_reg.get_reg(inst.rs2) < 0f32 { RISCV_FP_FSGN_JN => if self.fp_reg.get_reg(inst.rs2) < 0f32 {
self.fp_reg.set_reg(inst.rd, local_float) self.fp_reg.set_reg(inst.rd, local_float);
} else { } else {
self.fp_reg.set_reg(inst.rd, -local_float) self.fp_reg.set_reg(inst.rd, -local_float);
}, },
RISCV_FP_FSGN_JX => if (self.fp_reg.get_reg(inst.rs2) < 0.0 && self.fp_reg.get_reg(inst.rs1) >= 0.0) || RISCV_FP_FSGN_JX => if (self.fp_reg.get_reg(inst.rs2) < 0.0 && self.fp_reg.get_reg(inst.rs1) >= 0.0) ||
(self.fp_reg.get_reg(inst.rs2) >= 0.0 && self.fp_reg.get_reg(inst.rs1) < 0.0) { (self.fp_reg.get_reg(inst.rs2) >= 0.0 && self.fp_reg.get_reg(inst.rs1) < 0.0) {
self.fp_reg.set_reg(inst.rd, -local_float) self.fp_reg.set_reg(inst.rd, -local_float);
} else { } else {
self.fp_reg.set_reg(inst.rd, local_float) self.fp_reg.set_reg(inst.rd, local_float);
}, },
_ => panic!("this instruction ({}) doesn't exists", inst.value) _ => Err(format!("Unreachable in fp_fsgn_instruction! Instruction was {:?}", inst))?
} }
}, Ok(())
RISCV_FP_MINMAX => { }
/// Executes RISC-V min / max instruction on floating point values on the machine.
fn fp_minmax_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
let r1 = self.fp_reg.get_reg(inst.rs1); let r1 = self.fp_reg.get_reg(inst.rs1);
let r2 = self.fp_reg.get_reg(inst.rs2); let r2 = self.fp_reg.get_reg(inst.rs2);
match inst.funct3 { match inst.funct3 {
RISCV_FP_MINMAX_MIN => self.fp_reg.set_reg(inst.rd, if r1 < r2 {r1} else {r2}), RISCV_FP_MINMAX_MIN => self.fp_reg.set_reg(inst.rd, if r1 < r2 {r1} else {r2}),
RISCV_FP_MINMAX_MAX => self.fp_reg.set_reg(inst.rd, if r1 > r2 {r1} else {r2}), RISCV_FP_MINMAX_MAX => self.fp_reg.set_reg(inst.rd, if r1 > r2 {r1} else {r2}),
_ => panic!("this instruction ({}) doesn't exists", inst.value) _ => Err(format!("Unreachable in fp_minmax_instruction! Instruction was {:?}", inst))?
};
Ok(())
} }
},
RISCV_FP_FCVTW => { /// Executes RISC-V floating-point to integer conversion instruction on the machine.
fn fp_fcvtw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
if inst.rs2 == RISCV_FP_FCVTW_W { if inst.rs2 == RISCV_FP_FCVTW_W {
self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64) self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64)
} else { } else {
self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) as u64) as i64) self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) as u64) as i64)
} }
}, Ok(())
RISCV_FP_FCVTS => { }
/// Executes RISC-V integer to floating-point conversion instruction on the machine.
fn fp_fcvts_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
if inst.rs2 == RISCV_FP_FCVTS_W { if inst.rs2 == RISCV_FP_FCVTS_W {
self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32); self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32);
} else { } else {
self.fp_reg.set_reg(inst.rd, (self.int_reg.get_reg(inst.rs1) as u32) as f32); self.fp_reg.set_reg(inst.rd, (self.int_reg.get_reg(inst.rs1) as u32) as f32);
} }
}, Ok(())
RISCV_FP_FMVW => self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32), }
RISCV_FP_FMVXFCLASS => {
/// Executes RISC-V move from int_reg to fp_reg instruction on the machine.
fn fp_fmvw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32);
Ok(())
}
/// Executes RISC-V move from fp_reg to int_reg instruction on the machine.
fn fp_fmvxfclass_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX { if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX {
self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64); self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64);
Ok(())
} else { } else {
panic!("Fclass instruction is not handled in riscv simulator"); Err(format!("Unreachable in fp_fmvxfclass_instruction! Instruction was {:?}", inst))?
} }
}, }
RISCV_FP_FCMP => {
/// Executes RISC-V floating point values comparaison instructions on the machine.
fn fp_fcmp_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
match inst.funct3 { match inst.funct3 {
RISCV_FP_FCMP_FEQ => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) == self.fp_reg.get_reg(inst.rs2)) as i64), RISCV_FP_FCMP_FEQ => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) == self.fp_reg.get_reg(inst.rs2)) as i64),
RISCV_FP_FCMP_FLT => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) < self.fp_reg.get_reg(inst.rs2)) as i64), RISCV_FP_FCMP_FLT => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) < self.fp_reg.get_reg(inst.rs2)) as i64),
RISCV_FP_FCMP_FLE => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) <= self.fp_reg.get_reg(inst.rs2)) as i64), RISCV_FP_FCMP_FLE => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) <= self.fp_reg.get_reg(inst.rs2)) as i64),
_ => panic!("this instruction ({}) doesn't exists", inst.value) _ => Err(format!("Unreachable in fp_fcmp_instruction match! Instruction was {:?}", inst))?
}
},
_ => panic!("this instruction ({}) doesn't exists", inst.value)
} }
Ok(()) Ok(())
} }