use std::{ops::{Add, Sub}, io::Write}; use crate::simulator::print; use super::{decode::{Instruction, decode}}; use super::global::*; use std::fs::File; /// doit disparaitre const MEM_SIZE : usize = 0x500000; pub trait RegisterNum: Add + Sub + PartialEq + Copy {} impl RegisterNum for i64 {} impl RegisterNum for f32 {} 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; } } pub struct Machine { pub pc : u64, pub sp: usize, pub int_reg : Register, pub fp_reg : Register, pub main_memory : Vec, pub shiftmask : [u64 ; 64], pub registers_trace : String // for tests // 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 } impl Machine { pub fn _init_machine() -> Machine { let mut shiftmask : [u64 ; 64] = [0 ; 64]; let mut value : u64 = 0xffffffff; value = (value << 32) + value; for item in &mut shiftmask { *item = value; value >>= 1; } let mut ret = Machine { pc : 0, sp: 0, int_reg : Register::::init(), fp_reg : Register::::init(), main_memory : vec![0; MEM_SIZE], shiftmask, registers_trace : String::from("") }; ret.int_reg.set_reg(10, -1); ret } /// Read from main memory of the machine /// /// `panic!` when size is not 1, 2, 4 or 8 /// /// ### Parameters /// /// - **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(machine : &mut Machine, 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)"); } let mut ret: u64 = 0; for i in 0..size { ret <<= 8; ret += machine.main_memory[address + i as usize] as u64; } ret } /// Write to the main memory of the machine /// /// `panic!` when size is not 1, 2, 4 or 8 /// /// ### Parameters /// /// - **machine** contains the memory /// - **size** the number of bytes to write (1, 2, 4 or 8) /// - **address** the address to write to /// - **value** data to be written pub fn write_memory(machine: &mut Machine, size: i32, address: usize, value: u64) { if ![1, 2, 4, 8].contains(&size) { panic!("ERROR write_memory: WRONG `size` PARAMETER ({size}), must be 1, 2, 4 or 8") } for i in 0..size as usize { let inv_i = size as usize - i - 1; machine.main_memory[address + i] = ((value & 0xff << (8 * inv_i)) >> (inv_i * 8)) as u8; } } /// Write the contains of the main memory of the machine /// in a file called burritos_memory.txt /// /// ### Parameters /// /// - **machine** contains the memory pub fn extract_memory(machine: &mut Machine){ let file_path = "burritos_memory.txt"; let write_to_file = |path| -> std::io::Result { let mut file = File::create(path)?; file.write_all(&machine.main_memory)?; Ok(file) }; match write_to_file(file_path) { Err(e) => eprintln!("Failed to write memory to file: {}", e), Ok(_) => println!("Memory extracted to {}", file_path) }; } pub fn print_machine_status(machine: &mut Machine) { println!("######### Machine status #########"); for i in (0..32).step_by(3) { print!(">{0: <4} : {1:<16x} ", print::REG_X[i], machine.int_reg.get_reg(i)); print!(">{0: <4} : {1:<16x} ", print::REG_X[i+1], machine.int_reg.get_reg(i+1)); if i+2 < 32 { print!(">{0: <4} : {1:<16x} ", print::REG_X[i+2], machine.int_reg.get_reg(i+2)); } println!(); } println!("________________SP________________"); let sp_index = machine.int_reg.get_reg(2); for i in 0..5 { println!("SP+{:<2} : {:16x}", i*8, Self::read_memory(machine, 8, (sp_index + i*8) as usize)); } println!("##################################"); } pub fn string_registers(machine: &mut Machine) -> String { let mut s = String::from(""); for i in 0..32 { s.push_str(format!("{} ", machine.int_reg.get_reg(i)).as_str()); } s } /// Execute the instructions table of a machine putted in param /// /// ### Parameters /// /// - **machine** which contains a table of instructions pub fn run(machine : &mut Machine){ while Machine::one_instruction(machine) == 0 {} println!("trace : \n{}", machine.registers_trace); } /// 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;*/ if machine.main_memory.len() <= machine.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]; } 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()); machine.pc += 4; match inst.opcode { RISCV_LUI => { machine.int_reg.set_reg(inst.rd as usize, inst.imm31_12 as i64); }, RISCV_AUIPC => { machine.int_reg.set_reg(inst.rd as usize,machine.pc as i64 - 4 + inst.imm31_12 as i64); }, 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; }, 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); }, //****************************************************************************************** // 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); } } }, //****************************************************************************************** // 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); } } } //****************************************************************************************** // 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, if machine.int_reg.get_reg(inst.rs1 as usize) < inst.imm12_I_signed as i64 { 1 } else { 0 } ); }, 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 } }, //****************************************************************************************** // 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 { result = (local_data >> inst.shamt) & machine.shiftmask[32 + inst.shamt as usize] as i64; } else { // SRAIW result = 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); } } }, //****************************************************************************************** // 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); } } } }, //****************************************************************************************** // 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, if machine.fp_reg.get_reg(inst.rs1 as usize) == machine.fp_reg.get_reg(inst.rs2 as usize) {1} else {0}); }, RISCV_FP_FCMP_FLT => { machine.int_reg.set_reg(inst.rd as usize, if machine.fp_reg.get_reg(inst.rs1 as usize) < machine.fp_reg.get_reg(inst.rs2 as usize) {1} else {0}); }, RISCV_FP_FCMP_FLE => { machine.int_reg.set_reg(inst.rd as usize, if machine.fp_reg.get_reg(inst.rs1 as usize) <= machine.fp_reg.get_reg(inst.rs2 as usize) {1} else {0}); }, _ => { 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)}, } return 0; } /// print memory FOR DEBUG /// /// "@"adresse [16 bytes] pub fn print_memory(machine : &mut Machine, from: usize, to: usize) { for i in from..to { if i%16 == 0 { print!("\n@{:04x} ", i); } print!("{:02x}", machine.main_memory[i]); } println!(); } } #[cfg(test)] mod test { use std::fs; use crate::simulator::{machine::Machine, mem_cmp}; #[test] fn test_read_memory() { 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)); } #[test] fn test_write_memory() { let mut m = Machine::_init_machine(); Machine::write_memory(&mut m, 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); assert_eq!(52, m.main_memory[8]); assert_eq!(20, m.main_memory[9]); assert_eq!(43, m.main_memory[10]); assert_eq!(150, m.main_memory[11]); } #[test] fn test_comp() { let mut m = Machine::_init_machine(); let path_before = "memoryComp.txt".to_string(); let path_after = "memoryCompEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memoryCompTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } #[test] fn test_div() { let mut m = Machine::_init_machine(); let path_before = "memoryDiv.txt".to_string(); let path_after = "memoryDivEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memoryDivTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } #[test] fn test_if() { let mut m = Machine::_init_machine(); let path_before = "memoryIf.txt".to_string(); let path_after = "memoryIfEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memoryIfTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } #[test] fn test_jump() { let mut m = Machine::_init_machine(); let path_before = "memoryJump.txt".to_string(); let path_after = "memoryJumpEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memoryJumpTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } #[test] fn test_mul() { let mut m = Machine::_init_machine(); let path_before = "memoryMul.txt".to_string(); let path_after = "memoryMulEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memoryMulTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } #[test] fn test_ret() { let mut m = Machine::_init_machine(); let path_before = "memoryRet.txt".to_string(); let path_after = "memoryRetEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memoryRetTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } #[test] fn test_sub() { let mut m = Machine::_init_machine(); let path_before = "memorySub.txt".to_string(); let path_after = "memorySubEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memorySubTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } #[test] fn test_switch() { let mut m = Machine::_init_machine(); let path_before = "memorySwitch.txt".to_string(); let path_after = "memorySwitchEnd.txt".to_string(); let memory_before = mem_cmp::MemChecker::from(&path_before); let memory_after = mem_cmp::MemChecker::from(&path_after); mem_cmp::MemChecker::fill_memory_from_mem_checker(&memory_before, &mut m); Machine::run(&mut m); let path_trace = "memorySwitchTrace.txt".to_string(); let expected_trace = fs::read_to_string(path_trace).unwrap(); assert!(mem_cmp::MemChecker::compare_machine_memory(&memory_after, &m)); assert!(expected_trace.contains(m.registers_trace.as_str())); } }