From 43de76bd72da76fc975caf0e96bfc40f8dae0e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Autin?= Date: Thu, 23 Mar 2023 20:05:46 +0100 Subject: [PATCH] :recycle: Started work on machine.rs refactoring # Current changes - Crude error management - Readability improvements - Broke down one_instruction into smaller, more manageable methods - Added crude documentation --- src/simulator/machine.rs | 709 +++++++++++++++++---------------------- 1 file changed, 313 insertions(+), 396 deletions(-) diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 1a1057f..b785d6b 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -1,6 +1,6 @@ use std::{ops::{Add, Sub}, io::Write}; -use crate::simulator::print; +use crate::simulator::{print, error::MachineError}; use super::{decode::{Instruction, decode}, interrupt::Interrupt}; use super::global::*; @@ -230,28 +230,16 @@ impl Machine { /// /// - **machine** which contains a table of instructions pub fn run(machine : &mut Machine){ - while Machine::one_instruction(machine) == 0 {} + while let Ok(()) = Machine::one_instruction(machine) {} println!("trace : \n{}", machine.registers_trace); } - /// execute the current instruction + /// Execute the current instruction /// /// ### Parameters /// /// - **machine** which contains a table of instructions and a pc to the actual instruction - pub fn one_instruction(machine :&mut Machine) -> i32 { - - let unsigned_reg1 : u64; - let unsigned_reg2 : u64; - let long_result : i128; - - /*__int128 longResult; - int32_t local_data_a, local_data_b; - int64_t localLongResult; - uint32_t local_data_aUnsigned, local_data_bUnsigned; - int32_t localResult; - float localFloat; - uint64_t value;*/ + pub fn one_instruction(machine :&mut Machine) -> Result<(), MachineError> { if machine.main_memory.len() <= machine.pc as usize { panic!("ERROR : number max of instructions rushed"); @@ -274,422 +262,351 @@ impl Machine { match inst.opcode { RISCV_LUI => { machine.int_reg.set_reg(inst.rd as usize, inst.imm31_12 as i64); + Ok(()) }, RISCV_AUIPC => { machine.int_reg.set_reg(inst.rd as usize,machine.pc as i64 - 4 + inst.imm31_12 as i64); + Ok(()) }, RISCV_JAL => { machine.int_reg.set_reg(inst.rd as usize, machine.pc as i64); machine.pc = (machine.pc as i64 + inst.imm21_1_signed as i64 - 4) as u64; + Ok(()) }, RISCV_JALR => { let tmp = machine.pc; machine.pc = (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as u64 & 0xfffffffe; machine.int_reg.set_reg(inst.rd as usize, tmp as i64); + Ok(()) }, - - //****************************************************************************************** // Treatment for: BRANCH INSTRUCTIONS RISCV_BR => { - match inst.funct3 { - RISCV_BR_BEQ => { - if machine.int_reg.get_reg(inst.rs1 as usize) == machine.int_reg.get_reg(inst.rs2 as usize) { - machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; - } - }, - RISCV_BR_BNE => { - if machine.int_reg.get_reg(inst.rs1 as usize) != machine.int_reg.get_reg(inst.rs2 as usize) { - machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; - } - }, - RISCV_BR_BLT => { - if machine.int_reg.get_reg(inst.rs1 as usize) < machine.int_reg.get_reg(inst.rs2 as usize) { - machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; - } - }, - RISCV_BR_BGE => { - if machine.int_reg.get_reg(inst.rs1 as usize) >= machine.int_reg.get_reg(inst.rs2 as usize) { - machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; - } - }, - RISCV_BR_BLTU => { - if machine.int_reg.get_reg(inst.rs1 as usize) < machine.int_reg.get_reg(inst.rs2 as usize) { - machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; - } - }, - RISCV_BR_BGEU => { - if machine.int_reg.get_reg(inst.rs1 as usize) >= machine.int_reg.get_reg(inst.rs2 as usize) { - machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; - } - }, - _ => { - panic!("In BR switch case, this should never happen... Instr was {}", inst.value); - } - } + Self::branch_instruction(machine, inst) }, - - //****************************************************************************************** // Treatment for: LOAD INSTRUCTIONS RISCV_LD => { - match inst.funct3 { - RISCV_LD_LB | RISCV_LD_LBU => { - let tmp = Self::read_memory(machine, 1, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; - machine.int_reg.set_reg(inst.rd as usize, tmp); - }, - RISCV_LD_LH | RISCV_LD_LHU => { - let tmp = Self::read_memory(machine, 2, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; - machine.int_reg.set_reg(inst.rd as usize, tmp); - }, - RISCV_LD_LW | RISCV_LD_LWU => { - let tmp = Self::read_memory(machine, 4, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; - machine.int_reg.set_reg(inst.rd as usize, tmp); - }, - RISCV_LD_LD => { - let tmp = Self::read_memory(machine, 8, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; - machine.int_reg.set_reg(inst.rd as usize, tmp); - }, - _ => { - panic!("In LD switch case, this should never happen... Instr was {}", inst.value); - } - } + Self::load_instruction(machine, inst) }, // store instructions RISCV_ST => { - match inst.funct3 { - RISCV_ST_STB => { - Self::write_memory(machine, 1, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64); - }, - RISCV_ST_STH => { - Self::write_memory(machine, 2, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64); - }, - RISCV_ST_STW => { - Self::write_memory(machine, 4, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64); - }, - RISCV_ST_STD => { - Self::write_memory(machine, 8, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64); - }, - _ => { - panic!("In ST switch case, this should never happen... Instr was {}", inst.value); - } - } - } - //****************************************************************************************** + Self::store_instruction(machine, inst) + }, // Treatment for: OPI INSTRUCTIONS RISCV_OPI => { - match inst.funct3 { - RISCV_OPI_ADDI => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64); - }, - RISCV_OPI_SLTI => { - machine.int_reg.set_reg(inst.rd as usize, (machine.int_reg.get_reg(inst.rs1 as usize) < inst.imm12_I_signed as i64) as i64); - }, - RISCV_OPI_XORI => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) ^ inst.imm12_I_signed as i64); - }, - RISCV_OPI_ORI => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) | inst.imm12_I_signed as i64); - }, - RISCV_OPI_ANDI => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) & inst.imm12_I_signed as i64); - }, - RISCV_OPI_SLLI => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) << inst.shamt); - }, - RISCV_OPI_SRI => { - if inst.funct7_smaller == RISCV_OPI_SRI_SRLI { - machine.int_reg.set_reg(inst.rd as usize, (machine.int_reg.get_reg(inst.rs1 as usize) >> inst.shamt) & machine.shiftmask[inst.shamt as usize] as i64); - } else { // SRAI - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) >> inst.shamt); - } - } - _ => { panic!("In OPI switch case, this should never happen... Instr was %x\n {}", inst.value); } - } + Self::opi_instruction(machine, inst) }, - RISCV_OP => { - if inst.funct7 == 1 { - match inst.funct3 { - RISCV_OP_M_MUL => { - long_result = (machine.int_reg.get_reg(inst.rs1 as usize) * machine.int_reg.get_reg(inst.rs2 as usize)) as i128; - machine.int_reg.set_reg(inst.rd as usize, (long_result & 0xffffffffffffffff) as i64); - }, - RISCV_OP_M_MULH => { - long_result = (machine.int_reg.get_reg(inst.rs1 as usize) * machine.int_reg.get_reg(inst.rs2 as usize)) as i128; - machine.int_reg.set_reg(inst.rd as usize, ((long_result >> 64) & 0xffffffffffffffff) as i64); - }, - RISCV_OP_M_MULHSU => { - unsigned_reg2 = machine.int_reg.get_reg(inst.rs2 as usize) as u64; - long_result = (machine.int_reg.get_reg(inst.rs1 as usize) as u64 * unsigned_reg2) as i128; - machine.int_reg.set_reg(inst.rd as usize, ((long_result >> 64) & 0xffffffffffffffff) as i64); - }, - // VOIR CE QUE FAIT EXACTEMENT CE TRUC , PK on converve - /* - * VOIR SI LES CAST machine.int_reg[....] = i128*u64 as u32 FAUSSE RESULTAT (suit pas la logique du code c++) - * WHAT DA HECK - */ - RISCV_OP_M_MULHU => { - unsigned_reg1 = machine.int_reg.get_reg(inst.rs1 as usize) as u64; - unsigned_reg2 = machine.int_reg.get_reg(inst.rs2 as usize) as u64; - long_result = (unsigned_reg1 * unsigned_reg2) as i128; - machine.int_reg.set_reg(inst.rd as usize, ((long_result >> 64) & 0xffffffffffffffff) as i64); - }, - RISCV_OP_M_DIV => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) / machine.int_reg.get_reg(inst.rs2 as usize)); - } - _ => { - panic!("RISCV_OP : funct7 = 1 (Multiplication) :: Error\n"); - } - } - } else { - match inst.funct3 { - RISCV_OP_ADD => { - if inst.funct7 == RISCV_OP_ADD_ADD { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) + machine.int_reg.get_reg(inst.rs2 as usize)); - } else { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) - machine.int_reg.get_reg(inst.rs2 as usize)); - } - }, - RISCV_OP_SLL => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) << (machine.int_reg.get_reg(inst.rs2 as usize) & 0x3f)); - }, - RISCV_OP_SLT => { - if machine.int_reg.get_reg(inst.rs1 as usize) < machine.int_reg.get_reg(inst.rs2 as usize) { - machine.int_reg.set_reg(inst.rd as usize, 1); - } else { - machine.int_reg.set_reg(inst.rd as usize, 0); - } - }, - RISCV_OP_SLTU => { - unsigned_reg1 = machine.int_reg.get_reg(inst.rs1 as usize) as u64; - unsigned_reg2 = machine.int_reg.get_reg(inst.rs2 as usize) as u64; - if unsigned_reg1 < unsigned_reg2 { - machine.int_reg.set_reg(inst.rd as usize, 1); - } else { - machine.int_reg.set_reg(inst.rd as usize, 0); - } - }, - RISCV_OP_XOR => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) ^ machine.int_reg.get_reg(inst.rs2 as usize)); - }, - RISCV_OP_SR => { - // RISCV_OP_SR_SRL inaccessible - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) >> machine.int_reg.get_reg(inst.rs2 as usize)); - }, - RISCV_OP_OR => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) | machine.int_reg.get_reg(inst.rs2 as usize)); - }, - RISCV_OP_AND => { - machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) & machine.int_reg.get_reg(inst.rs2 as usize)); - }, - _ => { - panic!("RISCV_OP undefined case\n"); - } - }//LA - } + Self::op_instruction(machine, inst) }, - //****************************************************************************************** // Treatment for OPIW INSTRUCTIONS RISCV_OPIW => { - let local_data = machine.int_reg.get_reg(inst.rs1 as usize); - match inst.funct3 { - RISCV_OPIW_ADDIW => { - let result = local_data + inst.imm12_I_signed as i64; - machine.int_reg.set_reg(inst.rd as usize, result); - }, - RISCV_OPIW_SLLIW => { - let result = local_data << inst.shamt; - machine.int_reg.set_reg(inst.rd as usize, result); - }, - RISCV_OPIW_SRW => { - let result = if inst.funct7 == RISCV_OPIW_SRW_SRLIW { - (local_data >> inst.shamt) & machine.shiftmask[32 + inst.shamt as usize] as i64 - } else { // SRAIW - local_data >> inst.shamt - }; - machine.int_reg.set_reg(inst.rd as usize, result); - }, - _ => { - panic!("In OPI switch case, this should never happen... Instr was {}\n", inst.value); - } - } + Self::opiw_instruction(machine, inst) }, - //****************************************************************************************** // Treatment for: OPW INSTRUCTIONS - RISCV_OPW => { - if inst.funct7 == 1 { // rv64m - let local_data_a = machine.int_reg.get_reg(inst.rs1 as usize) & 0xffffffff; - let local_data_b = machine.int_reg.get_reg(inst.rs2 as usize) & 0xffffffff; - let local_data_a_unsigned = machine.int_reg.get_reg(inst.rs1 as usize) & 0xffffffff; - let local_data_b_unsigned = machine.int_reg.get_reg(inst.rs2 as usize) & 0xffffffff; - - // Match case for multiplication operations (in standard extension RV32M) - match inst.funct3 { - RISCV_OPW_M_MULW => { - machine.int_reg.set_reg(inst.rd as usize, local_data_a * local_data_b); - }, - RISCV_OPW_M_DIVW => { - machine.int_reg.set_reg(inst.rd as usize, local_data_a / local_data_b); - }, - RISCV_OPW_M_DIVUW => { - machine.int_reg.set_reg(inst.rd as usize, local_data_a_unsigned / local_data_b_unsigned); - }, - RISCV_OPW_M_REMW => { - machine.int_reg.set_reg(inst.rd as usize, local_data_a % local_data_b); - }, - RISCV_OPW_M_REMUW => { - machine.int_reg.set_reg(inst.rd as usize, local_data_a_unsigned % local_data_b_unsigned); - }, - _ => { - panic!("this instruction ({}) doesn't exists", inst.value); - } - } - } else { // others rv64 OPW operations - let local_dataa = machine.int_reg.get_reg(inst.rs1 as usize) & 0xffffffff; - let local_datab = machine.int_reg.get_reg(inst.rs2 as usize) & 0xffffffff; - - // Match case for base OP operation - match inst.funct3 { - RISCV_OPW_ADDSUBW => { - if inst.funct7 == RISCV_OPW_ADDSUBW_ADDW { - machine.int_reg.set_reg(inst.rd as usize, local_dataa + local_datab); - } else { // SUBW - machine.int_reg.set_reg(inst.rd as usize, local_dataa - local_datab); - } - }, - RISCV_OPW_SLLW => { - machine.int_reg.set_reg(inst.rd as usize, local_dataa << (local_datab & 0x1f)); - }, - RISCV_OPW_SRW => { - if inst.funct7 == RISCV_OPW_SRW_SRLW { - machine.int_reg.set_reg(inst.rd as usize, local_dataa >> (local_datab & 0x1f) & machine.shiftmask[32 + local_datab as usize] as i64); - } else { // SRAW - machine.int_reg.set_reg(inst.rd as usize, local_dataa >> (local_datab & 0x1f)); - } - }, - _ => { - panic!("this instruction ({}) doesn't exists", inst.value); - } - } - } - }, - //****************************************************************************************** + RISCV_OPW => Self::opw_instruction(machine, inst), // Treatment for: Simple floating point extension - RISCV_FP => { - match inst.funct7 { - RISCV_FP_ADD => { - machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) + machine.fp_reg.get_reg(inst.rs2 as usize)); - }, - RISCV_FP_SUB => { - machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) - machine.fp_reg.get_reg(inst.rs2 as usize)); - }, - RISCV_FP_MUL => { - machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) * machine.fp_reg.get_reg(inst.rs2 as usize)); - }, - RISCV_FP_DIV => { - machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) / machine.fp_reg.get_reg(inst.rs2 as usize)); - }, - RISCV_FP_SQRT => { - machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize).sqrt()); - }, - RISCV_FP_FSGN => { - let local_float = machine.fp_reg.get_reg(inst.rs1 as usize); - match inst.funct3 { - RISCV_FP_FSGN_J => { - if machine.fp_reg.get_reg(inst.rs2 as usize) < 0f32 { - machine.fp_reg.set_reg(inst.rd as usize, -local_float); - } else { - machine.fp_reg.set_reg(inst.rd as usize, local_float); - } - } - RISCV_FP_FSGN_JN => { - if machine.fp_reg.get_reg(inst.rs2 as usize) < 0f32 { - machine.fp_reg.set_reg(inst.rd as usize, local_float); - } else { - machine.fp_reg.set_reg(inst.rd as usize, -local_float); - } - } - RISCV_FP_FSGN_JX => { - if (machine.fp_reg.get_reg(inst.rs2 as usize) < 0.0 && machine.fp_reg.get_reg(inst.rs1 as usize) >= 0.0) || (machine.fp_reg.get_reg(inst.rs2 as usize) >= 0.0 && machine.fp_reg.get_reg(inst.rs1 as usize) < 0.0) { - machine.fp_reg.set_reg(inst.rd as usize, -local_float); - } else { - machine.fp_reg.set_reg(inst.rd as usize, local_float); - } - } - _ => { - panic!("this instruction ({}) doesn't exists", inst.value); - } - } - }, - RISCV_FP_MINMAX => { - let r1 = machine.fp_reg.get_reg(inst.rs1 as usize); - let r2 = machine.fp_reg.get_reg(inst.rs2 as usize); - match inst.funct3 { - RISCV_FP_MINMAX_MIN => { - machine.fp_reg.set_reg(inst.rd as usize, if r1 < r2 {r1} else {r2}); - }, - RISCV_FP_MINMAX_MAX => { - machine.fp_reg.set_reg(inst.rd as usize, if r1 > r2 {r1} else {r2}); - }, - _ => { - panic!("this instruction ({}) doesn't exists", inst.value); - } - } - }, - RISCV_FP_FCVTW => { - if inst.rs2 == RISCV_FP_FCVTW_W { - machine.int_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) as i64); - } else { - machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) as u64) as i64); - } - }, - RISCV_FP_FCVTS => { - if inst.rs2 == RISCV_FP_FCVTS_W { - machine.fp_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) as f32); - } else { - machine.fp_reg.set_reg(inst.rd as usize, (machine.int_reg.get_reg(inst.rs1 as usize) as u32) as f32); - } - }, - RISCV_FP_FMVW => { - machine.fp_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) as f32); - }, - RISCV_FP_FMVXFCLASS => { - if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX { - machine.int_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) as i64); - } else { - panic!("Fclass instruction is not handled in riscv simulator"); - } - }, - RISCV_FP_FCMP => { - match inst.funct3 { - RISCV_FP_FCMP_FEQ => { - machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) == machine.fp_reg.get_reg(inst.rs2 as usize)) as i64); - }, - RISCV_FP_FCMP_FLT => { - machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) < machine.fp_reg.get_reg(inst.rs2 as usize)) as i64); - }, - RISCV_FP_FCMP_FLE => { - machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) <= machine.fp_reg.get_reg(inst.rs2 as usize)) as i64); - }, - _ => { - panic!("this instruction ({}) doesn't exists", inst.value); - } - } - }, - _ => { - panic!("this instruction ({}) doesn't exists", inst.value); - } - } - } + RISCV_FP => Self::fp_instruction(machine, inst), + // Treatment for: System instructions RISCV_SYSTEM => { // temporary return value to stop the loop of run - // before we can use system call - return 1; - } - _ => { panic!("{:x} opcode non géré pc : {:x}", inst.opcode, machine.pc)}, + // before we can use system call + Err(MachineError::new(format!("{:x}: System opcode\npc: {:x}", inst.opcode, machine.pc).as_str())) + }, + _ => Err(MachineError::new(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, machine.pc).as_str())) } + } - 0 + /// Treatement for Branch instructions + fn branch_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + match inst.funct3 { + RISCV_BR_BEQ => { + if machine.int_reg.get_reg(inst.rs1 as usize) == machine.int_reg.get_reg(inst.rs2 as usize) { + machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; + } + }, + RISCV_BR_BNE => { + if machine.int_reg.get_reg(inst.rs1 as usize) != machine.int_reg.get_reg(inst.rs2 as usize) { + machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; + } + }, + RISCV_BR_BLT => { + if machine.int_reg.get_reg(inst.rs1 as usize) < machine.int_reg.get_reg(inst.rs2 as usize) { + machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; + } + }, + RISCV_BR_BGE => { + if machine.int_reg.get_reg(inst.rs1 as usize) >= machine.int_reg.get_reg(inst.rs2 as usize) { + machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; + } + }, + RISCV_BR_BLTU => { + if machine.int_reg.get_reg(inst.rs1 as usize) < machine.int_reg.get_reg(inst.rs2 as usize) { + machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; + } + }, + RISCV_BR_BGEU => { + if machine.int_reg.get_reg(inst.rs1 as usize) >= machine.int_reg.get_reg(inst.rs2 as usize) { + machine.pc = (machine.pc as i64 + inst.imm13_signed as i64 - 4) as u64; + } + }, + _ => { + panic!("In BR switch case, this should never happen... Instr was {}", inst.value); + } + } + Ok(()) + } + /// Executes RISC-V Load Instructions on the machine + fn load_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + match inst.funct3 { + RISCV_LD_LB | RISCV_LD_LBU => { + let tmp = Self::read_memory(machine, 1, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; + machine.int_reg.set_reg(inst.rd as usize, tmp); + }, + RISCV_LD_LH | RISCV_LD_LHU => { + let tmp = Self::read_memory(machine, 2, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; + machine.int_reg.set_reg(inst.rd as usize, tmp); + }, + RISCV_LD_LW | RISCV_LD_LWU => { + let tmp = Self::read_memory(machine, 4, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; + machine.int_reg.set_reg(inst.rd as usize, tmp); + }, + RISCV_LD_LD => { + let tmp = Self::read_memory(machine, 8, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64) as usize) as i64; + machine.int_reg.set_reg(inst.rd as usize, tmp); + }, + _ => panic!("In LD switch case, this should never happen... Instr was {}", inst.value) + } + Ok(()) + } + + /// Executes RISC-V Store Instructions on the machine + fn store_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + match inst.funct3 { + RISCV_ST_STB => Self::write_memory(machine, 1, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64), + RISCV_ST_STH => Self::write_memory(machine, 2, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64), + RISCV_ST_STW => Self::write_memory(machine, 4, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64), + RISCV_ST_STD => Self::write_memory(machine, 8, (machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_S_signed as i64) as usize, machine.int_reg.get_reg(inst.rs2 as usize) as u64), + _ => panic!("In ST switch case, this should never happen... Instr was {}", inst.value) + } + Ok(()) + } + + /// Executes RISC-V Integer Register-Immediate Instructions on the machine + fn opi_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + match inst.funct3 { + RISCV_OPI_ADDI => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) + inst.imm12_I_signed as i64), + RISCV_OPI_SLTI => machine.int_reg.set_reg(inst.rd as usize, (machine.int_reg.get_reg(inst.rs1 as usize) < inst.imm12_I_signed as i64) as i64), + RISCV_OPI_XORI => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) ^ inst.imm12_I_signed as i64), + RISCV_OPI_ORI => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) | inst.imm12_I_signed as i64), + RISCV_OPI_ANDI => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) & inst.imm12_I_signed as i64), + RISCV_OPI_SLLI => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) << inst.shamt), + RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI { + machine.int_reg.set_reg(inst.rd as usize, (machine.int_reg.get_reg(inst.rs1 as usize) >> inst.shamt) & machine.shiftmask[inst.shamt as usize] as i64); + } else { // SRAI + machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) >> inst.shamt); + }, + _ => panic!("In OPI switch case, this should never happen... Instr was %x\n {}", inst.value) + } + Ok(()) + } + + /// Executes simple RISC-V mathematical operations on the machine + fn op_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + let long_result: i128; + let unsigned_reg1: u64; + let unsigned_reg2: u64; + if inst.funct7 == 1 { + match inst.funct3 { + RISCV_OP_M_MUL => { + long_result = (machine.int_reg.get_reg(inst.rs1 as usize) * machine.int_reg.get_reg(inst.rs2 as usize)) as i128; + machine.int_reg.set_reg(inst.rd as usize, (long_result & 0xffffffffffffffff) as i64) + }, + RISCV_OP_M_MULH => { + long_result = (machine.int_reg.get_reg(inst.rs1 as usize) * machine.int_reg.get_reg(inst.rs2 as usize)) as i128; + machine.int_reg.set_reg(inst.rd as usize, ((long_result >> 64) & 0xffffffffffffffff) as i64) + }, + RISCV_OP_M_MULHSU => { + unsigned_reg2 = machine.int_reg.get_reg(inst.rs2 as usize) as u64; + long_result = (machine.int_reg.get_reg(inst.rs1 as usize) as u64 * unsigned_reg2) as i128; + machine.int_reg.set_reg(inst.rd as usize, ((long_result >> 64) & 0xffffffffffffffff) as i64) + }, + RISCV_OP_M_MULHU => { + unsigned_reg1 = machine.int_reg.get_reg(inst.rs1 as usize) as u64; + unsigned_reg2 = machine.int_reg.get_reg(inst.rs2 as usize) as u64; + long_result = (unsigned_reg1 * unsigned_reg2) as i128; + machine.int_reg.set_reg(inst.rd as usize, ((long_result >> 64) & 0xffffffffffffffff) as i64); + }, + RISCV_OP_M_DIV => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) / machine.int_reg.get_reg(inst.rs2 as usize)), + _ => panic!("RISCV_OP : funct7 = 1 (Multiplication) :: Error\n") + } + } else { + match inst.funct3 { + RISCV_OP_ADD => if inst.funct7 == RISCV_OP_ADD_ADD { + machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) + machine.int_reg.get_reg(inst.rs2 as usize)) + } else { + machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) - machine.int_reg.get_reg(inst.rs2 as usize)) + }, + RISCV_OP_SLL => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) << (machine.int_reg.get_reg(inst.rs2 as usize) & 0x3f)), + RISCV_OP_SLT => if machine.int_reg.get_reg(inst.rs1 as usize) < machine.int_reg.get_reg(inst.rs2 as usize) { + machine.int_reg.set_reg(inst.rd as usize, 1) + } else { + machine.int_reg.set_reg(inst.rd as usize, 0) + }, + RISCV_OP_SLTU => { + unsigned_reg1 = machine.int_reg.get_reg(inst.rs1 as usize) as u64; + unsigned_reg2 = machine.int_reg.get_reg(inst.rs2 as usize) as u64; + if unsigned_reg1 < unsigned_reg2 { + machine.int_reg.set_reg(inst.rd as usize, 1) + } else { + machine.int_reg.set_reg(inst.rd as usize, 0) + } + }, + RISCV_OP_XOR => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) ^ machine.int_reg.get_reg(inst.rs2 as usize)), + RISCV_OP_SR => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) >> machine.int_reg.get_reg(inst.rs2 as usize)), // RISCV_OP_SR_SRL inaccessible + RISCV_OP_OR => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) | machine.int_reg.get_reg(inst.rs2 as usize)), + RISCV_OP_AND => machine.int_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) & machine.int_reg.get_reg(inst.rs2 as usize)), + _ => panic!("RISCV_OP undefined case\n") + } + } + Ok(()) + } + + /// Exectutes simple RISC-V *iw instructions on the machine + fn opiw_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + let local_data = machine.int_reg.get_reg(inst.rs1 as usize); + match inst.funct3 { + RISCV_OPIW_ADDIW => { + let result = local_data + inst.imm12_I_signed as i64; + machine.int_reg.set_reg(inst.rd as usize, result) + }, + RISCV_OPIW_SLLIW => { + let result = local_data << inst.shamt; + machine.int_reg.set_reg(inst.rd as usize, result) + }, + RISCV_OPIW_SRW => { + let result = if inst.funct7 == RISCV_OPIW_SRW_SRLIW { + (local_data >> inst.shamt) & machine.shiftmask[32 + inst.shamt as usize] as i64 + } else { // SRAIW + local_data >> inst.shamt + }; + machine.int_reg.set_reg(inst.rd as usize, result) + }, + _ => panic!("In OPI switch case, this should never happen... Instr was {}\n", inst.value), + } + Ok(()) + } + + /// Executes simple RISC-V *w instructions on the machine + fn opw_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + if inst.funct7 == 1 { // rv64m + let local_data_a = machine.int_reg.get_reg(inst.rs1 as usize) & 0xffffffff; + let local_data_b = machine.int_reg.get_reg(inst.rs2 as usize) & 0xffffffff; + let local_data_a_unsigned = machine.int_reg.get_reg(inst.rs1 as usize) & 0xffffffff; + let local_data_b_unsigned = machine.int_reg.get_reg(inst.rs2 as usize) & 0xffffffff; + + // Match case for multiplication operations (in standard extension RV32M) + match inst.funct3 { + RISCV_OPW_M_MULW => machine.int_reg.set_reg(inst.rd as usize, local_data_a * local_data_b), + RISCV_OPW_M_DIVW => machine.int_reg.set_reg(inst.rd as usize, local_data_a / local_data_b), + RISCV_OPW_M_DIVUW => machine.int_reg.set_reg(inst.rd as usize, local_data_a_unsigned / local_data_b_unsigned), + RISCV_OPW_M_REMW => machine.int_reg.set_reg(inst.rd as usize, local_data_a % local_data_b), + RISCV_OPW_M_REMUW => machine.int_reg.set_reg(inst.rd as usize, local_data_a_unsigned % local_data_b_unsigned), + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + } else { // others rv64 OPW operations + let local_dataa = machine.int_reg.get_reg(inst.rs1 as usize) & 0xffffffff; + let local_datab = machine.int_reg.get_reg(inst.rs2 as usize) & 0xffffffff; + // Match case for base OP operation + match inst.funct3 { + RISCV_OPW_ADDSUBW => if inst.funct7 == RISCV_OPW_ADDSUBW_ADDW { + machine.int_reg.set_reg(inst.rd as usize, local_dataa + local_datab); + } else { // SUBW + machine.int_reg.set_reg(inst.rd as usize, local_dataa - local_datab); + }, + RISCV_OPW_SLLW => machine.int_reg.set_reg(inst.rd as usize, local_dataa << (local_datab & 0x1f)), + RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW { + machine.int_reg.set_reg(inst.rd as usize, local_dataa >> (local_datab & 0x1f) & machine.shiftmask[32 + local_datab as usize] as i64) + } else { // SRAW + machine.int_reg.set_reg(inst.rd as usize, local_dataa >> (local_datab & 0x1f)) + }, + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + } + Ok(()) + } + + /// Executes simple RISC-V floating point instructions on the machine + fn fp_instruction(machine: &mut Machine, inst: Instruction) -> Result<(), MachineError> { + match inst.funct7 { + RISCV_FP_ADD => machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) + machine.fp_reg.get_reg(inst.rs2 as usize)), + RISCV_FP_SUB => machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) - machine.fp_reg.get_reg(inst.rs2 as usize)), + RISCV_FP_MUL => machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) * machine.fp_reg.get_reg(inst.rs2 as usize)), + RISCV_FP_DIV => machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) / machine.fp_reg.get_reg(inst.rs2 as usize)), + RISCV_FP_SQRT => machine.fp_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize).sqrt()), + RISCV_FP_FSGN => { + let local_float = machine.fp_reg.get_reg(inst.rs1 as usize); + match inst.funct3 { + RISCV_FP_FSGN_J => if machine.fp_reg.get_reg(inst.rs2 as usize) < 0f32 { + machine.fp_reg.set_reg(inst.rd as usize, -local_float) + } else { + machine.fp_reg.set_reg(inst.rd as usize, local_float) + }, + RISCV_FP_FSGN_JN => if machine.fp_reg.get_reg(inst.rs2 as usize) < 0f32 { + machine.fp_reg.set_reg(inst.rd as usize, local_float) + } else { + machine.fp_reg.set_reg(inst.rd as usize, -local_float) + }, + RISCV_FP_FSGN_JX => if (machine.fp_reg.get_reg(inst.rs2 as usize) < 0.0 && machine.fp_reg.get_reg(inst.rs1 as usize) >= 0.0) || (machine.fp_reg.get_reg(inst.rs2 as usize) >= 0.0 && machine.fp_reg.get_reg(inst.rs1 as usize) < 0.0) { + machine.fp_reg.set_reg(inst.rd as usize, -local_float) + } else { + machine.fp_reg.set_reg(inst.rd as usize, local_float) + }, + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + }, + RISCV_FP_MINMAX => { + let r1 = machine.fp_reg.get_reg(inst.rs1 as usize); + let r2 = machine.fp_reg.get_reg(inst.rs2 as usize); + match inst.funct3 { + RISCV_FP_MINMAX_MIN => machine.fp_reg.set_reg(inst.rd as usize, if r1 < r2 {r1} else {r2}), + RISCV_FP_MINMAX_MAX => machine.fp_reg.set_reg(inst.rd as usize, if r1 > r2 {r1} else {r2}), + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + }, + RISCV_FP_FCVTW => { + if inst.rs2 == RISCV_FP_FCVTW_W { + machine.int_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) as i64) + } else { + machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) as u64) as i64) + } + }, + RISCV_FP_FCVTS => { + if inst.rs2 == RISCV_FP_FCVTS_W { + machine.fp_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) as f32); + } else { + machine.fp_reg.set_reg(inst.rd as usize, (machine.int_reg.get_reg(inst.rs1 as usize) as u32) as f32); + } + }, + RISCV_FP_FMVW => machine.fp_reg.set_reg(inst.rd as usize, machine.int_reg.get_reg(inst.rs1 as usize) as f32), + RISCV_FP_FMVXFCLASS => { + if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX { + machine.int_reg.set_reg(inst.rd as usize, machine.fp_reg.get_reg(inst.rs1 as usize) as i64); + } else { + panic!("Fclass instruction is not handled in riscv simulator"); + } + }, + RISCV_FP_FCMP => { + match inst.funct3 { + RISCV_FP_FCMP_FEQ => machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) == machine.fp_reg.get_reg(inst.rs2 as usize)) as i64), + RISCV_FP_FCMP_FLT => machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) < machine.fp_reg.get_reg(inst.rs2 as usize)) as i64), + RISCV_FP_FCMP_FLE => machine.int_reg.set_reg(inst.rd as usize, (machine.fp_reg.get_reg(inst.rs1 as usize) <= machine.fp_reg.get_reg(inst.rs2 as usize)) as i64), + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + }, + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + Ok(()) } /// print memory FOR DEBUG