diff --git a/Cargo.lock b/Cargo.lock index 9bb9ed5..30384b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,9 +6,16 @@ version = 3 name = "burritos" version = "0.1.0" dependencies = [ + "cc", "libc", ] +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "libc" version = "0.2.140" diff --git a/Cargo.toml b/Cargo.toml index 95cb216..911c397 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,7 @@ edition = "2021" libc = { version = "0.2.139", features = ["extra_traits"] } [registries.crates-io] -protocol = "sparse" \ No newline at end of file +protocol = "sparse" + +[build-dependencies] +cc = "1.0" \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..7b5ec8a --- /dev/null +++ b/build.rs @@ -0,0 +1,5 @@ +fn main() { + cc::Build::new() + .file("test/userlib/sys.s") + .compile("my-asm-lib"); +} \ No newline at end of file diff --git a/src/kernel/exception.rs b/src/kernel/exception.rs new file mode 100644 index 0000000..61b1544 --- /dev/null +++ b/src/kernel/exception.rs @@ -0,0 +1,124 @@ +use libc::printf; + +use crate::simulator::{machine::{ExceptionType, Machine}, error::{MachineOk, MachineError}}; + + +pub const SC_SHUTDOWN: u8 = 0; +pub const SC_EXIT: u8 = 1; +pub const SC_EXEC: u8 = 2; +pub const SC_JOIN: u8 = 3; +pub const SC_CREATE: u8 = 4; +pub const SC_OPEN: u8 = 5; +pub const SC_READ: u8 = 6; +pub const SC_WRITE: u8 = 7; +pub const SC_SEEK: u8 = 8; +pub const SC_CLOSE: u8 = 9; +pub const SC_NEW_THREAD: u8 = 10; +pub const SC_YIELD: u8 = 11; +pub const SC_PERROR: u8 = 12; +pub const SC_P: u8 = 13; +pub const SC_V: u8 = 14; +pub const SC_SEM_CREATE: u8 = 15 ; +pub const SC_SEM_DESTROY: u8 = 16; +pub const SC_LOCK_CREATE: u8 = 17 ; +pub const SC_LOCK_DESTROY: u8 = 18 ; +pub const SC_LOCK_ACQUIRE: u8 = 19 ; +pub const SC_LOCK_RELEASE: u8 = 20 ; +pub const SC_COND_CREATE: u8 = 21 ; +pub const SC_COND_DESTROY: u8 = 22 ; +pub const SC_COND_WAIT: u8 = 23 ; +pub const SC_COND_SIGNAL: u8 = 24; +pub const SC_COND_BROADCAST: u8 = 25; +pub const SC_TTY_SEND: u8 = 26; +pub const SC_TTY_RECEIVE: u8 = 27; +pub const SC_MKDIR: u8 = 28; +pub const SC_RMDIR: u8 = 29; +pub const SC_REMOVE: u8 = 30; +pub const SC_FSLIST: u8 = 31; +pub const SC_SYS_TIME: u8 = 32 ; +pub const SC_MMAP: u8 = 33; +pub const SC_DEBUG: u8 = 34; + +pub const CONSOLE_OUTPUT: u8 = 1; + +// todo : returns new types, not just machine errors and machine ok +pub fn call(exception: ExceptionType, machine: &Machine) -> Result { + + match exception { + ExceptionType::NoException => todo!(), + ExceptionType::SyscallException => syscall(machine), + ExceptionType::PagefaultException => todo!(), + ExceptionType::ReadOnlyException => todo!(), + ExceptionType::BusErrorException => todo!(), + ExceptionType::AddressErrorException => todo!(), + ExceptionType::OverflowException => todo!(), + ExceptionType::IllegalInstrException => todo!(), + ExceptionType::NumExceptionTypes => todo!(), + } +} + +fn syscall(machine: &Machine) -> Result { + let call_type = machine.read_int_register(17) as u8; + + match call_type { + SC_SHUTDOWN => Ok(MachineOk::Shutdown), + SC_EXIT => todo!(), + SC_EXEC => todo!(), + SC_JOIN => todo!(), + SC_CREATE => todo!(), + SC_OPEN => todo!(), + SC_READ => todo!(), + SC_WRITE => { + + let address = machine.read_int_register(10); + let size = machine.read_int_register(11); + // openfileid or 1 (console) + let f = machine.read_int_register(12); + + // load buffer + let mut buffer = "".to_string(); + for i in 0..size { + match char::from_digit(machine.read_memory(1, (address + i) as usize) as u32, 2) { + Some(c) => buffer.push(c), + None => todo!() // Throw a proper error + } + } + + if f as u8 == CONSOLE_OUTPUT { + println!("{}", buffer); // todo replace with console driver in the future + } else { + todo!("SC_WRITE to file is not yet implemented") + } + + Ok(MachineOk::Ok) + }, + SC_SEEK => todo!(), + SC_CLOSE => todo!(), + SC_NEW_THREAD => todo!(), + SC_YIELD => todo!(), + SC_PERROR => todo!(), + SC_P => todo!(), + SC_V => todo!(), + SC_SEM_CREATE => todo!(), + SC_SEM_DESTROY => todo!(), + SC_LOCK_CREATE => todo!(), + SC_LOCK_DESTROY => todo!(), + SC_LOCK_ACQUIRE => todo!(), + SC_LOCK_RELEASE => todo!(), + SC_COND_CREATE => todo!(), + SC_COND_DESTROY => todo!(), + SC_COND_WAIT => todo!(), + SC_COND_SIGNAL => todo!(), + SC_COND_BROADCAST => todo!(), + SC_TTY_SEND => todo!(), + SC_TTY_RECEIVE => todo!(), + SC_MKDIR => todo!(), + SC_RMDIR => todo!(), + SC_REMOVE => todo!(), + SC_FSLIST => todo!(), + SC_SYS_TIME => todo!(), + SC_MMAP => todo!(), + SC_DEBUG => todo!(), + _ => todo!() + } +} \ No newline at end of file diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 1fe4f0f..725760a 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -4,4 +4,5 @@ pub mod mgerror; pub mod system; mod ucontext; mod synch; -mod thread_manager; \ No newline at end of file +mod thread_manager; +pub mod exception; \ No newline at end of file diff --git a/src/simulator/decode.rs b/src/simulator/decode.rs deleted file mode 100644 index b388eb4..0000000 --- a/src/simulator/decode.rs +++ /dev/null @@ -1,95 +0,0 @@ -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, // shamt = imm[5:0] or imm[4:0] (depend of opcode) - - 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; - - 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 }; - - 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, - - opcode, - rs1, - rs2, - rs3, - rd, - funct7, - funct7_smaller, - - funct3, - imm12_I, - imm12_S, - - imm12_I_signed, - imm12_S_signed, - - imm13, - imm13_signed, - - imm31_12, - imm31_12_signed, - - imm21_1, - imm21_1_signed, - - shamt - } -} \ No newline at end of file diff --git a/src/simulator/error.rs b/src/simulator/error.rs index d6ea783..a61dac2 100644 --- a/src/simulator/error.rs +++ b/src/simulator/error.rs @@ -24,6 +24,11 @@ pub struct MachineError { message: String } +pub enum MachineOk { + Ok, + Shutdown +} + /// This impl allows this MachineError to be formatted into an empty format. /// /// ``` diff --git a/src/simulator/instruction.rs b/src/simulator/instruction.rs new file mode 100644 index 0000000..f85f5ac --- /dev/null +++ b/src/simulator/instruction.rs @@ -0,0 +1,532 @@ +//! # Instruction +//! +//! This module describes the internal representation of a RISC-V Instruction, +//! its constructor from raw data, and a debug print method. +#![allow(clippy::missing_docs_in_private_items, non_snake_case)] + +use core::num::Wrapping; // Permet d'autoriser les overflow pour les opérations voulues +use super::global::*; + +/// OP instruction name mapping +const NAMES_OP: [&str; 8] = ["add", "sll", "slt", "sltu", "xor", "sr", "or", "and"]; +/// OPI instruction name mapping +const NAMES_OPI: [&str; 8] = ["addi", "slli", "slti", "sltiu", "xori", "slri", "ori", "andi"]; +/// OPW instruction name mapping +const NAMES_OPW: [&str; 8] = ["addw", "sllw", "", "", "", "srw", "", ""]; +/// OPIW instruction name mapping +const NAMES_OPIW: [&str; 8] = ["addiw", "slliw", "", "", "", "sri", "", ""]; +/// MUL instruction name mapping +const NAMES_MUL: [&str; 8] = ["mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu"]; +/// BR instruction name mapping +const NAMES_BR: [&str; 8] = ["beq", "bne", "", "", "blt", "bge", "bltu", "bgeu"]; +/// ST instruction name mapping +const NAMES_ST: [&str; 4] = ["sb", "sh", "sw", "sd"]; +/// LD instruction name mapping +const NAMES_LD: [&str; 7] = ["lb", "lh", "lw", "ld", "lbu", "lhu", "lwu"]; + + +/// Integer register name mapping +pub const REG_X: [&str; 32] = ["zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", +"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", +"s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", +"t3", "t4", "t5", "t6"]; + +/// Floating-point register name mapping +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"]; + +/// RISC-V Instruction +#[derive(Debug)] +pub struct Instruction { + /// Original value used to construct self + 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, // shamt = imm[5:0] or imm[4:0] (depend of opcode) + + 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, +} + +impl Instruction { + + /// Construct a new instruction from a big endian raw binary instruction + pub fn new(value : u64) -> Self { + + let opcode = (value & 0x7f) as u8; + let rs1 = ((value >> 15) & 0x1f) as u8; + let rs2 = ((value >> 20) & 0x1f) as u8; + let rs3 = ((value >> 27) & 0x1f) as u8; + let rd = ((value >> 7) & 0x1f) as u8; + let funct7 = ((value >> 25) & 0x7f) as u8; + let funct7_smaller = funct7 & 0x3e; + + let funct3 = ((value >> 12) & 0x7) as u8; + let imm12_I = ((value >> 20) & 0xfff) as u16; + let imm12_S = (((value >> 20) & 0xfe0) + ((value >> 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 = (((value >> 19) & 0x1000) + ((value >> 20) & 0x7e0) + + ((value >> 7) & 0x1e) + ((value << 4) & 0x800)) as i16; + let imm13_signed = if imm13 >= 4096 { imm13 - 8192 } else { imm13 }; + + let imm31_12 = (value & 0xfffff000) as u32; + let imm31_12_signed = imm31_12 as i32; + + let imm21_1 = ((value & 0xff000) + ((value >> 9) & 0x800) + + ((value >> 20) & 0x7fe) + ((value >> 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 = ((value >> 20) & 0x3f) as u8; + + Instruction { + value, + + opcode, + rs1, + rs2, + rs3, + rd, + funct7, + funct7_smaller, + + funct3, + imm12_I, + imm12_S, + + imm12_I_signed, + imm12_S_signed, + + imm13, + imm13_signed, + + imm31_12, + imm31_12_signed, + + imm21_1, + imm21_1_signed, + + shamt + } + } + +} + +/// Converts an Instruction to a prettified debug String +/// +/// ### Usage +/// +/// ``` +/// let m = Machine::new(); +/// let i = Instruction::new(inst); +/// println!("{}", instruction_debug(i, m.pc)); +/// ``` +pub fn instruction_debug(ins: &Instruction, pc: i32) -> String { + let rd = ins.rd as usize; + let rs1 = ins.rs1 as usize; + let rs2 = ins.rs2 as usize; + let rs3 = ins.rs3 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, 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!("srli\t{},{},{}", REG_X[rd], REG_X[rs1], ins.shamt) + } else { + format!("srai\t{},{},{}", REG_X[rd], REG_X[rs1], ins.shamt) + } + } else if ins.funct3 == RISCV_OPI_SLLI { + format!("{}\t{},{},{}", NAMES_OPI[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.shamt) + } else { + format!("{}\t{},{},{}", NAMES_OPI[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.imm12_I_signed) + } + }, + RISCV_LUI => { + format!("lui\t{},{:x}", REG_X[rd], ins.imm31_12) + }, + RISCV_AUIPC => { + format!("auipc\t{},{:x}", REG_X[rd], ins.imm31_12) + }, + RISCV_JAL => { + format!("jal\t{},{:x}", REG_X[rd], (pc + ins.imm21_1_signed)) + }, + RISCV_JALR => { + format!("jalr\t{},{:x}({})", REG_X[rd], ins.imm12_I_signed, REG_X[rs1]) + }, + RISCV_BR => { + format!("{}\t{},{},{:x}", NAMES_BR[ins.funct3 as usize], REG_X[rs1], REG_X[rs2], pc + (ins.imm13_signed as i32)) + }, + RISCV_LD => { + format!("{}\t{},{}({})", NAMES_LD[ins.funct3 as usize], REG_X[rd], ins.imm12_I_signed, REG_X[rs1]) + }, + RISCV_ST => { + format!("{}\t{},{}({})", NAMES_ST[ins.funct3 as usize], REG_X[rs2], ins.imm12_S_signed, REG_X[rs1]) + }, + RISCV_OPIW => { + if ins.funct3 == RISCV_OPIW_SRW { + if ins.funct7 == RISCV_OPIW_SRW_SRLIW { + format!("srliw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2]) + } else { + format!("sraiw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2]) + } + } else { + format!("{}\t{},{},0x{:x}", NAMES_OPIW[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.imm12_I_signed) + } + }, + RISCV_OPW => { + if ins.funct7 == 1 { + format!("{}w\t{},{},{}", NAMES_MUL[ins.funct3 as usize], 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]) + } + }, + // RV32F Standard Extension + RISCV_FLW => { + format!("flw\t{},{},({})", REG_F[rd], ins.imm12_I_signed, REG_F[rs1]) + }, + RISCV_FSW => { + format!("fsw\t{},{},({})", REG_F[rs2], "OFFSET TODO", REG_F[rs1]) // TODO Offset in decode + }, + RISCV_FMADD => { + format!("fmadd\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) + }, + RISCV_FMSUB => { + format!("fmsub\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) + }, + RISCV_FNMSUB => { + format!("fnmsub\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) + }, + RISCV_FNMADD => { + format!("fnmadd\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) + }, + RISCV_FP => { + match ins.funct7 { + RISCV_FP_ADD => { + format!("{}\t{}{}{}", "fadd", REG_F[rd], REG_F[rs1], REG_F[rs2]) + }, + RISCV_FP_SUB => { + format!("{}\t{}{}{}", "fsub.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + }, + RISCV_FP_MUL => { + format!("{}\t{}{}{}", "fmul.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + }, + RISCV_FP_DIV => { + format!("{}\t{}{}{}", "fdiv.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + }, + RISCV_FP_SQRT => { + format!("{}\t{}{}", "fsqrt.s", REG_F[rd], REG_F[rs1]) + }, + RISCV_FP_FSGN => { + match ins.funct3 { + RISCV_FP_FSGN_J => { + format!("{}\t{}{}{}", "fsgnj.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + }, + RISCV_FP_FSGN_JN => { + format!("{}\t{}{}{}", "fsgnn.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + }, + RISCV_FP_FSGN_JX => { + format!("{}\t{}{}{}", "fsgnx.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + }, + _ => todo!("Unknown code") + } + }, + RISCV_FP_MINMAX => { + if ins.funct3 == 0 { + format!("{}\t{}{}{}", "fmin.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + } else { + format!("{}\t{}{}{}", "fmax.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + } + }, + RISCV_FP_FCVTW => { + if rs2 == 0 { + format!("{}\t{}{}", "fcvt.w.s", REG_F[rd], REG_F[rs1]) + } else { + format!("{}\t{}{}", "fcvt.wu.s", REG_F[rd], REG_F[rs1]) + } + }, + RISCV_FP_FMVXFCLASS => { + if ins.funct3 == 0 { + format!("{}\t{}{}", "fmv.x.w", REG_F[rd], REG_F[rs1]) + } else { + format!("{}\t{}{}", "fclass.s", REG_F[rd], REG_F[rs1]) + } + }, + RISCV_FP_FCMP => { + if ins.funct3 == 0 { + format!("{}\t{}{}{}", "fle.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + } else if ins.funct3 == 1 { + format!("{}\t{}{}{}", "flt.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + } else { + format!("{}\t{}{}{}", "feq.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) + } + }, + RISCV_FP_FCVTS => { + if rs2 == 0 { + format!("{}\t{}{}", "fcvt.s.w", REG_F[rd], REG_F[rs1]) + } else { + format!("{}\t{}{}", "fcvt.s.wu", REG_F[rd], REG_F[rs1]) + } + }, + RISCV_FP_FMVW => { + format!("{}\t{}{}", "fmv.w.x", REG_F[rd], REG_F[rs1]) + }, + _ => todo!("Unknown code") + } + }, + + RISCV_SYSTEM => { + "ecall".to_string() + }, + _ => todo!("{:x} opcode non géré pc : {:x}, value : {:x}", ins.opcode, pc, ins.value) // Change todo! to panic! in the future, I put todo! because there's a lot of opcode currently not implemented + } + +} + + +#[cfg(test)] +mod test { + #![allow(clippy::unusual_byte_groupings)] + + use crate::simulator::instruction::*; + + #[test] + fn test_op() { + let sub = Instruction::new(0b0100000_10000_10001_000_11100_0110011); + let add = Instruction::new(0b0000000_10000_10001_000_11100_0110011); + let xor = Instruction::new(0b0000000_10000_10001_100_11100_0110011); + let slr = Instruction::new(0b0000000_10000_10001_101_11100_0110011); + let sra = Instruction::new(0b0100000_10000_10001_101_11100_0110011); + + assert_eq!("sub\tt3,a7,a6", instruction_debug(&sub, 0)); + assert_eq!("xor\tt3,a7,a6", instruction_debug(&xor, 0)); + assert_eq!("srl\tt3,a7,a6", instruction_debug(&slr, 0)); + assert_eq!("sra\tt3,a7,a6", instruction_debug(&sra, 0)); + assert_eq!("add\tt3,a7,a6", instruction_debug(&add, 0)); + + } + + #[test] + fn test_opi() { + let addi = Instruction::new(0b0000000000_10001_000_11100_0010011); + let slli = Instruction::new(0b0000000000_10001_001_11100_0010011); + let slti = Instruction::new(0b0000000000_10001_010_11100_0010011); + let sltiu = Instruction::new(0b0000000000_10001_011_11100_0010011); + let xori = Instruction::new(0b_0000000000010001_100_11100_0010011); + let ori = Instruction::new(0b00000000000_10001_110_11100_0010011); + let andi = Instruction::new(0b000000000000_10001_111_11100_0010011); + assert_eq!("andi\tt3,a7,0", instruction_debug(&andi, 0)); + assert_eq!("addi\tt3,a7,0", instruction_debug(&addi, 0)); + assert_eq!("slli\tt3,a7,0", instruction_debug(&slli, 0)); + assert_eq!("slti\tt3,a7,0", instruction_debug(&slti, 0)); + assert_eq!("sltiu\tt3,a7,0", instruction_debug(&sltiu, 0)); + assert_eq!("xori\tt3,a7,0", instruction_debug(&xori, 0)); + assert_eq!("ori\tt3,a7,0", instruction_debug(&ori, 0)); + } + + #[test] + fn test_lui() { + let lui = Instruction::new(0b01110001000011111000_11100_0110111); + let lui_negatif = Instruction::new(0b11110001000011111000_11100_0110111); + assert_eq!("lui\tt3,710f8000", instruction_debug(&lui, 0)); + assert_eq!("lui\tt3,f10f8000", instruction_debug(&lui_negatif, 0)); + } + + #[test] + fn test_ld() { + // imm rs1 f3 rd opcode + let lb = Instruction::new(0b010111110000_10001_000_11100_0000011); + let lh = Instruction::new(0b010111110000_10001_001_11100_0000011); + let lw = Instruction::new(0b010111110000_10001_010_11100_0000011); + let lbu = Instruction::new(0b010111110000_10001_100_11100_0000011); + let lhu = Instruction::new(0b010111110000_10001_101_11100_0000011); + let ld = Instruction::new(0b010111110000_10001_011_11100_0000011); + let lwu = Instruction::new(0b010111110000_10001_110_11100_0000011); + + assert_eq!("lb\tt3,1520(a7)", instruction_debug(&lb, 0)); + assert_eq!("lh\tt3,1520(a7)", instruction_debug(&lh, 0)); + assert_eq!("lw\tt3,1520(a7)", instruction_debug(&lw, 0)); + assert_eq!("lbu\tt3,1520(a7)", instruction_debug(&lbu, 0)); + assert_eq!("lhu\tt3,1520(a7)", instruction_debug(&lhu, 0)); + assert_eq!("ld\tt3,1520(a7)", instruction_debug(&ld, 0)); + assert_eq!("lwu\tt3,1520(a7)", instruction_debug(&lwu, 0)); + } + + #[test] + fn test_opw() { + let addw: Instruction = Instruction::new(0b0000000_10000_10001_000_11100_0111011); + let sllw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0111011); + let srlw: Instruction = Instruction::new(0b0000000_10000_10001_101_11100_0111011); + let sraw: Instruction = Instruction::new(0b0100000_10000_10001_101_11100_0111011); + + assert_eq!("addw\tt3,a7,a6", instruction_debug(&addw, 0)); + assert_eq!("sllw\tt3,a7,a6", instruction_debug(&sllw, 0)); + assert_eq!("srlw\tt3,a7,a6", instruction_debug(&srlw, 0)); + assert_eq!("sraw\tt3,a7,a6", instruction_debug(&sraw, 0)); + } + + #[test] + fn test_opwi() { + let addiw: Instruction =Instruction::new(0b000000000000_10001_000_11100_0011011); + let slliw: Instruction = Instruction::new(0b0000000_10000_10001_001_11100_0011011); + let srai: Instruction = Instruction::new(0b010000010001_10001_101_11100_0010011); + assert_eq!("addiw\tt3,a7,0x0", instruction_debug(&addiw, 0)); + assert_eq!("slliw\tt3,a7,0x10", instruction_debug(&slliw, 0)); + assert_eq!("srai\tt3,a7,17", instruction_debug(&srai, 0)); + + } + + #[test] + fn test_br() { + let beq: Instruction = Instruction::new(0b0000000_10000_10001_000_00000_1100011); + let bne: Instruction = Instruction::new(0b0000000_10000_10001_001_00000_1100011); + let blt: Instruction = Instruction::new(0b0000000_10000_10001_100_00000_1100011); + let bge: Instruction = Instruction::new(0b0000000_10000_10001_101_00000_1100011); + let bge2: Instruction = Instruction::new(0x00f75863); + let bltu: Instruction = Instruction::new(0b0000000_10000_10001_110_00000_1100011); + let bgeu: Instruction = Instruction::new(0b0000000_10000_10001_111_00000_1100011); + assert_eq!("blt\ta7,a6,0", instruction_debug(&blt, 0)); + assert_eq!("bge\ta7,a6,0", instruction_debug(&bge, 0)); + assert_eq!("bge\ta4,a5,104d4", instruction_debug(&bge2, 0x104c4)); + assert_eq!("bltu\ta7,a6,0", instruction_debug(&bltu, 0)); + assert_eq!("bgeu\ta7,a6,0", instruction_debug(&bgeu, 0)); + assert_eq!("bne\ta7,a6,0", instruction_debug(&bne, 0)); + assert_eq!("beq\ta7,a6,0", instruction_debug(&beq, 0)); + } + + #[test] + fn test_small_program() { + /* Code for : + int a = 0; + int b = 5; + a = b; + a = a * b; + a = a + b; + b = a - b; + */ + assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113), 0)); + assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23), 0)); + assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413), 0)); + assert_eq!("sw zero,-20(s0)", instruction_debug(&Instruction::new(0xfe042623), 0)); + assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793), 0)); + assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0)); + assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); + assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); + assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); + assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); + assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); + assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb), 0)); + assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); + assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); + assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); + assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); + assert_eq!("addw a5,a4,a5", instruction_debug(&Instruction::new(0x00f707bb), 0)); + assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); + assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); + assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); + assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); + assert_eq!("subw a5,a4,a5", instruction_debug(&Instruction::new(0x40f707bb), 0)); + assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0)); + assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793), 0)); + assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513), 0)); + assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403), 0)); + assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113), 0)); + assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067), 0)); + + } + + + #[test] + fn test_fibo() { + assert_eq!("jal zero,10504", instruction_debug(&Instruction::new(0x0500006f), 0x104b4)); + assert_eq!("blt a4,a5,104b8", instruction_debug(&Instruction::new(0xfaf740e3), 0x10518)); + } + + #[test] + fn test_mul_prog() { + assert_eq!("addi sp,sp,-32", instruction_debug(&Instruction::new(0xfe010113), 0)); + assert_eq!("sd s0,24(sp)", instruction_debug(&Instruction::new(0x00813c23), 0)); + assert_eq!("addi s0,sp,32", instruction_debug(&Instruction::new(0x02010413), 0)); + assert_eq!("addi a5,zero,5", instruction_debug(&Instruction::new(0x00500793), 0)); + assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); + assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); + assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); + assert_eq!("addi a5,a4,0", instruction_debug(&Instruction::new(0x00070793), 0)); + assert_eq!("slliw a5,a5,0x2", instruction_debug(&Instruction::new(0x0027979b), 0)); + assert_eq!("addw a5,a5,a4", instruction_debug(&Instruction::new(0x00e787bb), 0)); + assert_eq!("sw a5,-24(s0)", instruction_debug(&Instruction::new(0xfef42423), 0)); + assert_eq!("lw a5,-20(s0)", instruction_debug(&Instruction::new(0xfec42783), 0)); + assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); + assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); + assert_eq!("mulw a5,a4,a5", instruction_debug(&Instruction::new(0x02f707bb), 0)); + assert_eq!("sw a5,-28(s0)", instruction_debug(&Instruction::new(0xfef42223), 0)); + assert_eq!("lw a5,-28(s0)", instruction_debug(&Instruction::new(0xfe442783), 0)); + assert_eq!("addi a4,a5,0", instruction_debug(&Instruction::new(0x00078713), 0)); + assert_eq!("lw a5,-24(s0)", instruction_debug(&Instruction::new(0xfe842783), 0)); + assert_eq!("divw a5,a4,a5", instruction_debug(&Instruction::new(0x02f747bb), 0)); + assert_eq!("sw a5,-20(s0)", instruction_debug(&Instruction::new(0xfef42623), 0)); + assert_eq!("addi a5,zero,0", instruction_debug(&Instruction::new(0x00000793), 0)); + assert_eq!("addi a0,a5,0", instruction_debug(&Instruction::new(0x00078513), 0)); + assert_eq!("ld s0,24(sp)", instruction_debug(&Instruction::new(0x01813403), 0)); + assert_eq!("addi sp,sp,32", instruction_debug(&Instruction::new(0x02010113), 0)); + assert_eq!("jalr zero,0(ra)", instruction_debug(&Instruction::new(0x00008067), 0)); + } + +} \ No newline at end of file diff --git a/src/simulator/machine.rs b/src/simulator/machine.rs index 1ab9087..9485472 100644 --- a/src/simulator/machine.rs +++ b/src/simulator/machine.rs @@ -16,14 +16,19 @@ use std::{ fs::File }; use crate::simulator::{ - print, error::MachineError, - decode::*, + instruction::{*, self}, interrupt::Interrupt, global::*, register::* }; +use crate::kernel::{ + exception +}; + +use super::error::MachineOk; + /// # Exceptions /// /// Textual names of the exceptions that can be generated by user program @@ -49,6 +54,16 @@ pub enum ExceptionType { NumExceptionTypes } +/// # Machine Status +/// +/// The machine can be running kernel code (SystemMode), user code (UserMode), +/// or there can be no running thread if the ready list is empty (IdleMode). +pub enum MachineStatus { + IdleMode, + SystemMode, + UserMode +} + /// ID of the stack register pub const STACK_REG: usize = 2; /// Number of available Integer registers @@ -79,9 +94,12 @@ pub struct Machine { /// Debug data pub registers_trace : String, // for tests /// todo: document Interrupts - pub interrupt: Interrupt + 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 + + /// Current machine status + pub status: MachineStatus } @@ -106,7 +124,8 @@ impl Machine { main_memory : vec![0_u8; MEM_SIZE], shiftmask, interrupt: Interrupt::new(), - registers_trace : String::from("") + registers_trace : String::from(""), + status: MachineStatus::SystemMode } } @@ -179,10 +198,10 @@ impl Machine { 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 as u8)); - print!(">{0: <4} : {1:<16x} ", print::REG_X[i+1], self.int_reg.get_reg((i+1) as u8)); + print!(">{0: <4} : {1:<16x} ", instruction::REG_X[i], self.int_reg.get_reg(i as u8)); + print!(">{0: <4} : {1:<16x} ", instruction::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) as u8)); + print!(">{0: <4} : {1:<16x} ", instruction::REG_X[i+2], self.int_reg.get_reg((i+2) as u8)); } println!(); } @@ -207,6 +226,21 @@ impl Machine { s } + pub fn raise_exception(&mut self, exception: ExceptionType, address : u64) -> Result{ + + self.set_status(MachineStatus::SystemMode); + // Handle the interruption + match exception::call(exception, self) { + Ok(MachineOk::Shutdown) => { + self.set_status(MachineStatus::UserMode); + return Ok(MachineOk::Shutdown); + } + _ => () + } // todo: return error if the syscall code is invalid + self.set_status(MachineStatus::UserMode); + Ok(MachineOk::Ok) + } + /// Execute the instructions table of a machine putted in param /// /// ### Parameters @@ -215,7 +249,8 @@ impl Machine { pub fn run(&mut self) { loop { match self.one_instruction() { - Ok(_) => println!("hello"), + Ok(MachineOk::Ok) => println!("hello"), + Ok(MachineOk::Shutdown) => break, 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 @@ -227,7 +262,7 @@ impl Machine { /// ### Parameters /// /// - **machine** which contains a table of instructions and a pc to the actual instruction - pub fn one_instruction(&mut self) -> Result<(), MachineError> { + pub fn one_instruction(&mut self) -> Result { if self.main_memory.len() <= self.pc as usize { panic!("ERROR : number max of instructions rushed"); @@ -238,10 +273,10 @@ impl Machine { } let val = u32::from_be_bytes(val) as u64; - let inst : Instruction = decode(val); + let inst : Instruction = Instruction::new(val); self.print_status(); - println!("executing instruction : {:016x} at pc 0x{:x}", val, self.pc); - println!("{}", print::print(decode(val), self.pc as i32)); + println!("executing instruction : {:016x} at pc {:x}", val, self.pc); + println!("{}", instruction::instruction_debug(&inst, self.pc as i32)); let trace = Self::string_registers(self); self.registers_trace.push_str(format!("{}\n", trace).as_str()); @@ -251,20 +286,20 @@ impl Machine { // Treatment for: LOAD UPPER IMMEDIATE INSTRUCTION RISCV_LUI => { self.int_reg.set_reg(inst.rd, inst.imm31_12 as i64); - Ok(()) + Ok(MachineOk::Ok) }, // Treatment for: ADD UPPER IMMEDIATE TO PC INSTRUCTION RISCV_AUIPC => { self.int_reg.set_reg(inst.rd, self.pc as i64 - 4 + inst.imm31_12 as i64); - Ok(()) + Ok(MachineOk::Ok) }, // Treatement for: JUMP AND LINK INSTRUCTIONS (direct jump) RISCV_JAL => { 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(()) + Ok((MachineOk::Ok)) }, // Treatment for: JUMP AND LINK REGISTER INSTRUCTIONS (indirect jump) @@ -272,35 +307,35 @@ impl Machine { 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(()) + Ok((MachineOk::Ok)) }, // Treatment for: BRANCH INSTRUCTIONS - RISCV_BR => self.branch_instruction(inst), + RISCV_BR => self.branch_instruction(inst), // Treatment for: LOAD INSTRUCTIONS - RISCV_LD => self.load_instruction(inst), + RISCV_LD => self.load_instruction(inst), // Treatment for: STORE INSTRUCTIONS - RISCV_ST => self.store_instruction(inst), - - // Treatment for: OPI INSTRUCTIONS - RISCV_OPI => self.opi_instruction(inst), + RISCV_ST => self.store_instruction(inst), // Treatment for: OP INSTRUCTIONS - RISCV_OP => self.op_instruction(inst), + RISCV_OP => self.op_instruction(inst), + + // Treatment for: OPI INSTRUCTIONS + RISCV_OPI => self.opi_instruction(inst), + + // Treatment for: OPW INSTRUCTIONS + RISCV_OPW => self.opw_instruction(inst), // Treatment for OPIW INSTRUCTIONS - RISCV_OPIW => self.opiw_instruction(inst), - - // Treatment for: OPW INSTRUCTIONS - RISCV_OPW => self.opw_instruction(inst), + RISCV_OPIW => self.opiw_instruction(inst), // Treatment for: FLOATING POINT INSTRUCTIONS - RISCV_FP => self.fp_instruction(inst), + RISCV_FP => self.fp_instruction(inst), // Treatment for: SYSTEM CALLS - RISCV_SYSTEM => Err(format!("{:x}: System opcode\npc: {:x}", inst.opcode, self.pc))?, + RISCV_SYSTEM => self.raise_exception(ExceptionType::SyscallException, self.pc), // Default case _ => Err(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, self.pc))? @@ -308,7 +343,7 @@ impl Machine { } /// Treatement for Branch instructions - fn branch_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + fn branch_instruction(&mut self, inst: Instruction) -> Result { let op = match inst.funct3 { RISCV_BR_BEQ => |a, b| a == b, RISCV_BR_BNE => |a, b| a != b, @@ -316,152 +351,152 @@ impl Machine { RISCV_BR_BGE => |a, b| a >= b, RISCV_BR_BLTU => |a, b| a < b, RISCV_BR_BGEU => |a, b| a >= b, - _ => unreachable!() + _ => Err(format!("Unreachable in branch_instruction match! Instruction was {:?}", inst))? }; let rs1 = self.int_reg.get_reg(inst.rs1); let 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(()) + Ok(MachineOk::Ok) } /// Executes RISC-V Load Instructions on the machine - fn load_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + fn load_instruction(&mut self, inst: Instruction) -> Result { 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(()) + Ok(MachineOk::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())? + 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!("Unreachable in load_instruction match! Instruction was {:?}", inst))? } } /// Executes RISC-V Store Instructions on the machine - fn store_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + fn store_instruction(&mut self, inst: Instruction) -> Result { 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(()) + Ok(MachineOk::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())? + _ => Err(format!("Unreachable in store_instruction match! Instruction was {:?}", inst))? } } /// Executes RISC-V Integer Register-Immediate Instructions on the machine - fn opi_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + fn opi_instruction(&mut self, inst: Instruction) -> Result { 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(()) + Ok(MachineOk::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))? + 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!("Unreachable in opi_instruction match! Instruction was {:?}", inst))? } } /// Executes simple RISC-V mathematical operations on the machine - fn op_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + fn op_instruction(&mut self, inst: Instruction) -> Result { 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") + 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)), + _ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))? } } 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") + 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)), + _ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))? } } - Ok(()) + Ok(MachineOk::Ok) } /// Exectutes simple RISC-V *iw instructions on the machine - fn opiw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + fn opiw_instruction(&mut self, inst: Instruction) -> Result { 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")?, + 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(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))? }; self.int_reg.set_reg(inst.rd, result); - Ok(()) + Ok(MachineOk::Ok) } /// Executes simple RISC-V *w instructions on the machine - fn opw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + fn opw_instruction(&mut self, inst: Instruction) -> Result { 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; @@ -470,107 +505,144 @@ impl Machine { // 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) + 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), + _ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))? } } 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) + 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)) + }, + _ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))? } } - Ok(()) + Ok(MachineOk::Ok) } - /// Executes simple RISC-V floating point instructions on the machine - fn fp_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> { + /// Executes simple RISC-V floating point instructions on the machine. + /// + /// See Risc-V Spec v2.2 Chapter 8: “F” Standard Extension for Single-Precision Floating-Point, Version 2.0. + fn fp_instruction(&mut self, inst: Instruction) -> Result { + let mut set_reg = |operation: &dyn Fn (f32, f32) -> f32| { + let a = self.fp_reg.get_reg(inst.rs1); + let b = self.fp_reg.get_reg(inst.rs2); + self.fp_reg.set_reg(inst.rd, operation(a, b)); + Ok(MachineOk::Ok) + }; 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) + RISCV_FP_ADD => set_reg(&core::ops::Add::add), + RISCV_FP_SUB => set_reg(&core::ops::Sub::sub), + RISCV_FP_MUL => set_reg(&core::ops::Mul::mul), + RISCV_FP_DIV => set_reg(&core::ops::Div::div), + RISCV_FP_SQRT => { self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1).sqrt()); Ok(MachineOk::Ok) }, + RISCV_FP_FSGN => self.fp_fsgn_instruction(inst), + RISCV_FP_MINMAX => self.fp_minmax_instruction(inst), + RISCV_FP_FCVTW => self.fp_fcvtw_instruction(inst), + RISCV_FP_FCVTS => self.fp_fcvts_instruction(inst), + RISCV_FP_FMVW => self.fp_fmvw_instruction(inst), + RISCV_FP_FMVXFCLASS => self.fp_fmvxfclass_instruction(inst), + RISCV_FP_FCMP => self.fp_fcmp_instruction(inst), + _ => Err(format!("Unreachable in fp_instruction match! Instruction was {:?}", inst))? } - Ok(()) + } + + /// Executes RISC-V sign-injection instruction on floating point values on the machine. + fn fp_fsgn_instruction(&mut self, inst: Instruction) -> Result { + 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); + }, + _ => Err(format!("Unreachable in fp_fsgn_instruction! Instruction was {:?}", inst))? + } + Ok(MachineOk::Ok) + } + + /// Executes RISC-V min / max instruction on floating point values on the machine. + fn fp_minmax_instruction(&mut self, inst: Instruction) -> Result { + 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}), + _ => Err(format!("Unreachable in fp_minmax_instruction! Instruction was {:?}", inst))? + }; + Ok(MachineOk::Ok) + } + + /// Executes RISC-V floating-point to integer conversion instruction on the machine. + fn fp_fcvtw_instruction(&mut self, inst: Instruction) -> Result { + 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) + } + Ok(MachineOk::Ok) + } + + /// Executes RISC-V integer to floating-point conversion instruction on the machine. + fn fp_fcvts_instruction(&mut self, inst: Instruction) -> Result { + 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); + } + Ok(MachineOk::Ok) + } + + /// Executes RISC-V move from int_reg to fp_reg instruction on the machine. + fn fp_fmvw_instruction(&mut self, inst: Instruction) -> Result { + self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32); + Ok(MachineOk::Ok) + } + + /// Executes RISC-V move from fp_reg to int_reg instruction on the machine. + fn fp_fmvxfclass_instruction(&mut self, inst: Instruction) -> Result { + if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX { + self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64); + Ok(MachineOk::Ok) + } else { + Err(format!("Unreachable in fp_fmvxfclass_instruction! Instruction was {:?}", inst))? + } + } + + /// Executes RISC-V floating point values comparaison instructions on the machine. + fn fp_fcmp_instruction(&mut self, inst: Instruction) -> Result { + 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), + _ => Err(format!("Unreachable in fp_fcmp_instruction match! Instruction was {:?}", inst))? + } + Ok(MachineOk::Ok) } /// print memory FOR DEBUG @@ -605,6 +677,14 @@ impl Machine { pub fn write_fp_register(&mut self, index: usize, value: f32) { self.fp_reg.set_reg(index as u8, value); } + + pub fn get_status(&self) -> MachineStatus { + todo!() + } + + pub fn set_status(&mut self, new_status: MachineStatus) { + self.status = new_status; + } } #[cfg(test)] diff --git a/src/simulator/mod.rs b/src/simulator/mod.rs index 037d545..f764fbd 100644 --- a/src/simulator/mod.rs +++ b/src/simulator/mod.rs @@ -1,7 +1,6 @@ pub mod machine; pub mod error; -pub mod decode; -pub mod print; +pub mod instruction; pub mod mem_cmp; pub mod loader; pub mod interrupt; diff --git a/src/simulator/print.rs b/src/simulator/print.rs deleted file mode 100644 index c9b62b1..0000000 --- a/src/simulator/print.rs +++ /dev/null @@ -1,414 +0,0 @@ -#![allow(dead_code)] -use super::decode::{Instruction}; -use super::global::*; - -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] = ["mul", "mulh", "mulhsu", "mulhu", "div", "divu", "rem", "remu"]; -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 -pub const REG_X: [&str; 32] = ["zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", -"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; - let rs3 = ins.rs3 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, 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!("srli\t{},{},{}", REG_X[rd], REG_X[rs1], ins.shamt) - } else { - format!("srai\t{},{},{}", REG_X[rd], REG_X[rs1], ins.shamt) - } - } else if ins.funct3 == RISCV_OPI_SLLI { - format!("{}\t{},{},{}", NAMES_OPI[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.shamt) - } else { - format!("{}\t{},{},{}", NAMES_OPI[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.imm12_I_signed) - } - }, - RISCV_LUI => { - format!("lui\t{},{:x}", REG_X[rd], ins.imm31_12) - }, - RISCV_AUIPC => { - format!("auipc\t{},{:x}", REG_X[rd], ins.imm31_12) - }, - RISCV_JAL => { - format!("jal\t{},{:x}", REG_X[rd], (pc + ins.imm21_1_signed)) - }, - RISCV_JALR => { - format!("jalr\t{},{:x}({})", REG_X[rd], ins.imm12_I_signed, REG_X[rs1]) - }, - RISCV_BR => { - format!("{}\t{},{},{:x}", NAMES_BR[ins.funct3 as usize], REG_X[rs1], REG_X[rs2], pc + (ins.imm13_signed as i32)) - }, - RISCV_LD => { - format!("{}\t{},{}({})", NAMES_LD[ins.funct3 as usize], REG_X[rd], ins.imm12_I_signed, REG_X[rs1]) - }, - RISCV_ST => { - format!("{}\t{},{}({})", NAMES_ST[ins.funct3 as usize], REG_X[rs2], ins.imm12_S_signed, REG_X[rs1]) - }, - RISCV_OPIW => { - if ins.funct3 == RISCV_OPIW_SRW { - if ins.funct7 == RISCV_OPIW_SRW_SRLIW { - format!("srliw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2]) - } else { - format!("sraiw\t{},{},{}", REG_X[rd], REG_X[rs1], REG_X[rs2]) - } - } else { - format!("{}\t{},{},0x{:x}", NAMES_OPIW[ins.funct3 as usize], REG_X[rd], REG_X[rs1], ins.imm12_I_signed) - } - }, - RISCV_OPW => { - if ins.funct7 == 1 { - format!("{}w\t{},{},{}", NAMES_MUL[ins.funct3 as usize], 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]) - } - }, - // RV32F Standard Extension - RISCV_FLW => { - format!("flw\t{},{},({})", REG_F[rd], ins.imm12_I_signed, REG_F[rs1]) - }, - RISCV_FSW => { - format!("fsw\t{},{},({})", REG_F[rs2], "OFFSET TODO", REG_F[rs1]) // TODO Offset in decode - }, - RISCV_FMADD => { - format!("fmadd\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) - }, - RISCV_FMSUB => { - format!("fmsub\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) - }, - RISCV_FNMSUB => { - format!("fnmsub\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) - }, - RISCV_FNMADD => { - format!("fnmadd\t{}{}{}{}", REG_F[rd], REG_F[rs1], REG_F[rs2], REG_F[rs3]) - }, - RISCV_FP => { - match ins.funct7 { - RISCV_FP_ADD => { - format!("{}\t{}{}{}", "fadd", REG_F[rd], REG_F[rs1], REG_F[rs2]) - }, - RISCV_FP_SUB => { - format!("{}\t{}{}{}", "fsub.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - }, - RISCV_FP_MUL => { - format!("{}\t{}{}{}", "fmul.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - }, - RISCV_FP_DIV => { - format!("{}\t{}{}{}", "fdiv.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - }, - RISCV_FP_SQRT => { - format!("{}\t{}{}", "fsqrt.s", REG_F[rd], REG_F[rs1]) - }, - RISCV_FP_FSGN => { - match ins.funct3 { - RISCV_FP_FSGN_J => { - format!("{}\t{}{}{}", "fsgnj.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - }, - RISCV_FP_FSGN_JN => { - format!("{}\t{}{}{}", "fsgnn.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - }, - RISCV_FP_FSGN_JX => { - format!("{}\t{}{}{}", "fsgnx.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - }, - _ => todo!("Unknown code") - } - }, - RISCV_FP_MINMAX => { - if ins.funct3 == 0 { - format!("{}\t{}{}{}", "fmin.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - } else { - format!("{}\t{}{}{}", "fmax.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - } - }, - RISCV_FP_FCVTW => { - if rs2 == 0 { - format!("{}\t{}{}", "fcvt.w.s", REG_F[rd], REG_F[rs1]) - } else { - format!("{}\t{}{}", "fcvt.wu.s", REG_F[rd], REG_F[rs1]) - } - }, - RISCV_FP_FMVXFCLASS => { - if ins.funct3 == 0 { - format!("{}\t{}{}", "fmv.x.w", REG_F[rd], REG_F[rs1]) - } else { - format!("{}\t{}{}", "fclass.s", REG_F[rd], REG_F[rs1]) - } - }, - RISCV_FP_FCMP => { - if ins.funct3 == 0 { - format!("{}\t{}{}{}", "fle.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - } else if ins.funct3 == 1 { - format!("{}\t{}{}{}", "flt.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - } else { - format!("{}\t{}{}{}", "feq.s", REG_F[rd], REG_F[rs1], REG_F[rs2]) - } - }, - RISCV_FP_FCVTS => { - if rs2 == 0 { - format!("{}\t{}{}", "fcvt.s.w", REG_F[rd], REG_F[rs1]) - } else { - format!("{}\t{}{}", "fcvt.s.wu", REG_F[rd], REG_F[rs1]) - } - }, - RISCV_FP_FMVW => { - format!("{}\t{}{}", "fmv.w.x", REG_F[rd], REG_F[rs1]) - }, - _ => todo!("Unknown code") - } - }, - - RISCV_SYSTEM => { - "ecall".to_string() - }, - _ => unreachable!("{:x} opcode non géré pc : {:x}, value : {:x}", ins.opcode, pc, ins.value) - } - -} - - -#[cfg(test)] -mod test { - #![allow(clippy::unusual_byte_groupings)] - - 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,710f8000", print::print(lui, 0)); - assert_eq!("lui\tt3,f10f8000", 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,0x0", print::print(addiw, 0)); - assert_eq!("slliw\tt3,a7,0x10", 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 bge2: decode::Instruction = decode::decode(0x00f75863); - 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!("bge\ta4,a5,104d4", print::print(bge2, 0x104c4)); - 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)); - } - - #[test] - fn test_small_program() { - /* Code for : - int a = 0; - int b = 5; - a = b; - a = a * b; - a = a + b; - b = a - b; - */ - assert_eq!("addi sp,sp,-32", print::print(decode::decode(0xfe010113), 0)); - assert_eq!("sd s0,24(sp)", print::print(decode::decode(0x00813c23), 0)); - assert_eq!("addi s0,sp,32", print::print(decode::decode(0x02010413), 0)); - assert_eq!("sw zero,-20(s0)", print::print(decode::decode(0xfe042623), 0)); - assert_eq!("addi a5,zero,5", print::print(decode::decode(0x00500793), 0)); - assert_eq!("sw a5,-24(s0)", print::print(decode::decode(0xfef42423), 0)); - assert_eq!("lw a5,-24(s0)", print::print(decode::decode(0xfe842783), 0)); - assert_eq!("sw a5,-20(s0)", print::print(decode::decode(0xfef42623), 0)); - assert_eq!("lw a5,-20(s0)", print::print(decode::decode(0xfec42783), 0)); - assert_eq!("addi a4,a5,0", print::print(decode::decode(0x00078713), 0)); - assert_eq!("lw a5,-24(s0)", print::print(decode::decode(0xfe842783), 0)); - assert_eq!("mulw a5,a4,a5", print::print(decode::decode(0x02f707bb), 0)); - assert_eq!("sw a5,-20(s0)", print::print(decode::decode(0xfef42623), 0)); - assert_eq!("lw a5,-20(s0)", print::print(decode::decode(0xfec42783), 0)); - assert_eq!("addi a4,a5,0", print::print(decode::decode(0x00078713), 0)); - assert_eq!("lw a5,-24(s0)", print::print(decode::decode(0xfe842783), 0)); - assert_eq!("addw a5,a4,a5", print::print(decode::decode(0x00f707bb), 0)); - assert_eq!("sw a5,-20(s0)", print::print(decode::decode(0xfef42623), 0)); - assert_eq!("lw a5,-20(s0)", print::print(decode::decode(0xfec42783), 0)); - assert_eq!("addi a4,a5,0", print::print(decode::decode(0x00078713), 0)); - assert_eq!("lw a5,-24(s0)", print::print(decode::decode(0xfe842783), 0)); - assert_eq!("subw a5,a4,a5", print::print(decode::decode(0x40f707bb), 0)); - assert_eq!("sw a5,-24(s0)", print::print(decode::decode(0xfef42423), 0)); - assert_eq!("addi a5,zero,0", print::print(decode::decode(0x00000793), 0)); - assert_eq!("addi a0,a5,0", print::print(decode::decode(0x00078513), 0)); - assert_eq!("ld s0,24(sp)", print::print(decode::decode(0x01813403), 0)); - assert_eq!("addi sp,sp,32", print::print(decode::decode(0x02010113), 0)); - assert_eq!("jalr zero,0(ra)", print::print(decode::decode(0x00008067), 0)); - - } - - - #[test] - fn test_fibo() { - assert_eq!("jal zero,10504", print::print(decode::decode(0x0500006f), 0x104b4)); - assert_eq!("blt a4,a5,104b8", print::print(decode::decode(0xfaf740e3), 0x10518)); - } - - #[test] - fn test_mul_prog() { - assert_eq!("addi sp,sp,-32", print::print(decode::decode(0xfe010113), 0)); - assert_eq!("sd s0,24(sp)", print::print(decode::decode(0x00813c23), 0)); - assert_eq!("addi s0,sp,32", print::print(decode::decode(0x02010413), 0)); - assert_eq!("addi a5,zero,5", print::print(decode::decode(0x00500793), 0)); - assert_eq!("sw a5,-20(s0)", print::print(decode::decode(0xfef42623), 0)); - assert_eq!("lw a5,-20(s0)", print::print(decode::decode(0xfec42783), 0)); - assert_eq!("addi a4,a5,0", print::print(decode::decode(0x00078713), 0)); - assert_eq!("addi a5,a4,0", print::print(decode::decode(0x00070793), 0)); - assert_eq!("slliw a5,a5,0x2", print::print(decode::decode(0x0027979b), 0)); - assert_eq!("addw a5,a5,a4", print::print(decode::decode(0x00e787bb), 0)); - assert_eq!("sw a5,-24(s0)", print::print(decode::decode(0xfef42423), 0)); - assert_eq!("lw a5,-20(s0)", print::print(decode::decode(0xfec42783), 0)); - assert_eq!("addi a4,a5,0", print::print(decode::decode(0x00078713), 0)); - assert_eq!("lw a5,-24(s0)", print::print(decode::decode(0xfe842783), 0)); - assert_eq!("mulw a5,a4,a5", print::print(decode::decode(0x02f707bb), 0)); - assert_eq!("sw a5,-28(s0)", print::print(decode::decode(0xfef42223), 0)); - assert_eq!("lw a5,-28(s0)", print::print(decode::decode(0xfe442783), 0)); - assert_eq!("addi a4,a5,0", print::print(decode::decode(0x00078713), 0)); - assert_eq!("lw a5,-24(s0)", print::print(decode::decode(0xfe842783), 0)); - assert_eq!("divw a5,a4,a5", print::print(decode::decode(0x02f747bb), 0)); - assert_eq!("sw a5,-20(s0)", print::print(decode::decode(0xfef42623), 0)); - assert_eq!("addi a5,zero,0", print::print(decode::decode(0x00000793), 0)); - assert_eq!("addi a0,a5,0", print::print(decode::decode(0x00078513), 0)); - assert_eq!("ld s0,24(sp)", print::print(decode::decode(0x01813403), 0)); - assert_eq!("addi sp,sp,32", print::print(decode::decode(0x02010113), 0)); - assert_eq!("jalr zero,0(ra)", print::print(decode::decode(0x00008067), 0)); - } - -} \ No newline at end of file diff --git a/src/simulator/register.rs b/src/simulator/register.rs index 339c0e5..bbad262 100644 --- a/src/simulator/register.rs +++ b/src/simulator/register.rs @@ -6,6 +6,14 @@ use crate::simulator::machine::{NUM_FP_REGS, NUM_INT_REGS}; use std::ops::{Add, Sub}; +/// Forcing the Register struct's generic type into having the following Traits +/// +/// - Add +/// - Sub +/// - PartialEq +/// - Copy +/// +/// Generally speaking, only numbers have the combinaison of these traits. pub trait RegisterNum: Add + Sub + PartialEq + Copy {} impl RegisterNum for i64 {} diff --git a/test/userlib/sys.s b/test/userlib/sys.s index 64c3069..970117b 100644 --- a/test/userlib/sys.s +++ b/test/userlib/sys.s @@ -65,7 +65,7 @@ __start: .globl Halt .type __Halt, @function -Halt: +Shutdown: addi a7,zero,SC_HALT ecall jr ra diff --git a/test/userlib/syscall.h b/test/userlib/syscall.h index e650db1..a90e897 100644 --- a/test/userlib/syscall.h +++ b/test/userlib/syscall.h @@ -84,7 +84,7 @@ typedef int t_error; /* Stop Nachos, and print out performance stats */ -void Halt(); +void Shutdown(); /* Return the time spent running Nachos */ diff --git a/test/userlib/syscall.rs b/test/userlib/syscall.rs new file mode 100644 index 0000000..4350f5a --- /dev/null +++ b/test/userlib/syscall.rs @@ -0,0 +1,21 @@ +pub struct Burritos_Time { + seconds: i64, + nanos: i64 +} +pub struct ThreadId{ + id: u64 +} +pub struct t_error{ + t: i32 +} +extern "C"{ + fn Shutdown() -> (); + fn SysTime(t: Burritos_Time) -> (); + fn Exit(status: i32) -> (); + fn Exec(name: String) -> ThreadId; + fn newThread(debug_name: String, func: i32, arg: i32) -> ThreadId; + fn Join (id: ThreadId) -> t_error; + fn Yield() -> (); + fn Perror(mess: String) -> (); + +} \ No newline at end of file