Moving files to simulator module

This commit is contained in:
Quentin Legot
2023-01-11 14:58:12 +01:00
parent 27cd7d35c7
commit b1909e3280
5 changed files with 9 additions and 8 deletions

95
src/simulator/decode.rs Normal file
View File

@ -0,0 +1,95 @@
use core::num::Wrapping; // Permet d'autoriser les overflow pour les opérations voulues
#[allow(non_snake_case)] // supprimer le warning snake case (quand les noms de variables ont des majuscules)
#[derive(Debug)]
pub struct Instruction {
pub value : u64,
pub opcode : u8,
pub rs1 : u8,
pub rs2 : u8,
pub rs3 : u8,
pub rd : u8,
pub funct7 : u8,
pub funct7_smaller : u8,
pub funct3 : u8,
pub shamt : u8,
pub imm12_I : u16,
pub imm12_S : u16,
pub imm12_I_signed : i16,
pub imm12_S_signed : i16,
pub imm13 : i16,
pub imm13_signed : i16,
pub imm31_12 : u32,
pub imm21_1 : u32,
pub imm31_12_signed : i32,
pub imm21_1_signed : i32,
}
#[allow(non_snake_case)]
pub fn decode(val : u64) -> Instruction {
let value = val;
let opcode = (val & 0x7f) as u8;
let rs1 = ((val >> 15) & 0x1f) as u8;
let rs2 = ((val >> 20) & 0x1f) as u8;
let rs3 = ((val >> 27) & 0x1f) as u8;
let rd = ((val >> 7) & 0x1f) as u8;
let funct7 = ((val >> 25) & 0x7f) as u8;
let funct7_smaller = (funct7 & 0x3e) as u8;
let funct3 = ((val >> 12) & 0x7) as u8;
let imm12_I = ((val >> 20) & 0xfff) as u16;
let imm12_S = (((val >> 20) & 0xfe0) + ((val >> 7) & 0x1f)) as u16;
let imm12_I_signed = if imm12_I >= 2048 { (Wrapping(imm12_I) - Wrapping(4096)).0 } else { imm12_I } as i16;
let imm12_S_signed = if imm12_S >= 2048 { (Wrapping(imm12_S) - Wrapping(4096)).0 } else { imm12_S } as i16;
let imm13 = (((val >> 19) & 0x1000) + ((val >> 20) & 0x7e0) +
((val >> 7) & 0x1e) + ((val << 4) & 0x800)) as i16;
let imm13_signed = if imm13 >= 4096 { imm13 - 8192 } else { imm13 } as i16;
let imm31_12 = (val & 0xfffff000) as u32;
let imm31_12_signed = imm31_12 as i32;
let imm21_1 = ((val & 0xff000) + ((val >> 9) & 0x800) +
((val >> 20) & 0x7fe) + ((val >> 11) & 0x100000)) as u32;
let imm21_1_signed = if imm21_1 >= 1048576 { (Wrapping(imm21_1) - Wrapping(2097152)).0 } else { imm21_1 } as i32;
let shamt = ((val >> 20) & 0x3f) as u8;
Instruction {
value : value,
opcode : opcode,
rs1 : rs1,
rs2 : rs2,
rs3 : rs3,
rd : rd,
funct7 : funct7,
funct7_smaller : funct7_smaller,
funct3 : funct3,
imm12_I : imm12_I,
imm12_S : imm12_S,
imm12_I_signed : imm12_I_signed,
imm12_S_signed : imm12_S_signed,
imm13 : imm13,
imm13_signed : imm13_signed,
imm31_12 : imm31_12,
imm31_12_signed : imm31_12_signed,
imm21_1 : imm21_1,
imm21_1_signed : imm21_1_signed,
shamt : shamt
}
}

383
src/simulator/machine.rs Normal file
View File

@ -0,0 +1,383 @@
use super::{decode::{Instruction, decode}, print::*};
/// doit disparaitre
const MEM_SIZE : usize= 4096;
pub struct Machine {
pub pc : u64,
pub int_reg : [i64 ; 32],
pub instructions : [u64 ; 100],
pub main_memory : [u8 ; MEM_SIZE],
pub shiftmask : [u64 ; 64]
// 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 i in 0..64 {
shiftmask[i] = value;
value = value >> 1;
}
Machine {
pc : 0,
instructions : [0 ; 100],
int_reg : [0 ; 32],
main_memory : [0 ; MEM_SIZE],
shiftmask : shiftmask
}
}
/// Read from main memory of the machine
///
/// ### 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 size != 1 && size != 2 && size != 4 && size != 8 {
println!("ERROR read_memory : wrong size parameter {}, must be (1, 2, 4 or 8)", size);
}
let mut ret : u64 = machine.main_memory[address] as u64;
if size == 2 || size == 4 || size == 8 {
ret = ret << 8;
ret += machine.main_memory[address + 1] as u64;
}
if size == 4 || size == 8 {
ret = ret << 8;
ret += machine.main_memory[address + 2] as u64;
}
if size == 8 {
ret = ret << 8;
ret += machine.main_memory[address + 3] as u64;
}
return ret;
}
/// Execute the instructions table of a machine putted in param
///
/// ### Parameters
///
/// - **machine** which contains a table of instructions
pub fn run(machine : Machine){
let mut m = machine;
loop{
Machine::one_instruction(&mut m);
}
}
/// 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) {
let mut unsigned_reg1 : u64 = 0;
let mut unsigned_reg2 : u64 = 0;
let mut long_result : i128 = 0;
/*__int128 longResult;
int32_t localDataa, localDatab;
int64_t localLongResult;
uint32_t localDataaUnsigned, localDatabUnsigned;
int32_t localResult;
float localFloat;
uint64_t value;*/
if machine.instructions.len() <= machine.pc as usize {
println!("ERROR : number max of instructions rushed");
return ;
}
let inst : Instruction = decode(machine.instructions[machine.pc as usize]);
match inst.opcode {
RISCV_LUI => {
machine.int_reg[inst.rd as usize] = inst.imm31_12 as i64;
},
RISCV_AUIPC => {
machine.int_reg[inst.rd as usize] = machine.pc as i64 - 4 + inst.imm31_12 as i64;
},
RISCV_JAL => {
machine.int_reg[inst.rd as usize] = machine.pc as i64;
machine.pc += inst.imm21_1_signed as u64 - 4;
},
RISCV_JALR => {
let tmp = machine.pc;
machine.pc = (machine.int_reg[inst.rs1 as usize] as u64 + inst.imm12_I_signed as u64) & 0xfffffffe;
machine.int_reg[inst.rd as usize] = tmp as i64;
},
//******************************************************************************************
// Treatment for: BRANCH INSTRUCTIONS
RISCV_BR => {
match inst.funct3 {
RISCV_BR_BEQ => {
if machine.int_reg[inst.rs1 as usize] == machine.int_reg[inst.rs2 as usize] {
machine.pc += inst.imm13_signed as u64 - 4;
}
},
RISCV_BR_BNE => {
if machine.int_reg[inst.rs1 as usize] != machine.int_reg[inst.rs2 as usize] {
machine.pc += inst.imm13_signed as u64 - 4;
}
},
RICV_BR_BLT => {
if machine.int_reg[inst.rs1 as usize] < machine.int_reg[inst.rs2 as usize] {
machine.pc += inst.imm13_signed as u64 - 4;
}
},
RICV_BR_BGE => {
if machine.int_reg[inst.rs1 as usize] >= machine.int_reg[inst.rs2 as usize] {
machine.pc += inst.imm13_signed as u64 - 4;
}
},
RICV_BR_BLTU => {
if machine.int_reg[inst.rs1 as usize] < machine.int_reg[inst.rs2 as usize] {
machine.pc += inst.imm13_signed as u64 - 4;
}
},
RICV_BR_BGEU => {
if machine.int_reg[inst.rs1 as usize] >= machine.int_reg[inst.rs2 as usize] {
machine.pc += inst.imm13_signed as u64 - 4;
}
},
_ => {
println!("In BR switch case, this should never happen... Instr was {}", inst.value);
}
}
},
//******************************************************************************************
// Treatment for: LOAD INSTRUCTIONS
RISCV_LD => {
match inst.funct3 {
RISCV_LD_LB => {
machine.int_reg[inst.rd as usize] = Self::read_memory(machine, 1, (inst.rs1 as i16 + inst.imm12_I_signed) as usize) as i64;
},
RISCV_LD_LH => {
machine.int_reg[inst.rd as usize] = Self::read_memory(machine, 2, (inst.rs1 as i16 + inst.imm12_I_signed) as usize) as i64;
},
RISCV_LD_LW => {
machine.int_reg[inst.rd as usize] = Self::read_memory(machine, 4, (inst.rs1 as i16 + inst.imm12_I_signed) as usize) as i64;
},
RISCV_LD_LD => {
machine.int_reg[inst.rd as usize] = Self::read_memory(machine, 8, (inst.rs1 as i16 + inst.imm12_I_signed) as usize) as i64;
},
// same thing three opration ?
RISCV_LD_LBU => {
machine.int_reg[inst.rd as usize] = Self::read_memory(machine, 1, (inst.rs1 as i16 + inst.imm12_I_signed) as usize) as i64;
},
RISCV_LD_LHU => {
machine.int_reg[inst.rd as usize] = Self::read_memory(machine, 2, (inst.rs1 as i16 + inst.imm12_I_signed) as usize) as i64;
},
RISCV_LD_LWU => {
machine.int_reg[inst.rd as usize] = Self::read_memory(machine, 4, (inst.rs1 as i16 + inst.imm12_I_signed) as usize) as i64;
},
_ => {
println!("In LD switch case, this should never happen... Instr was {}", inst.value);
}
}
},
//TODO store instructions
//******************************************************************************************
// Treatment for: OPI INSTRUCTIONS
RISCV_OPI => {
match inst.funct3 {
RISCV_OPI_ADDI => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] + inst.imm12_I_signed as i64;
},
RISCV_OPI_SLTI => {
machine.int_reg[inst.rd as usize] =
if machine.int_reg[inst.rs1 as usize] < inst.imm12_I_signed as i64 { 1 } else { 0 };
},
RISCV_OPI_XORI => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] ^ inst.imm12_I_signed as i64;
},
RISCV_OPI_ORI => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] | inst.imm12_I_signed as i64;
},
RISCV_OPI_ANDI => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] & inst.imm12_I_signed as i64;
},
RISCV_OPI_SLLI => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] << inst.shamt;
},
RISCV_OPI_SRI => {
if inst.funct7_smaller == RISCV_OPI_SRI_SRLI {
machine.int_reg[inst.rd as usize] = (machine.int_reg[inst.rs1 as usize] >> inst.shamt) & machine.shiftmask[inst.shamt as usize] as i64;
} else { // SRAI
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] >> inst.shamt;
}
}
_ => { println!("{} inconnu", inst.funct3); }
}
},
RISCV_OP => {
if inst.funct7 == 1{
match inst.funct3 {
RISCV_OP_M_MUL => {
long_result = (machine.int_reg[inst.rs1 as usize] * machine.int_reg[inst.rs2 as usize]) as i128;
machine.int_reg[inst.rd as usize] = (long_result & 0xffffffffffffffff) as i64;
},
RISCV_OP_M_MULH => {
long_result = (machine.int_reg[inst.rs1 as usize] * machine.int_reg[inst.rs2 as usize]) as i128;
},
RISCV_OP_M_MULHSU => {
unsigned_reg2 = machine.int_reg[inst.rs2 as usize] as u64;
long_result = (machine.int_reg[inst.rs1 as usize] as u64 * unsigned_reg2) as i128;
machine.int_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[inst.rs1 as usize] as u64;
unsigned_reg2 = machine.int_reg[inst.rs2 as usize] as u64;
long_result = (unsigned_reg1 * unsigned_reg2) as i128;
machine.int_reg[inst.rd as usize] = ((long_result >> 64) & 0xffffffffffffffff) as i64;
},
RISCV_OP_M_DIV => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] / machine.int_reg[inst.rs2 as usize];
}
_ => {
println!("RISCV_OP : funct7 = 1 (Multiplication) :: Error\n");
}
}
} else {
match inst.funct3 {
RISCV_OP_ADD => {
if (inst.funct7 == RISCV_OP_ADD_ADD) {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] + machine.int_reg[inst.rs2 as usize];
} else {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] - machine.int_reg[inst.rs2 as usize];
}
},
RISCV_OP_SLL => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] << (machine.int_reg[inst.rs2 as usize] & 0x3f);
},
RISCV_OP_SLT => {
if machine.int_reg[inst.rs1 as usize] < machine.int_reg[inst.rs2 as usize] {
machine.int_reg[inst.rd as usize] = 1;
} else {
machine.int_reg[inst.rd as usize] = 0;
}
},
RISCV_OP_SLTU => {
unsigned_reg1 = machine.int_reg[inst.rs1 as usize] as u64;
unsigned_reg2 = machine.int_reg[inst.rs2 as usize] as u64;
if unsigned_reg1 < unsigned_reg2 {
machine.int_reg[inst.rd as usize] = 1;
} else {
machine.int_reg[inst.rd as usize] = 0;
}
},
RISCV_OP_XOR => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] ^ machine.int_reg[inst.rs2 as usize];
},
RISCV_OP_SR => {
// RISCV_OP_SR_SRL inaccessible
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] >> (machine.int_reg[inst.rs2 as usize] & 0x3f);
},
RISCV_OP_OR => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] | machine.int_reg[inst.rs2 as usize];
},
RISCV_OP_AND => {
machine.int_reg[inst.rd as usize] = machine.int_reg[inst.rs1 as usize] & machine.int_reg[inst.rs2 as usize];
},
_ => {
println!("RISCV_OP undefined case\n");
}
}//LA
}
},
//******************************************************************************************
// Treatment for: OPW INSTRUCTIONS
RISCV_OPW => {
if inst.funct7 == 1 {
let localDataa = machine.int_reg[inst.rs1 as usize] & 0xffffffff;
let localDatab = machine.int_reg[inst.rs2 as usize] & 0xffffffff;
let localDataaUnsigned = machine.int_reg[inst.rs1 as usize] & 0xffffffff;
let localDatabUnsigned = machine.int_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[inst.rd as usize] = localDataa * localDatab;
},
RISCV_OPW_M_DIVW => {
machine.int_reg[inst.rd as usize] = localDataa / localDatab;
},
RISCV_OPW_M_DIVUW => {
machine.int_reg[inst.rd as usize] = localDataaUnsigned / localDatabUnsigned;
},
RISCV_OPW_M_REMW => {
machine.int_reg[inst.rd as usize] = localDataa % localDatab;
},
RISCV_OPW_M_REMUW => {
machine.int_reg[inst.rd as usize] = localDataaUnsigned % localDatabUnsigned;
},
_ => {
println!("this instruction ({}) doesn't exists", inst.value);
}
}
} else {
let local_dataa = machine.int_reg[inst.rs1 as usize] & 0xffffffff;
let local_datab = machine.int_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[inst.rd as usize] = local_dataa + local_datab;
} else { // SUBW
machine.int_reg[inst.rd as usize] = local_dataa - local_datab;
}
},
RISCV_OPW_SLLW => {
machine.int_reg[inst.rd as usize] = local_dataa << (local_datab & 0x1f);
},
RISCV_OPW_SRW => {
if inst.funct7 == RISCV_OPW_SRW_SRLW {
machine.int_reg[inst.rd as usize] = local_dataa >> (local_datab & 0x1f) & machine.shiftmask[32 + local_datab as usize] as i64;
} else { // SRAW
machine.int_reg[inst.rd as usize] = local_dataa >> (local_datab & 0x1f);
}
},
_ => {
println!("this instruction ({}) doesn't exists", inst.value);
}
}
}
}
_ => { println!("{} opcode non géré", inst.opcode)},
}
machine.pc += 4;
}
}
#[cfg(test)]
mod test {
use super::Machine;
}

3
src/simulator/mod.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod machine;
pub mod decode;
pub mod print;

415
src/simulator/print.rs Normal file
View File

@ -0,0 +1,415 @@
#![allow(dead_code)]
#![allow(unused_variables)]
use super::decode::{Instruction};
pub const RISCV_LUI: u8 = 0x37;
pub const RISCV_AUIPC: u8 = 0x17;
pub const RISCV_JAL: u8 = 0x6f;
pub const RISCV_JALR: u8 = 0x67;
pub const RISCV_BR: u8 = 0x63;
pub const RISCV_LD: u8 = 0x3;
pub const RISCV_ST: u8 = 0x23;
pub const RISCV_OPI: u8 = 0x13;
pub const RISCV_OP: u8 = 0x33;
pub const RISCV_OPIW: u8 = 0x1b;
pub const RISCV_OPW: u8 = 0x3b;
pub const RISCV_BR_BEQ: u8 = 0x0;
pub const RISCV_BR_BNE: u8 = 0x1;
pub const RISCV_BR_BLT: u8 = 0x4;
pub const RISCV_BR_BGE: u8 = 0x5;
pub const RISCV_BR_BLTU: u8 = 0x6;
pub const RISCV_BR_BGEU: u8 = 0x7;
pub const RISCV_LD_LB: u8 = 0x0;
pub const RISCV_LD_LH: u8 = 0x1;
pub const RISCV_LD_LW: u8 = 0x2;
pub const RISCV_LD_LD: u8 = 0x3;
pub const RISCV_LD_LBU: u8 = 0x4;
pub const RISCV_LD_LHU: u8 = 0x5;
pub const RISCV_LD_LWU: u8 = 0x6;
pub const RISCV_ST_STH: u8 = 0x1;
pub const RISCV_ST_STW: u8 = 0x2;
pub const RISCV_ST_STB: u8 = 0x0;
pub const RISCV_ST_STD: u8 = 0x3;
pub const RISCV_OPI_ADDI: u8 = 0x0;
pub const RISCV_OPI_SLTI: u8 = 0x2;
pub const RISCV_OPI_SLTIU: u8 = 0x3;
pub const RISCV_OPI_XORI: u8 = 0x4;
pub const RISCV_OPI_ORI: u8 = 0x6;
pub const RISCV_OPI_ANDI: u8 = 0x7;
pub const RISCV_OPI_SLLI: u8 = 0x1;
pub const RISCV_OPI_SRI: u8 = 0x5;
pub const RISCV_OPI_SRI_SRAI: u8 = 0x20;
pub const RISCV_OPI_SRI_SRLI: u8 = 0x0;
pub const RISCV_OP_ADD: u8 = 0x0;
pub const RISCV_OP_SLL: u8 = 0x1;
pub const RISCV_OP_SLT: u8 = 0x2;
pub const RISCV_OP_SLTU: u8 = 0x3;
pub const RISCV_OP_XOR: u8 = 0x4;
pub const RISCV_OP_SR: u8 = 0x5;
pub const RISCV_OP_OR: u8 = 0x6;
pub const RISCV_OP_AND: u8 = 0x7;
pub const RISCV_OP_ADD_ADD: u8 = 0x0;
pub const RISCV_OP_ADD_SUB: u8 = 0x20;
pub const RISCV_OP_SR_SRL: u8 = 0x0;
pub const RISCV_OP_SR_SRA: u8 = 0x20;
pub const RISCV_SYSTEM: u8 = 0x73;
pub const RISCV_OPIW_ADDIW: u8 = 0x0;
pub const RISCV_OPIW_SLLIW: u8 = 0x1;
pub const RISCV_OPIW_SRW: u8 = 0x5;
pub const RISCV_OPIW_SRW_SRLIW: u8 = 0x0;
pub const RISCV_OPIW_SRW_SRAIW: u8 = 0x20;
pub const RISCV_OPW_ADDSUBW: u8 = 0x0;
pub const RISCV_OPW_SLLW: u8 = 0x1;
pub const RISCV_OPW_SRW: u8 = 0x5;
pub const RISCV_OPW_ADDSUBW_ADDW: u8 = 0x0;
pub const RISCV_OPW_ADDSUBW_SUBW: u8 = 0x20;
pub const RISCV_OPW_SRW_SRLW: u8 = 0x0;
pub const RISCV_OPW_SRW_SRAW: u8 = 0x20;
pub const RISCV_SYSTEM_ENV: u8 = 0x0;
pub const RISCV_SYSTEM_ENV_ECALL: u8 = 0x0;
pub const RISCV_SYSTEM_ENV_EBREAK: u8 = 0x1;
pub const RISCV_SYSTEM_CSRRS: u8 = 0x2;
pub const RISCV_SYSTEM_CSRRW: u8 = 0x1;
pub const RISCV_SYSTEM_CSRRC: u8 = 0x3;
pub const RISCV_SYSTEM_CSRRWI: u8 = 0x5;
pub const RISCV_SYSTEM_CSRRSI: u8 = 0x6;
pub const RISCV_SYSTEM_CSRRCI: u8 = 0x7;
pub const RISCV_FLW: u8 = 0x07;
pub const RISCV_FSW: u8 = 0x27;
pub const RISCV_FMADD: u8 = 0x43;
pub const RISCV_FMSUB: u8 = 0x47;
pub const RISCV_FNMSUB: u8 = 0x4b;
pub const RISCV_FNMADD: u8 = 0x4f;
pub const RISCV_FP: u8 = 0x53;
pub const RISCV_FP_ADD: u8 = 0x0;
pub const RISCV_FP_SUB: u8 = 0x4;
pub const RISCV_FP_MUL: u8 = 0x8;
pub const RISCV_FP_DIV: u8 = 0xc;
pub const RISCV_FP_SQRT: u8 = 0x2c;
pub const RISCV_FP_FSGN: u8 = 0x10;
pub const RISCV_FP_MINMAX: u8 = 0x14;
pub const RISCV_FP_FCVTW: u8 = 0x60;
pub const RISCV_FP_FMVXFCLASS: u8 = 0x70;
pub const RISCV_FP_FCMP: u8 = 0x50;
pub const RISCV_FP_FEQS: u8 = 0x53;
pub const RISCV_FP_FCVTS: u8 = 0x68;
pub const RISCV_FP_FCVTDS: u8 = 0x21;
pub const RISCV_FP_FSGN_J: u8 = 0x0;
pub const RISCV_FP_FSGN_JN: u8 = 0x1;
pub const RISCV_FP_FSGN_JX: u8 = 0x2;
pub const RISCV_FP_MINMAX_MIN: u8 = 0x0;
pub const RISCV_FP_MINMAX_MAX: u8 = 0x1;
pub const RISCV_FP_FCVTW_W: u8 = 0x0;
pub const RISCV_FP_FCVTW_WU: u8 = 0x1;
pub const RISCV_FP_FCVTS_W: u8 = 0x0;
pub const RISCV_FP_FCVTS_WU: u8 = 0x1;
pub const RISCV_FP_FMVXFCLASS_FMVX: u8 = 0x0;
pub const RISCV_FP_FMVXFCLASS_FCLASS: u8 = 0x1;
pub const RISCV_FP_FCMP_FEQ: u8 = 2;
pub const RISCV_FP_FCMP_FLT: u8 = 1;
pub const RISCV_FP_FCMP_FLE: u8 = 0;
pub const RISCV_FP_FMVW: u8 = 0x78;
pub const RISCV_OP_M: u8 = 0x1;
pub const RISCV_OP_M_MUL: u8 = 0x0;
pub const RISCV_OP_M_MULH: u8 = 0x1;
pub const RISCV_OP_M_MULHSU: u8 = 0x2;
pub const RISCV_OP_M_MULHU: u8 = 0x3;
pub const RISCV_OP_M_DIV: u8 = 0x4;
pub const RISCV_OP_M_DIVU: u8 = 0x5;
pub const RISCV_OP_M_REM: u8 = 0x6;
pub const RISCV_OP_M_REMU: u8 = 0x7;
pub const RISCV_OPW_M_MULW: u8 = 0x0;
pub const RISCV_OPW_M_DIVW: u8 = 0x4;
pub const RISCV_OPW_M_DIVUW: u8 = 0x5;
pub const RISCV_OPW_M_REMW: u8 = 0x6;
pub const RISCV_OPW_M_REMUW: u8 = 0x7;
pub const RISCV_FENCE: u8 = 0x0f;
pub const RISCV_ATOM: u8 = 0x2f;
pub const RISCV_ATOM_LR: u8 = 0x2;
pub const RISCV_ATOM_SC: u8 = 0x3;
pub const RISCV_ATOM_SWAP: u8 = 0x1;
pub const RISCV_ATOM_ADD: u8 = 0;
pub const RISCV_ATOM_XOR: u8 = 0x4;
pub const RISCV_ATOM_AND: u8 = 0xc;
pub const RISCV_ATOM_OR: u8 = 0x8;
pub const RISCV_ATOM_MIN: u8 = 0x10;
pub const RISCV_ATOM_MAX: u8 = 0x14;
pub const RISCV_ATOM_MINU: u8 = 0x18;
pub const RISCV_ATOM_MAXU: u8 = 0x1c;
const names_op: [&str; 8] = ["add", "sll", "slt", "sltu", "xor", "sr", "or", "and"];
const names_opi: [&str; 8] = ["addi", "slli", "slti", "sltiu", "xori", "slri", "ori", "andi"];
const names_mul: [&str; 8] = ["mpylo", "mpyhi", "mpyhi", "mpyhi", "divhi", "divhi", "divlo", "divlo"];
const names_br: [&str; 8] = ["beq", "bne", "", "", "blt", "bge", "bltu", "bgeu"];
const names_st: [&str; 4] = ["sb", "sh", "sw", "sd"];
const names_ld: [&str; 7] = ["lb", "lh", "lw", "ld", "lbu", "lhu", "lwu"];
const names_opw: [&str; 8] = ["addw", "sllw", "", "", "", "srw", "", ""];
const names_opiw: [&str; 8] = ["addiw", "slliw", "", "", "", "sri", "", ""];
// Register name mapping
const reg_x: [&str; 32] = ["zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", // fp ou s0 ?
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
"s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
"t3", "t4", "t5", "t6"];
const _reg_f: [&str; 32] = ["ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1",
"fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7",
"fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11",
"ft8", "ft9", "ft10", "ft11"];
pub fn print(ins: Instruction, pc: i32) -> String { //TODO pc should be u64
let rd = ins.rd as usize;
let rs1 = ins.rs1 as usize;
let rs2 = ins.rs2 as usize;
match ins.opcode {
RISCV_OP => {
let name: &str;
if ins.funct7 == 1 { // Use mul array
name = names_mul[ins.funct3 as usize]
} else {
if ins.funct3 == RISCV_OP_ADD {
// Add or Sub
if ins.funct7 == RISCV_OP_ADD_ADD {
name = "add";
} else {
name = "sub";
}
} else if ins.funct3 == RISCV_OP_SR {
// Srl or Sra
if ins.funct7 == RISCV_OP_SR_SRL {
name = "srl";
} else {
name = "sra";
}
} else {
name = names_op[ins.funct3 as usize];
}
}
format!("{}\t{}, {}, {}", name.to_string(), reg_x[rd], reg_x[rs1], reg_x[rs2])
},
RISCV_OPI => {
// SHAMT OR IMM
if ins.funct3 == RISCV_OPI_SRI {
if ins.funct7 == RISCV_OPI_SRI_SRLI {
format!("slrii\t{}, {}, {}", reg_x[rd], reg_x[rs1], ins.shamt.to_string())
} else {
format!("srai\t{}, {}, {}", reg_x[rd], reg_x[rs1], ins.shamt.to_string())
}
} else if ins.funct3 == RISCV_OPI_SLLI {
format!("{}\t{}, {}, {}", names_opi[ins.funct3 as usize], reg_x[rd], reg_x[rs1], ins.shamt.to_string())
} else {
format!("{}\t{}, {}, {}", names_opi[ins.funct3 as usize], reg_x[rd], reg_x[rs1], ins.imm12_I_signed.to_string())
}
},
RISCV_LUI => {
format!("lui\t{}, 0x{:X}", reg_x[rd], ins.imm31_12)
},
RISCV_AUIPC => {
format!("auipc\t{}, {:X}", reg_x[rd], ins.imm31_12)
},
RISCV_JAL => {
if ins.rd == 0 {
format!("j\t{}", ins.imm31_12.to_string())
} else {
format!("jal\t{}, {:X}", reg_x[rd], (pc - 4 + ins.imm21_1_signed))
}
},
RISCV_JALR => {
if ins.rd == 0 {
if ins.rs1 == 1 {
"ret".to_string()
} else {
format!("jr\t{:X}", ins.imm31_12)
}
} else {
format!("jalr\t{}, ({})", ins.imm12_I_signed.to_string(), reg_x[rs1])
}
},
RISCV_BR => {
format!("{}\t{}, {}, {}", names_br[ins.funct3 as usize].to_string(), reg_x[rs1], reg_x[rs2], ins.imm13_signed.to_string())
},
RISCV_LD => {
format!("{}\t{}, {}({})", names_ld[ins.funct3 as usize].to_string(), reg_x[rd], ins.imm12_I_signed.to_string(), reg_x[rs1])
},
RISCV_ST => {
format!("{}\t{}, {}({})", names_st[ins.funct3 as usize].to_string(), reg_x[rs2], ins.imm12_S_signed.to_string(), reg_x[rs1])
},
RISCV_OPIW => {
if ins.funct3 == RISCV_OPIW_SRW {
if ins.funct7 == RISCV_OPIW_SRW_SRLIW {
format!("srlwi\t{}, {}, {}", reg_x[rd], reg_x[rs1], reg_x[rs2])
} else {
format!("srawi\t{}, {}, {}", reg_x[rd], reg_x[rs1], reg_x[rs2])
}
} else if ins.funct3 == RISCV_OPIW_SLLIW {
format!("{}\t{}, {}, {}", names_opi[ins.funct3 as usize], reg_x[rd], reg_x[rs1], reg_x[rs2])
} else {
format!("{}\t{}, {}, {}", names_opiw[ins.funct3 as usize], reg_x[rd], reg_x[rs1], ins.imm12_I_signed.to_string())
}
},
RISCV_OPW => {
if ins.funct7 == 1 {
format!("{}w\t{}, {}, {}", names_mul[ins.funct3 as usize].to_string(), reg_x[rd], reg_x[rs1], reg_x[rs2])
} else {
if ins.funct3 == RISCV_OP_ADD {
if ins.funct7 == RISCV_OPW_ADDSUBW_ADDW {
format!("addw\t{}, {}, {}", reg_x[rd], reg_x[rs1], reg_x[rs2])
} else {
format!("subw\t{}, {}, {}", reg_x[rd], reg_x[rs1], reg_x[rs2])
}
} else if ins.funct3 == RISCV_OPW_SRW {
if ins.funct7 == RISCV_OPW_SRW_SRLW {
format!("srlw\t{}, {}, {}", reg_x[rd], reg_x[rs1], reg_x[rs2])
} else {
format!("sraw\t{}, {}, {}", reg_x[rd], reg_x[rs1], reg_x[rs2])
}
} else {
format!("{}\t{}, {}, {}", names_opw[ins.funct3 as usize], reg_x[rd], reg_x[rs1], reg_x[rs2])
}
}
},
RISCV_SYSTEM => {
"ecall".to_string()
},
_ => "Unknown".to_string() // Error
}
}
#[cfg(test)]
mod test {
use crate::simulator::{decode, print};
#[test]
fn test_op() {
let sub = decode::decode(0b0100000_10000_10001_000_11100_0110011);
let add = decode::decode(0b0000000_10000_10001_000_11100_0110011);
let xor = decode::decode(0b0000000_10000_10001_100_11100_0110011);
let slr = decode::decode(0b0000000_10000_10001_101_11100_0110011);
let sra = decode::decode(0b0100000_10000_10001_101_11100_0110011);
assert_eq!("sub\tt3, a7, a6", print::print(sub, 0));
assert_eq!("xor\tt3, a7, a6", print::print(xor, 0));
assert_eq!("srl\tt3, a7, a6", print::print(slr, 0));
assert_eq!("sra\tt3, a7, a6", print::print(sra, 0));
assert_eq!("add\tt3, a7, a6", print::print(add, 0));
}
#[test]
fn test_opi() {
let addi = decode::decode(0b0000000000_10001_000_11100_0010011);
let slli = decode::decode(0b0000000000_10001_001_11100_0010011);
let slti = decode::decode(0b0000000000_10001_010_11100_0010011);
let sltiu = decode::decode(0b0000000000_10001_011_11100_0010011);
let xori = decode::decode(0b_0000000000010001_100_11100_0010011);
let ori = decode::decode(0b00000000000_10001_110_11100_0010011);
let andi = decode::decode(0b000000000000_10001_111_11100_0010011);
assert_eq!("andi\tt3, a7, 0", print::print(andi, 0));
assert_eq!("addi\tt3, a7, 0", print::print(addi, 0));
assert_eq!("slli\tt3, a7, 0", print::print(slli, 0));
assert_eq!("slti\tt3, a7, 0", print::print(slti, 0));
assert_eq!("sltiu\tt3, a7, 0", print::print(sltiu, 0));
assert_eq!("xori\tt3, a7, 0", print::print(xori, 0));
assert_eq!("ori\tt3, a7, 0", print::print(ori, 0));
}
#[test]
fn test_lui() {
let lui = decode::decode(0b01110001000011111000_11100_0110111);
let lui_negatif = decode::decode(0b11110001000011111000_11100_0110111);
assert_eq!("lui\tt3, 0x710F8000", print::print(lui, 0));
assert_eq!("lui\tt3, 0xF10F8000", print::print(lui_negatif, 0));
}
#[test]
fn test_ld() {
// imm rs1 f3 rd opcode
let lb = decode::decode(0b010111110000_10001_000_11100_0000011);
let lh = decode::decode(0b010111110000_10001_001_11100_0000011);
let lw = decode::decode(0b010111110000_10001_010_11100_0000011);
let lbu = decode::decode(0b010111110000_10001_100_11100_0000011);
let lhu = decode::decode(0b010111110000_10001_101_11100_0000011);
let ld = decode::decode(0b010111110000_10001_011_11100_0000011);
let lwu = decode::decode(0b010111110000_10001_110_11100_0000011);
assert_eq!("lb\tt3, 1520(a7)", print::print(lb, 0));
assert_eq!("lh\tt3, 1520(a7)", print::print(lh, 0));
assert_eq!("lw\tt3, 1520(a7)", print::print(lw, 0));
assert_eq!("lbu\tt3, 1520(a7)", print::print(lbu, 0));
assert_eq!("lhu\tt3, 1520(a7)", print::print(lhu, 0));
assert_eq!("ld\tt3, 1520(a7)", print::print(ld, 0));
assert_eq!("lwu\tt3, 1520(a7)", print::print(lwu, 0));
}
#[test]
fn test_opw() {
let addw: decode::Instruction = decode::decode(0b0000000_10000_10001_000_11100_0111011);
let sllw: decode::Instruction = decode::decode(0b0000000_10000_10001_001_11100_0111011);
let srlw: decode::Instruction = decode::decode(0b0000000_10000_10001_101_11100_0111011);
let sraw: decode::Instruction = decode::decode(0b0100000_10000_10001_101_11100_0111011);
assert_eq!("addw\tt3, a7, a6", print::print(addw, 0));
assert_eq!("sllw\tt3, a7, a6", print::print(sllw, 0));
assert_eq!("srlw\tt3, a7, a6", print::print(srlw, 0));
assert_eq!("sraw\tt3, a7, a6", print::print(sraw, 0));
}
#[test]
fn test_opwi() {
let addiw: decode::Instruction =decode::decode(0b000000000000_10001_000_11100_0011011);
let slliw: decode::Instruction = decode::decode(0b0000000_10000_10001_001_11100_0011011);
let srai: decode::Instruction = decode::decode(0b010000010001_10001_101_11100_0010011);
assert_eq!("addiw\tt3, a7, 0", print::print(addiw, 0));
assert_eq!("slli\tt3, a7, a6", print::print(slliw, 0));
assert_eq!("srai\tt3, a7, 17", print::print(srai, 0));
}
#[test]
fn test_br() {
let beq: decode::Instruction = decode::decode(0b0000000_10000_10001_000_00000_1100011);
let bne: decode::Instruction = decode::decode(0b0000000_10000_10001_001_00000_1100011);
let blt: decode::Instruction = decode::decode(0b0000000_10000_10001_100_00000_1100011);
let bge: decode::Instruction = decode::decode(0b0000000_10000_10001_101_00000_1100011);
let bltu: decode::Instruction = decode::decode(0b0000000_10000_10001_110_00000_1100011);
let bgeu: decode::Instruction = decode::decode(0b0000000_10000_10001_111_00000_1100011);
assert_eq!("blt\ta7, a6, 0", print::print(blt, 0));
assert_eq!("bge\ta7, a6, 0", print::print(bge, 0));
assert_eq!("bltu\ta7, a6, 0", print::print(bltu, 0));
assert_eq!("bgeu\ta7, a6, 0", print::print(bgeu, 0));
assert_eq!("bne\ta7, a6, 0", print::print(bne, 0));
assert_eq!("beq\ta7, a6, 0", print::print(beq, 0));
}
}