diff --git a/src/main.rs b/src/main.rs index 874aa9a..9fe5976 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,5 +18,6 @@ use simulator::machine::Machine; fn main() { let mut machine = Machine::init_machine(); - let system = &mut System::default(); + let system = System::default(); + machine.run() } diff --git a/src/simulator/error.rs b/src/simulator/error.rs new file mode 100644 index 0000000..d6ea783 --- /dev/null +++ b/src/simulator/error.rs @@ -0,0 +1,55 @@ +//! # Error +//! +//! This module contains the definition of the MachineError struct, +//! for error management in the Machine module. +//! +//! Basic usage: +//! +//! ``` +//! fn example(x: bool) -> Result<(), MachineError> { +//! match x { +//! true => Ok(()), +//! _ => Err(MachineError::new("Machine failed because of ...")); +//! } +//! } +//! ``` + +use std::fmt; + +/// Machine Error +/// This error serves as a specific exception handler for the Machine struct +#[derive(Debug, Clone)] +pub struct MachineError { + /// The error message + message: String +} + +/// This impl allows this MachineError to be formatted into an empty format. +/// +/// ``` +/// // Result of printing a MachineError +/// let m = MachineError::new("Lorem Ipsum"); +/// println!("Example: {}", m); +/// ``` +/// +/// Console output:Error} +/// ``` +/// example Lorem Ipsum +/// ``` +impl fmt::Display for MachineError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Machine error: {}", &self.message) + } +} + +impl From<&str> for MachineError { + fn from(value: &str) -> Self { + MachineError { message: value.to_string() } + } +} + +impl From for MachineError { + fn from(value: String) -> Self { + MachineError { message: value } + } +} \ No newline at end of file diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 7d62e78..0d9619b 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -1,109 +1,84 @@ -use std::{ops::{Add, Sub}, io::Write}; +//! # Machine +//! +//! This module contains a RISC-V simulator. +//! It supports the base instruction set along +//! with 32bit floating point operations. +//! +//! Basic usage: +//! +//! ``` +//! let mut machine = Machine::init_machine(); +//! machine.run(); +//! ``` -use crate::simulator::print; +use std::{ + io::Write, + fs::File +}; +use crate::simulator::{ + print, + error::MachineError, + decode::*, + interrupt::Interrupt, + global::*, + register::* +}; -use super::{decode::{Instruction, decode}, interrupt::Interrupt}; -use super::global::*; -use std::fs::File; - - -/* -* Decommenter la variant si il est utilisé quelque part - */ +/// # Exceptions +/// +/// Textual names of the exceptions that can be generated by user program +/// execution, for debugging purpose. +/// todo: is this really supposed to stand in machine.rs? pub enum ExceptionType { - NO_EXCEPTION,//Everything ok! - //SYSCALL_EXCEPTION,//A program executed a system call. - PAGEFAULT_EXCEPTION,//Page fault exception - READONLY_EXCEPTION,//Write attempted to a page marked "read-only" */ - BUSERROR_EXCEPTION, - /* translation resulted - in an invalid physical - address (mis-aligned or - out-of-bounds) */ - ADDRESSERROR_EXCEPTION, /* Reference that was - not mapped in the address - space */ - //OVERFLOW_EXCEPTION, //Integer overflow in add or sub. - //ILLEGALINSTR_EXCEPTION, //Unimplemented or reserved instr. - //NUM_EXCEPTION_TYPES + /// Everything ok + NoException, + /// A program executed a system call + SyscallException, + /// Page fault exception + PagefaultException, + /// Write attempted to a page marked "read-only" + ReadOnlyException, + /// Translation resulted in an invalid physical address (mis-aligned or out-of-bounds) + BusErrorException, + /// Reference which was not mapped in the address space + AddressErrorException, + /// Integer overflow in add or sub + OverflowException, + /// Unimplemented or reserved instruction + IllegalInstrException, + NumExceptionTypes } - +/// ID of the stack register pub const STACK_REG: usize = 2; - +/// Number of available Integer registers pub const NUM_INT_REGS: usize = 32; +/// Number of available Floating Point registers pub const NUM_FP_REGS: usize = 32; - -//max number of physical page +/// max number of physical pages pub const NUM_PHY_PAGE : u64 = 400; -//doit etre une puissance de deux +/// Must be 2^x pub const PAGE_SIZE : u64 = 128; -//doit etre un multiple de PAGE_SIZE +/// Must be a multiple of PAGE_SIZE pub const MEM_SIZE : usize = (PAGE_SIZE*NUM_PHY_PAGE*100) as usize; - -pub trait RegisterNum: Add + Sub + PartialEq + Copy {} - -impl RegisterNum for i64 {} - -impl RegisterNum for f32 {} - - -#[derive(PartialEq)] -pub struct Register { - register: [U; 32] -} - -impl Register { - - pub fn get_reg(&self, position: usize) -> U { - self.register[position] - } - -} - -impl Register { - - pub fn init() -> Register { - Register { - register: [0i64; 32] - } - } - - pub fn set_reg(&mut self, position: usize, value: i64) { - if position != 0 { - self.register[position] = value; - } else { - // Panic ou rien ? (dans le doute pour le moment panic) - // unreachable!("You can't write to zero register") - } - } - -} - -impl Register { - - pub fn init() -> Register { - Register { - register: [0f32; 32] - } - } - - pub fn set_reg(&mut self, position: usize, value: f32) { - self.register[position] = value; - } - -} - -#[derive(PartialEq)] +/// RISC-V Simulator pub struct Machine { + /// Program counter pub pc : u64, + /// Stack pointer pub sp: usize, + /// Integer register pub int_reg : Register, + /// Floating point register pub fp_reg : Register, + /// Heap memory pub main_memory : Vec, + /// Shiftmask pub shiftmask : [u64 ; 64], + /// Debug data pub registers_trace : String, // for tests + /// todo: document Interrupts pub interrupt: Interrupt // futur taille à calculer int memSize = g_cfg->NumPhysPages * g_cfg->PageSize; //creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg @@ -112,6 +87,7 @@ pub struct Machine { impl Machine { + /// Machine constructor pub fn init_machine() -> Machine { let mut shiftmask : [u64 ; 64] = [0 ; 64]; let mut value : u64 = 0xffffffff; @@ -122,19 +98,16 @@ impl Machine { value >>= 1; } - let mut ret = Machine { + Machine { pc : 0, sp: 0, - int_reg : Register::::init(), + int_reg : { let mut r = Register::::init(); r.set_reg(10, -1); r }, fp_reg : Register::::init(), main_memory : vec![0_u8; MEM_SIZE], shiftmask, interrupt: Interrupt::new(), registers_trace : String::from("") - }; - - ret.int_reg.set_reg(10, -1); - ret + } } /// Read from main memory of the machine @@ -146,7 +119,7 @@ impl Machine { /// - **machine** which contains the main memory /// - **size** the number of bytes to read (1, 2, 4, 8) /// - **address** in the memory to read - pub fn read_memory(&mut self, size : i32, address : usize) -> u64 { + pub fn read_memory(&self, size : i32, address : usize) -> u64 { if ![1, 2, 4, 8].contains(&size) { panic!("ERROR read_memory : wrong size parameter {size}, must be (1, 2, 4 or 8)"); } @@ -198,28 +171,38 @@ impl Machine { }; } - pub fn print_machine_status(&mut self) { + /// Print the status of the machine to the standard output + /// + /// ### Parameters + /// + /// - **machine** the machine to get the status from + pub fn print_status(&self) { println!("######### Machine status #########"); for i in (0..32).step_by(3) { - print!(">{0: <4} : {1:<16x} ", print::REG_X[i], self.int_reg.get_reg(i)); - print!(">{0: <4} : {1:<16x} ", print::REG_X[i+1], self.int_reg.get_reg(i+1)); + print!(">{0: <4} : {1:<16x} ", print::REG_X[i], self.int_reg.get_reg(i as u8)); + print!(">{0: <4} : {1:<16x} ", print::REG_X[i+1], self.int_reg.get_reg((i+1) as u8)); if i+2 < 32 { - print!(">{0: <4} : {1:<16x} ", print::REG_X[i+2], self.int_reg.get_reg(i+2)); + print!(">{0: <4} : {1:<16x} ", print::REG_X[i+2], self.int_reg.get_reg((i+2) as u8)); } println!(); } println!("________________SP________________"); let sp_index = self.int_reg.get_reg(2); for i in 0..5 { - println!("SP+{:<2} : {:16x}", i*8, Self::read_memory(self, 8, (sp_index + i*8) as usize)); + println!("SP+{:<2} : {:16x}", i*8, self.read_memory(8, (sp_index + i*8) as usize)); } println!("##################################"); } - pub fn string_registers(machine: &mut Machine) -> String { + /// Get the state of the registers as a string + /// + /// ### Parameters + /// + /// - **machine** the machine to read the registers from + pub fn string_registers(&self) -> String { let mut s = String::from(""); for i in 0..32 { - s.push_str(format!("{} ", machine.int_reg.get_reg(i)).as_str()); + s.push_str(format!("{} ", self.int_reg.get_reg(i)).as_str()); } s } @@ -229,496 +212,398 @@ impl Machine { /// ### Parameters /// /// - **machine** which contains a table of instructions - pub fn run(&mut self){ - while Machine::one_instruction(self) == 0 {} - println!("trace : \n{}", self.registers_trace); + pub fn run(&mut self) { + loop { + match self.one_instruction() { + Ok(_) => println!("hello"), + Err(e) => { if e.to_string().contains("System") { break; } panic!("FATAL at pc {} -> {}", self.pc, e) } + } + self.write_int_register(0, 0); // In case an instruction write on register 0 + } } - /// 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 { + pub fn one_instruction(&mut self) -> Result<(), MachineError> { - 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;*/ - - if machine.main_memory.len() <= machine.pc as usize { + if self.main_memory.len() <= self.pc as usize { panic!("ERROR : number max of instructions rushed"); } let mut val: [u8; 4] = [0; 4]; - for i in 0..4 { - val[i] = machine.main_memory[machine.pc as usize + i]; + for (i, elem) in val.iter_mut().enumerate() { + *elem = self.main_memory[self.pc as usize + i]; } let val = u32::from_be_bytes(val) as u64; let inst : Instruction = decode(val); - Self::print_machine_status(machine); - println!("executing instruction : {:016x} at pc {:x}", val, machine.pc); - println!("{}", print::print(decode(val), machine.pc as i32)); - let trace = Self::string_registers(machine); - machine.registers_trace.push_str(format!("{}\n", trace).as_str()); + self.print_status(); + println!("executing instruction : {:016x} at pc {:x}", val, self.pc); + println!("{}", print::print(decode(val), self.pc as i32)); + let trace = Self::string_registers(self); + self.registers_trace.push_str(format!("{}\n", trace).as_str()); - machine.pc += 4; + self.pc += 4; match inst.opcode { + // Treatment for: LOAD UPPER IMMEDIATE INSTRUCTION RISCV_LUI => { - machine.int_reg.set_reg(inst.rd as usize, inst.imm31_12 as i64); + self.int_reg.set_reg(inst.rd, inst.imm31_12 as i64); + Ok(()) }, + + // Treatment for: ADD UPPER IMMEDIATE TO PC INSTRUCTION RISCV_AUIPC => { - machine.int_reg.set_reg(inst.rd as usize,machine.pc as i64 - 4 + inst.imm31_12 as i64); + self.int_reg.set_reg(inst.rd, self.pc as i64 - 4 + inst.imm31_12 as i64); + Ok(()) }, + + // Treatement for: JUMP AND LINK INSTRUCTIONS (direct jump) 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; + self.int_reg.set_reg(inst.rd, self.pc as i64); + self.pc = (self.pc as i64 + inst.imm21_1_signed as i64 - 4) as u64; + Ok(()) }, + + // Treatment for: JUMP AND LINK REGISTER INSTRUCTIONS (indirect jump) 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); + let tmp = self.pc; + self.pc = (self.int_reg.get_reg(inst.rs1) + inst.imm12_I_signed as i64) as u64 & 0xfffffffe; + self.int_reg.set_reg(inst.rd, 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); - } - } - }, + RISCV_BR => self.branch_instruction(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); - } - } - }, - // 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); - } - } - } - //****************************************************************************************** + RISCV_LD => self.load_instruction(inst), + + // Treatment for: STORE INSTRUCTIONS + RISCV_ST => self.store_instruction(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); } - } - }, - - 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 - } - }, - //****************************************************************************************** + RISCV_OPI => self.opi_instruction(inst), + + // Treatment for: OP INSTRUCTIONS + RISCV_OP => self.op_instruction(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); - } - } - }, - //****************************************************************************************** + RISCV_OPIW => self.opiw_instruction(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; + RISCV_OPW => self.opw_instruction(inst), - // 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; + // Treatment for: FLOATING POINT INSTRUCTIONS + RISCV_FP => self.fp_instruction(inst), - // 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); - } - } - } - }, - //****************************************************************************************** - // 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_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)}, + // Treatment for: SYSTEM CALLS + RISCV_SYSTEM => Err(format!("{:x}: System opcode\npc: {:x}", inst.opcode, self.pc))?, + + // Default case + _ => Err(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, self.pc))? } + } - 0 + /// Treatement for Branch instructions + fn branch_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + let op = match inst.funct3 { + RISCV_BR_BEQ => |a, b| a == b, + RISCV_BR_BNE => |a, b| a != b, + RISCV_BR_BLT => |a, b| a < b, + RISCV_BR_BGE => |a, b| a >= b, + RISCV_BR_BLTU => |a, b| a < b, + RISCV_BR_BGEU => |a, b| a >= b, + _ => unreachable!() + }; + let rs1 = self.int_reg.get_reg(inst.rs1); + let rs2 = self.int_reg.get_reg(inst.rs2); + if op(rs1, rs2) { + self.pc = (self.pc as i64 + inst.imm13_signed as i64 - 4) as u64; + } + Ok(()) + } + /// Executes RISC-V Load Instructions on the machine + fn load_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + let mut set_reg = |rd, size| { + let val = self.read_memory(size, (self.int_reg.get_reg(inst.rs1) + inst.imm12_I_signed as i64) as usize) as i64; + self.int_reg.set_reg(rd, val); + Ok(()) + }; + match inst.funct3 { + RISCV_LD_LB | RISCV_LD_LBU => set_reg(inst.rd, 1), + RISCV_LD_LH | RISCV_LD_LHU => set_reg(inst.rd, 2), + RISCV_LD_LW | RISCV_LD_LWU => set_reg(inst.rd, 4), + RISCV_LD_LD => set_reg(inst.rd, 8), + _ => Err(format!("In LD switch case, this should never happen... Instr was {}", inst.value).as_str())? + } + } + + /// Executes RISC-V Store Instructions on the machine + fn store_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + let mut store = |size| { + self.write_memory( + size, + (self.int_reg.get_reg(inst.rs1) + inst.imm12_S_signed as i64) as usize, + self.int_reg.get_reg(inst.rs2) as u64 + ); + Ok(()) + }; + match inst.funct3 { + RISCV_ST_STB => store(1), + RISCV_ST_STH => store(2), + RISCV_ST_STW => store(4), + RISCV_ST_STD => store(8), + _ => Err(format!("In ST switch case, this should never happen... Instr was {}", inst.value).as_str())? + } + } + + /// Executes RISC-V Integer Register-Immediate Instructions on the machine + fn opi_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + let rs1 = self.int_reg.get_reg(inst.rs1); + let imm12 = inst.imm12_I_signed as i64; + let shamt = inst.shamt as i64; + let mut compute = |operation: &dyn Fn (i64, i64) -> i64, a, b| { + self.int_reg.set_reg(inst.rd, operation(a, b)); + Ok(()) + }; + match inst.funct3 { + RISCV_OPI_ADDI => compute(&std::ops::Add::add, rs1, imm12), + RISCV_OPI_SLTI => compute(&|a, b| (a < b) as i64, rs1, imm12), + RISCV_OPI_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12), + RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12), + RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12), + RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, imm12), + RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI { + compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt) + } else { + compute(&core::ops::Shr::shr, rs1, shamt) + } + _ => Err(format!("In OPI switch case, this should never happen... Instr was %x\n {}", inst.value))? + } + } + + /// Executes simple RISC-V mathematical operations on the machine + fn op_instruction(&mut self, 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 = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128; + self.int_reg.set_reg(inst.rd, (long_result & 0xffffffffffffffff) as i64) + }, + RISCV_OP_M_MULH => { + long_result = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128; + self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64) + }, + RISCV_OP_M_MULHSU => { + unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64; + long_result = (self.int_reg.get_reg(inst.rs1) as u64 * unsigned_reg2) as i128; + self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64) + }, + RISCV_OP_M_MULHU => { + unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64; + unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64; + long_result = (unsigned_reg1 * unsigned_reg2) as i128; + 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)), + _ => panic!("RISCV_OP : funct7 = 1 (Multiplication) :: Error\n") + } + } else { + match inst.funct3 { + RISCV_OP_ADD => if inst.funct7 == RISCV_OP_ADD_ADD { + self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) + self.int_reg.get_reg(inst.rs2)) + } else { + self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) - self.int_reg.get_reg(inst.rs2)) + }, + RISCV_OP_SLL => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) << (self.int_reg.get_reg(inst.rs2) & 0x3f)), + RISCV_OP_SLT => if self.int_reg.get_reg(inst.rs1) < self.int_reg.get_reg(inst.rs2) { + self.int_reg.set_reg(inst.rd, 1) + } else { + self.int_reg.set_reg(inst.rd, 0) + }, + RISCV_OP_SLTU => { + unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64; + unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64; + if unsigned_reg1 < unsigned_reg2 { + self.int_reg.set_reg(inst.rd, 1) + } else { + self.int_reg.set_reg(inst.rd, 0) + } + }, + RISCV_OP_XOR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) ^ self.int_reg.get_reg(inst.rs2)), + 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_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") + } + } + Ok(()) + } + + /// Exectutes simple RISC-V *iw instructions on the machine + fn opiw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + let local_data = self.int_reg.get_reg(inst.rs1); + let result = match inst.funct3 { + RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64, + 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 }, + _ => Err("In OPI switch case, this should never happen... Instr was {}\n")?, + }; + self.int_reg.set_reg(inst.rd, result); + Ok(()) + } + + /// Executes simple RISC-V *w instructions on the machine + fn opw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + if inst.funct7 == 1 { // rv64m + let local_data_a = self.int_reg.get_reg(inst.rs1) & 0xffffffff; + let local_data_b = self.int_reg.get_reg(inst.rs2) & 0xffffffff; + let local_data_a_unsigned = self.int_reg.get_reg(inst.rs1) & 0xffffffff; + let local_data_b_unsigned = self.int_reg.get_reg(inst.rs2) & 0xffffffff; + + // Match case for multiplication operations (in standard extension RV32M) + match inst.funct3 { + RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, local_data_a * local_data_b), + RISCV_OPW_M_DIVW => self.int_reg.set_reg(inst.rd, local_data_a / local_data_b), + 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_REMUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned % local_data_b_unsigned), + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + } else { // others rv64 OPW operations + let local_dataa = self.int_reg.get_reg(inst.rs1) & 0xffffffff; + let local_datab = self.int_reg.get_reg(inst.rs2) & 0xffffffff; + // Match case for base OP operation + match inst.funct3 { + RISCV_OPW_ADDSUBW => if inst.funct7 == RISCV_OPW_ADDSUBW_ADDW { + self.int_reg.set_reg(inst.rd, local_dataa + local_datab); + } else { // SUBW + self.int_reg.set_reg(inst.rd, local_dataa - local_datab); + }, + RISCV_OPW_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)), + RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW { + self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f) & self.shiftmask[32 + local_datab as usize] as i64) + } else { // SRAW + self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f)) + }, + _ => panic!("this instruction ({}) doesn't exist", inst.value) + } + } + Ok(()) + } + + /// Executes simple RISC-V floating point instructions on the machine + fn fp_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + 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_SUB => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) - self.fp_reg.get_reg(inst.rs2)), + 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_DIV => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) / self.fp_reg.get_reg(inst.rs2)), + RISCV_FP_SQRT => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1).sqrt()), + RISCV_FP_FSGN => { + let local_float = self.fp_reg.get_reg(inst.rs1); + match inst.funct3 { + RISCV_FP_FSGN_J => if self.fp_reg.get_reg(inst.rs2) < 0f32 { + self.fp_reg.set_reg(inst.rd, -local_float) + } else { + self.fp_reg.set_reg(inst.rd, local_float) + }, + RISCV_FP_FSGN_JN => if self.fp_reg.get_reg(inst.rs2) < 0f32 { + self.fp_reg.set_reg(inst.rd, local_float) + } else { + 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) || + (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) + } else { + self.fp_reg.set_reg(inst.rd, local_float) + }, + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + }, + RISCV_FP_MINMAX => { + let r1 = self.fp_reg.get_reg(inst.rs1); + let r2 = self.fp_reg.get_reg(inst.rs2); + match inst.funct3 { + 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}), + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + }, + RISCV_FP_FCVTW => { + if inst.rs2 == RISCV_FP_FCVTW_W { + self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64) + } else { + self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) as u64) as i64) + } + }, + RISCV_FP_FCVTS => { + if inst.rs2 == RISCV_FP_FCVTS_W { + self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32); + } else { + self.fp_reg.set_reg(inst.rd, (self.int_reg.get_reg(inst.rs1) as u32) as f32); + } + }, + RISCV_FP_FMVW => self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32), + RISCV_FP_FMVXFCLASS => { + if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX { + self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64); + } else { + panic!("Fclass instruction is not handled in riscv simulator"); + } + }, + RISCV_FP_FCMP => { + 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_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), + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + }, + _ => panic!("this instruction ({}) doesn't exists", inst.value) + } + Ok(()) } /// print memory FOR DEBUG /// - /// "@"adresse [16 bytes] - pub fn _print_memory(machine : &mut Machine, from: usize, to: usize) { + /// "@"adress [16 bytes] + pub fn print_memory(&self, from: usize, to: usize) { for i in from..to { if i%16 == 0 { print!("\n@{:04x} ", i); } - print!("{:02x}", machine.main_memory[i]); + print!("{:02x}", self.main_memory[i]); } println!(); } + /// Get value from int register pub fn read_int_register(&self, index: usize) -> i64 { - self.int_reg.get_reg(index) + self.int_reg.get_reg(index as u8) } + /// Get value from float register pub fn read_fp_register(&self, index: usize) -> f32 { - self.fp_reg.get_reg(index) + self.fp_reg.get_reg(index as u8) } + /// Write into int register pub fn write_int_register(&mut self, index: usize, value: i64) { - self.int_reg.set_reg(index, value); + self.int_reg.set_reg(index as u8, value); } + /// Write info float register pub fn write_fp_register(&mut self, index: usize, value: f32) { - self.fp_reg.set_reg(index, value); + self.fp_reg.set_reg(index as u8, value); } } @@ -728,6 +613,30 @@ mod test { use crate::simulator::{machine::Machine, mem_cmp}; + macro_rules! get_full_path { + ($prefix: expr, $test_name:expr) => {{ + let mut s = String::from("test/machine/"); + s.push_str($prefix); + s.push_str($test_name); + s.push_str(".txt"); + &s.to_owned() + }} + } + + macro_rules! init_test { + ($a:expr) => {{ + let mut m = Machine::init_machine(); + let end_file_name = { let mut s = String::from($a); s.push_str("End"); s }; + let memory_before = mem_cmp::MemChecker::from(get_full_path!("memory", $a)).unwrap(); + let memory_after = mem_cmp::MemChecker::from(get_full_path!("memory", &end_file_name)).unwrap(); + mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); + m.run(); + let expected_trace = fs::read_to_string(get_full_path!("reg_trace", $a)).unwrap(); + assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); + assert!(expected_trace.contains(m.registers_trace.as_str())); + }}; + } + #[test] fn test_init_machine() { let _ = Machine::init_machine(); @@ -738,16 +647,16 @@ mod test { let mut m = Machine::init_machine(); m.main_memory[4] = 43; m.main_memory[5] = 150; - assert_eq!((43 << 8) + 150, Machine::read_memory(&mut m, 2, 4)); + assert_eq!((43 << 8) + 150, m.read_memory(2, 4)); } #[test] fn test_write_memory() { let mut m = Machine::init_machine(); - Machine::write_memory(&mut m, 2, 6, (43 << 8) + 150); + m.write_memory(2, 6, (43 << 8) + 150); assert_eq!(43, m.main_memory[6]); assert_eq!(150, m.main_memory[7]); - Machine::write_memory(&mut m, 4, 8, (52 << 24) + (20 << 16) + (43 << 8) + 150); + m.write_memory(4, 8, (52 << 24) + (20 << 16) + (43 << 8) + 150); assert_eq!(52, m.main_memory[8]); assert_eq!(20, m.main_memory[9]); assert_eq!(43, m.main_memory[10]); @@ -756,127 +665,46 @@ mod test { #[test] fn test_comp() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memoryComp.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memoryCompEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceComp.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Comp") } #[test] fn test_add() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memoryAdd.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memoryAddEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceAdd.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Add") } #[test] fn test_div() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memoryDiv.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memoryDivEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceDiv.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Div") } #[test] fn test_if() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memoryIf.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memoryIfEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceIf.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("If") } #[test] fn test_jump() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memoryJump.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memoryJumpEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceJump.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Jump") } #[test] fn test_mul() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memoryMult.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memoryMultEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceMult.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Mult") } #[test] fn test_ret() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memoryRet.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memoryRetEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceRet.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Ret") } #[test] fn test_sub() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memorySub.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memorySubEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceSub.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Sub") } #[test] fn test_switch() { - let mut m = Machine::init_machine(); - let memory_before = mem_cmp::MemChecker::from("test/machine/memorySwitch.txt").unwrap(); - let memory_after = mem_cmp::MemChecker::from("test/machine/memorySwitchEnd.txt").unwrap(); - mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); - Machine::run(&mut m); - - let expected_trace = fs::read_to_string("test/machine/reg_traceSwitch.txt").unwrap(); - - assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); - assert!(expected_trace.contains(m.registers_trace.as_str())); + init_test!("Switch") } } diff --git a/src/simulator/mmu.rs b/src/simulator/mmu.rs index 780e49f..f91dcb0 100644 --- a/src/simulator/mmu.rs +++ b/src/simulator/mmu.rs @@ -29,7 +29,7 @@ impl <'a>MMU <'_>{ MMU::translate(mmu, virt_addr, &mut phy_addr_double_check, false); match exc { - ExceptionType::NO_EXCEPTION => { + ExceptionType::NoException => { if phy_addr != phy_addr_double_check { //Besoin ici d'une impl pour gestion d'exeption //dans nachos : g-machine->RaiseException(exc, virt_addr); @@ -44,7 +44,7 @@ impl <'a>MMU <'_>{ _ => { //Besoin ici d'une impl pour gestion d'exeption //dans nachos : g-machine->RaiseException(exc, virt_addr); - println!("Error from mmu_read_mem :: Exception different from NO_EXCEPTION"); + println!("Error from mmu_read_mem :: Exception different from NoException"); return false; } } @@ -63,7 +63,7 @@ impl <'a>MMU <'_>{ MMU::translate(mmu, virt_addr, &mut phy_addr_double_check, true); match exc { - ExceptionType::NO_EXCEPTION => { + ExceptionType::NoException => { if phy_addr != phy_addr_double_check { //Besoin ici d'une impl pour gestion d'exeption //dans nachos : g-machine->RaiseException(exc, virt_addr); @@ -78,7 +78,7 @@ impl <'a>MMU <'_>{ _ => { //Besoin ici d'une impl pour gestion d'exeption //dans nachos : g-machine->RaiseException(exc, virt_addr); - println!("Error from mmu_write_mem :: Exception different from NO_EXCEPTION"); + println!("Error from mmu_write_mem :: Exception different from NoException"); return false; } } @@ -96,7 +96,7 @@ impl <'a>MMU <'_>{ match &mut mmu.translationTable { None => { println!("Error from translate : MMU refers to None (No page Table)"); - return ExceptionType::ADDRESSERROR_EXCEPTION; + return ExceptionType::AddressErrorException; } Some(table_ref) => { @@ -104,7 +104,7 @@ impl <'a>MMU <'_>{ //On verifie que notre index est valide if vpn >= table_ref.get_max_num_pages(){ println!("Error from translate :: index is out of bound"); - return ExceptionType::ADDRESSERROR_EXCEPTION; + return ExceptionType::AddressErrorException; } /*Doc nachos dit que ce test sert a savoir si la page est mappée @@ -113,13 +113,13 @@ impl <'a>MMU <'_>{ */ if !table_ref.get_bit_read(vpn) && !table_ref.get_bit_write(vpn) { println!("Error from translate :: virtual page # {} not mapped",vpn); - return ExceptionType::ADDRESSERROR_EXCEPTION; + return ExceptionType::AddressErrorException; } //si on souhaite effectuer un acces lecture, on verifie que l'on dispose du droit d'acces sur cette page if writing && !table_ref.get_bit_write(vpn) { println!("Error from translate :: write access on a read only virtual page # {}",vpn); - return ExceptionType::READONLY_EXCEPTION; + return ExceptionType::AddressErrorException; } //if the page is not yet in main memory, run the page fault manager @@ -129,13 +129,13 @@ impl <'a>MMU <'_>{ println!("We need to update the page table by raising an exception -> not implemented"); //Ici il faudra reverifier le bit valid apres intervention du page fault manager - return ExceptionType::ADDRESSERROR_EXCEPTION; + return ExceptionType::AddressErrorException; } //Make sure that the physical adress is correct if table_ref.get_physical_page(vpn) < 0 || table_ref.get_physical_page(vpn) >= (NUM_PHY_PAGE as i32) { println!("Error from translate :: no valid correspondance"); - return ExceptionType::BUSERROR_EXCEPTION; + return ExceptionType::BusErrorException; } //Set U/M bits to 1 @@ -151,6 +151,6 @@ impl <'a>MMU <'_>{ } } - ExceptionType::NO_EXCEPTION + ExceptionType::NoException } } \ No newline at end of file diff --git a/src/simulator/mod.rs b/src/simulator/mod.rs index 8626048..037d545 100644 --- a/src/simulator/mod.rs +++ b/src/simulator/mod.rs @@ -1,4 +1,5 @@ pub mod machine; +pub mod error; pub mod decode; pub mod print; pub mod mem_cmp; @@ -6,7 +7,9 @@ pub mod loader; pub mod interrupt; pub mod translationtable; pub mod mmu; +pub mod register; +/// Definition of global constants pub mod global { #![allow(dead_code)] @@ -52,15 +55,15 @@ pub mod global { /// /// See func3 to know the type of instruction (LD, LW, LH, LB, LWU, LHU, LBU) pub const RISCV_LD: u8 = 0x3; - // Store instructions + /// Store instructions pub const RISCV_ST: u8 = 0x23; - // immediate Arithmetic operations + /// immediate Arithmetic operations pub const RISCV_OPI: u8 = 0x13; - // Arithmetic operations + /// Arithmetic operations pub const RISCV_OP: u8 = 0x33; /// Immediate arithmetic operations for rv64i pub const RISCV_OPIW: u8 = 0x1b; - // Arithmetic operations for rv64i + /// Arithmetic operations for rv64i pub const RISCV_OPW: u8 = 0x3b; /// Type: B diff --git a/src/simulator/register.rs b/src/simulator/register.rs new file mode 100644 index 0000000..339c0e5 --- /dev/null +++ b/src/simulator/register.rs @@ -0,0 +1,53 @@ +//! # Register +//! +//! This mod contains the definition of the Register structs +//! for use within the Machine module. + +use crate::simulator::machine::{NUM_FP_REGS, NUM_INT_REGS}; +use std::ops::{Add, Sub}; + +pub trait RegisterNum: Add + Sub + PartialEq + Copy {} + +impl RegisterNum for i64 {} + +impl RegisterNum for f32 {} + +/// Machine register array +#[derive(PartialEq)] +pub struct Register { + /// 32 available registers of type U + register: [U; 32] +} + +impl Register { + /// Returns the current value held in register *position* + pub fn get_reg(&self, position: u8) -> U { + self.register[position as usize] + } + + /// Set value of register *position* to *value* + /// + /// Checking against trying to set a new value to the 0th register + /// as its value is NOT supposed to change + pub fn set_reg(&mut self, position: u8, value: U) { + if position != 0 { self.register[position as usize] = value; } + } +} + +impl Register { + /// i64 register constructor + pub fn init() -> Register { + Register { + register: [0i64; NUM_INT_REGS] + } + } +} + +impl Register { + /// f32 register constructor + pub fn init() -> Register { + Register { + register: [0f32; NUM_FP_REGS] + } + } +} \ No newline at end of file