Merge branch 'thread_scheduler' into bin-loader
This commit is contained in:
commit
4480212ab0
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -6,9 +6,16 @@ version = 3
|
|||||||
name = "burritos"
|
name = "burritos"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.140"
|
version = "0.2.140"
|
||||||
|
@ -7,4 +7,7 @@ edition = "2021"
|
|||||||
libc = { version = "0.2.139", features = ["extra_traits"] }
|
libc = { version = "0.2.139", features = ["extra_traits"] }
|
||||||
|
|
||||||
[registries.crates-io]
|
[registries.crates-io]
|
||||||
protocol = "sparse"
|
protocol = "sparse"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = "1.0"
|
5
build.rs
Normal file
5
build.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
fn main() {
|
||||||
|
cc::Build::new()
|
||||||
|
.file("test/userlib/sys.s")
|
||||||
|
.compile("my-asm-lib");
|
||||||
|
}
|
124
src/kernel/exception.rs
Normal file
124
src/kernel/exception.rs
Normal file
@ -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<MachineOk, MachineError> {
|
||||||
|
|
||||||
|
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<MachineOk, MachineError> {
|
||||||
|
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!()
|
||||||
|
}
|
||||||
|
}
|
@ -4,4 +4,5 @@ pub mod mgerror;
|
|||||||
pub mod system;
|
pub mod system;
|
||||||
mod ucontext;
|
mod ucontext;
|
||||||
mod synch;
|
mod synch;
|
||||||
mod thread_manager;
|
mod thread_manager;
|
||||||
|
pub mod exception;
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,6 +24,11 @@ pub struct MachineError {
|
|||||||
message: String
|
message: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum MachineOk {
|
||||||
|
Ok,
|
||||||
|
Shutdown
|
||||||
|
}
|
||||||
|
|
||||||
/// This impl allows this MachineError to be formatted into an empty format.
|
/// This impl allows this MachineError to be formatted into an empty format.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
532
src/simulator/instruction.rs
Normal file
532
src/simulator/instruction.rs
Normal file
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -16,14 +16,19 @@ use std::{
|
|||||||
fs::File
|
fs::File
|
||||||
};
|
};
|
||||||
use crate::simulator::{
|
use crate::simulator::{
|
||||||
print,
|
|
||||||
error::MachineError,
|
error::MachineError,
|
||||||
decode::*,
|
instruction::{*, self},
|
||||||
interrupt::Interrupt,
|
interrupt::Interrupt,
|
||||||
global::*,
|
global::*,
|
||||||
register::*
|
register::*
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::kernel::{
|
||||||
|
exception
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::error::MachineOk;
|
||||||
|
|
||||||
/// # Exceptions
|
/// # Exceptions
|
||||||
///
|
///
|
||||||
/// Textual names of the exceptions that can be generated by user program
|
/// Textual names of the exceptions that can be generated by user program
|
||||||
@ -49,6 +54,16 @@ pub enum ExceptionType {
|
|||||||
NumExceptionTypes
|
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
|
/// ID of the stack register
|
||||||
pub const STACK_REG: usize = 2;
|
pub const STACK_REG: usize = 2;
|
||||||
/// Number of available Integer registers
|
/// Number of available Integer registers
|
||||||
@ -79,9 +94,12 @@ pub struct Machine {
|
|||||||
/// Debug data
|
/// Debug data
|
||||||
pub registers_trace : String, // for tests
|
pub registers_trace : String, // for tests
|
||||||
/// todo: document Interrupts
|
/// todo: document Interrupts
|
||||||
pub interrupt: Interrupt
|
pub interrupt: Interrupt,
|
||||||
// futur taille à calculer int memSize = g_cfg->NumPhysPages * g_cfg->PageSize;
|
// 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
|
//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],
|
main_memory : vec![0_u8; MEM_SIZE],
|
||||||
shiftmask,
|
shiftmask,
|
||||||
interrupt: Interrupt::new(),
|
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) {
|
pub fn print_status(&self) {
|
||||||
println!("######### Machine status #########");
|
println!("######### Machine status #########");
|
||||||
for i in (0..32).step_by(3) {
|
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} ", instruction::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+1], self.int_reg.get_reg((i+1) as u8));
|
||||||
if i+2 < 32 {
|
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!();
|
println!();
|
||||||
}
|
}
|
||||||
@ -207,6 +226,21 @@ impl Machine {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raise_exception(&mut self, exception: ExceptionType, address : u64) -> Result<MachineOk, MachineError>{
|
||||||
|
|
||||||
|
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
|
/// Execute the instructions table of a machine putted in param
|
||||||
///
|
///
|
||||||
/// ### Parameters
|
/// ### Parameters
|
||||||
@ -215,7 +249,8 @@ impl Machine {
|
|||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
match self.one_instruction() {
|
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) }
|
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
|
self.write_int_register(0, 0); // In case an instruction write on register 0
|
||||||
@ -227,7 +262,7 @@ impl Machine {
|
|||||||
/// ### Parameters
|
/// ### Parameters
|
||||||
///
|
///
|
||||||
/// - **machine** which contains a table of instructions and a pc to the actual instruction
|
/// - **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<MachineOk, MachineError> {
|
||||||
|
|
||||||
if self.main_memory.len() <= self.pc as usize {
|
if self.main_memory.len() <= self.pc as usize {
|
||||||
panic!("ERROR : number max of instructions rushed");
|
panic!("ERROR : number max of instructions rushed");
|
||||||
@ -238,10 +273,10 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let val = u32::from_be_bytes(val) as u64;
|
let val = u32::from_be_bytes(val) as u64;
|
||||||
let inst : Instruction = decode(val);
|
let inst : Instruction = Instruction::new(val);
|
||||||
self.print_status();
|
self.print_status();
|
||||||
println!("executing instruction : {:016x} at pc 0x{:x}", val, self.pc);
|
println!("executing instruction : {:016x} at pc {:x}", val, self.pc);
|
||||||
println!("{}", print::print(decode(val), self.pc as i32));
|
println!("{}", instruction::instruction_debug(&inst, self.pc as i32));
|
||||||
let trace = Self::string_registers(self);
|
let trace = Self::string_registers(self);
|
||||||
self.registers_trace.push_str(format!("{}\n", trace).as_str());
|
self.registers_trace.push_str(format!("{}\n", trace).as_str());
|
||||||
|
|
||||||
@ -251,20 +286,20 @@ impl Machine {
|
|||||||
// Treatment for: LOAD UPPER IMMEDIATE INSTRUCTION
|
// Treatment for: LOAD UPPER IMMEDIATE INSTRUCTION
|
||||||
RISCV_LUI => {
|
RISCV_LUI => {
|
||||||
self.int_reg.set_reg(inst.rd, inst.imm31_12 as i64);
|
self.int_reg.set_reg(inst.rd, inst.imm31_12 as i64);
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Treatment for: ADD UPPER IMMEDIATE TO PC INSTRUCTION
|
// Treatment for: ADD UPPER IMMEDIATE TO PC INSTRUCTION
|
||||||
RISCV_AUIPC => {
|
RISCV_AUIPC => {
|
||||||
self.int_reg.set_reg(inst.rd, self.pc as i64 - 4 + inst.imm31_12 as i64);
|
self.int_reg.set_reg(inst.rd, self.pc as i64 - 4 + inst.imm31_12 as i64);
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Treatement for: JUMP AND LINK INSTRUCTIONS (direct jump)
|
// Treatement for: JUMP AND LINK INSTRUCTIONS (direct jump)
|
||||||
RISCV_JAL => {
|
RISCV_JAL => {
|
||||||
self.int_reg.set_reg(inst.rd, self.pc as i64);
|
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;
|
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)
|
// Treatment for: JUMP AND LINK REGISTER INSTRUCTIONS (indirect jump)
|
||||||
@ -272,35 +307,35 @@ impl Machine {
|
|||||||
let tmp = self.pc;
|
let tmp = self.pc;
|
||||||
self.pc = (self.int_reg.get_reg(inst.rs1) + inst.imm12_I_signed as i64) as u64 & 0xfffffffe;
|
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);
|
self.int_reg.set_reg(inst.rd, tmp as i64);
|
||||||
Ok(())
|
Ok((MachineOk::Ok))
|
||||||
},
|
},
|
||||||
|
|
||||||
// Treatment for: BRANCH INSTRUCTIONS
|
// Treatment for: BRANCH INSTRUCTIONS
|
||||||
RISCV_BR => self.branch_instruction(inst),
|
RISCV_BR => self.branch_instruction(inst),
|
||||||
|
|
||||||
// Treatment for: LOAD INSTRUCTIONS
|
// Treatment for: LOAD INSTRUCTIONS
|
||||||
RISCV_LD => self.load_instruction(inst),
|
RISCV_LD => self.load_instruction(inst),
|
||||||
|
|
||||||
// Treatment for: STORE INSTRUCTIONS
|
// Treatment for: STORE INSTRUCTIONS
|
||||||
RISCV_ST => self.store_instruction(inst),
|
RISCV_ST => self.store_instruction(inst),
|
||||||
|
|
||||||
// Treatment for: OPI INSTRUCTIONS
|
|
||||||
RISCV_OPI => self.opi_instruction(inst),
|
|
||||||
|
|
||||||
// Treatment for: OP INSTRUCTIONS
|
// 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
|
// Treatment for OPIW INSTRUCTIONS
|
||||||
RISCV_OPIW => self.opiw_instruction(inst),
|
RISCV_OPIW => self.opiw_instruction(inst),
|
||||||
|
|
||||||
// Treatment for: OPW INSTRUCTIONS
|
|
||||||
RISCV_OPW => self.opw_instruction(inst),
|
|
||||||
|
|
||||||
// Treatment for: FLOATING POINT INSTRUCTIONS
|
// Treatment for: FLOATING POINT INSTRUCTIONS
|
||||||
RISCV_FP => self.fp_instruction(inst),
|
RISCV_FP => self.fp_instruction(inst),
|
||||||
|
|
||||||
// Treatment for: SYSTEM CALLS
|
// 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
|
// Default case
|
||||||
_ => Err(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, self.pc))?
|
_ => Err(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, self.pc))?
|
||||||
@ -308,7 +343,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Treatement for Branch instructions
|
/// Treatement for Branch instructions
|
||||||
fn branch_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
|
fn branch_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
|
||||||
let op = match inst.funct3 {
|
let op = match inst.funct3 {
|
||||||
RISCV_BR_BEQ => |a, b| a == b,
|
RISCV_BR_BEQ => |a, b| a == b,
|
||||||
RISCV_BR_BNE => |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_BGE => |a, b| a >= b,
|
||||||
RISCV_BR_BLTU => |a, b| a < b,
|
RISCV_BR_BLTU => |a, b| a < b,
|
||||||
RISCV_BR_BGEU => |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 rs1 = self.int_reg.get_reg(inst.rs1);
|
||||||
let rs2 = self.int_reg.get_reg(inst.rs2);
|
let rs2 = self.int_reg.get_reg(inst.rs2);
|
||||||
if op(rs1, rs2) {
|
if op(rs1, rs2) {
|
||||||
self.pc = (self.pc as i64 + inst.imm13_signed as i64 - 4) as u64;
|
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
|
/// 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<MachineOk, MachineError> {
|
||||||
let mut set_reg = |rd, size| {
|
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;
|
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);
|
self.int_reg.set_reg(rd, val);
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
};
|
};
|
||||||
match inst.funct3 {
|
match inst.funct3 {
|
||||||
RISCV_LD_LB | RISCV_LD_LBU => set_reg(inst.rd, 1),
|
RISCV_LD_LB | RISCV_LD_LBU => set_reg(inst.rd, 1),
|
||||||
RISCV_LD_LH | RISCV_LD_LHU => set_reg(inst.rd, 2),
|
RISCV_LD_LH | RISCV_LD_LHU => set_reg(inst.rd, 2),
|
||||||
RISCV_LD_LW | RISCV_LD_LWU => set_reg(inst.rd, 4),
|
RISCV_LD_LW | RISCV_LD_LWU => set_reg(inst.rd, 4),
|
||||||
RISCV_LD_LD => set_reg(inst.rd, 8),
|
RISCV_LD_LD => set_reg(inst.rd, 8),
|
||||||
_ => Err(format!("In LD switch case, this should never happen... Instr was {}", inst.value).as_str())?
|
_ => Err(format!("Unreachable in load_instruction match! Instruction was {:?}", inst))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes RISC-V Store Instructions on the machine
|
/// 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<MachineOk, MachineError> {
|
||||||
let mut store = |size| {
|
let mut store = |size| {
|
||||||
self.write_memory(
|
self.write_memory(
|
||||||
size,
|
size,
|
||||||
(self.int_reg.get_reg(inst.rs1) + inst.imm12_S_signed as i64) as usize,
|
(self.int_reg.get_reg(inst.rs1) + inst.imm12_S_signed as i64) as usize,
|
||||||
self.int_reg.get_reg(inst.rs2) as u64
|
self.int_reg.get_reg(inst.rs2) as u64
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
};
|
};
|
||||||
match inst.funct3 {
|
match inst.funct3 {
|
||||||
RISCV_ST_STB => store(1),
|
RISCV_ST_STB => store(1),
|
||||||
RISCV_ST_STH => store(2),
|
RISCV_ST_STH => store(2),
|
||||||
RISCV_ST_STW => store(4),
|
RISCV_ST_STW => store(4),
|
||||||
RISCV_ST_STD => store(8),
|
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
|
/// 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<MachineOk, MachineError> {
|
||||||
let rs1 = self.int_reg.get_reg(inst.rs1);
|
let rs1 = self.int_reg.get_reg(inst.rs1);
|
||||||
let imm12 = inst.imm12_I_signed as i64;
|
let imm12 = inst.imm12_I_signed as i64;
|
||||||
let shamt = inst.shamt as i64;
|
let shamt = inst.shamt as i64;
|
||||||
let mut compute = |operation: &dyn Fn (i64, i64) -> i64, a, b| {
|
let mut compute = |operation: &dyn Fn (i64, i64) -> i64, a, b| {
|
||||||
self.int_reg.set_reg(inst.rd, operation(a, b));
|
self.int_reg.set_reg(inst.rd, operation(a, b));
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
};
|
};
|
||||||
match inst.funct3 {
|
match inst.funct3 {
|
||||||
RISCV_OPI_ADDI => compute(&std::ops::Add::add, rs1, imm12),
|
RISCV_OPI_ADDI => compute(&std::ops::Add::add, rs1, imm12),
|
||||||
RISCV_OPI_SLTI => compute(&|a, b| (a < b) as i64, 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_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12),
|
||||||
RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12),
|
RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12),
|
||||||
RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12),
|
RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12),
|
||||||
RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, imm12),
|
RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, imm12),
|
||||||
RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI {
|
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)
|
compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt)
|
||||||
} else {
|
} else {
|
||||||
compute(&core::ops::Shr::shr, rs1, shamt)
|
compute(&core::ops::Shr::shr, rs1, shamt)
|
||||||
}
|
}
|
||||||
_ => Err(format!("In OPI switch case, this should never happen... Instr was %x\n {}", inst.value))?
|
_ => Err(format!("Unreachable in opi_instruction match! Instruction was {:?}", inst))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes simple RISC-V mathematical operations on the machine
|
/// 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<MachineOk, MachineError> {
|
||||||
let long_result: i128;
|
let long_result: i128;
|
||||||
let unsigned_reg1: u64;
|
let unsigned_reg1: u64;
|
||||||
let unsigned_reg2: u64;
|
let unsigned_reg2: u64;
|
||||||
if inst.funct7 == 1 {
|
if inst.funct7 == 1 {
|
||||||
match inst.funct3 {
|
match inst.funct3 {
|
||||||
RISCV_OP_M_MUL => {
|
RISCV_OP_M_MUL => {
|
||||||
long_result = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128;
|
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)
|
self.int_reg.set_reg(inst.rd, (long_result & 0xffffffffffffffff) as i64)
|
||||||
},
|
},
|
||||||
RISCV_OP_M_MULH => {
|
RISCV_OP_M_MULH => {
|
||||||
long_result = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128;
|
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)
|
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64)
|
||||||
},
|
},
|
||||||
RISCV_OP_M_MULHSU => {
|
RISCV_OP_M_MULHSU => {
|
||||||
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
|
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;
|
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)
|
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64)
|
||||||
},
|
},
|
||||||
RISCV_OP_M_MULHU => {
|
RISCV_OP_M_MULHU => {
|
||||||
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
|
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
|
||||||
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
|
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
|
||||||
long_result = (unsigned_reg1 * unsigned_reg2) as i128;
|
long_result = (unsigned_reg1 * unsigned_reg2) as i128;
|
||||||
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64);
|
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)),
|
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")
|
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match inst.funct3 {
|
match inst.funct3 {
|
||||||
RISCV_OP_ADD => if inst.funct7 == RISCV_OP_ADD_ADD {
|
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))
|
self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) + self.int_reg.get_reg(inst.rs2))
|
||||||
} else {
|
} else {
|
||||||
self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) - self.int_reg.get_reg(inst.rs2))
|
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_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) {
|
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)
|
self.int_reg.set_reg(inst.rd, 1)
|
||||||
} else {
|
} else {
|
||||||
self.int_reg.set_reg(inst.rd, 0)
|
self.int_reg.set_reg(inst.rd, 0)
|
||||||
},
|
},
|
||||||
RISCV_OP_SLTU => {
|
RISCV_OP_SLTU => {
|
||||||
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
|
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
|
||||||
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
|
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
|
||||||
if unsigned_reg1 < unsigned_reg2 {
|
if unsigned_reg1 < unsigned_reg2 {
|
||||||
self.int_reg.set_reg(inst.rd, 1)
|
self.int_reg.set_reg(inst.rd, 1)
|
||||||
} else {
|
} else {
|
||||||
self.int_reg.set_reg(inst.rd, 0)
|
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_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_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_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)),
|
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")
|
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exectutes simple RISC-V *iw instructions on the machine
|
/// 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<MachineOk, MachineError> {
|
||||||
let local_data = self.int_reg.get_reg(inst.rs1);
|
let local_data = self.int_reg.get_reg(inst.rs1);
|
||||||
let result = match inst.funct3 {
|
let result = match inst.funct3 {
|
||||||
RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64,
|
RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64,
|
||||||
RISCV_OPIW_SLLIW => local_data << inst.shamt,
|
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 },
|
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")?,
|
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
|
||||||
};
|
};
|
||||||
self.int_reg.set_reg(inst.rd, result);
|
self.int_reg.set_reg(inst.rd, result);
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes simple RISC-V *w instructions on the machine
|
/// 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<MachineOk, MachineError> {
|
||||||
if inst.funct7 == 1 { // rv64m
|
if inst.funct7 == 1 { // rv64m
|
||||||
let local_data_a = self.int_reg.get_reg(inst.rs1) & 0xffffffff;
|
let local_data_a = self.int_reg.get_reg(inst.rs1) & 0xffffffff;
|
||||||
let local_data_b = self.int_reg.get_reg(inst.rs2) & 0xffffffff;
|
let local_data_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 case for multiplication operations (in standard extension RV32M)
|
||||||
match inst.funct3 {
|
match inst.funct3 {
|
||||||
RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, local_data_a * local_data_b),
|
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_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_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_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),
|
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)
|
_ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
|
||||||
}
|
}
|
||||||
} else { // others rv64 OPW operations
|
} else { // others rv64 OPW operations
|
||||||
let local_dataa = self.int_reg.get_reg(inst.rs1) & 0xffffffff;
|
let local_dataa = self.int_reg.get_reg(inst.rs1) & 0xffffffff;
|
||||||
let local_datab = self.int_reg.get_reg(inst.rs2) & 0xffffffff;
|
let local_datab = self.int_reg.get_reg(inst.rs2) & 0xffffffff;
|
||||||
// Match case for base OP operation
|
// Match case for base OP operation
|
||||||
match inst.funct3 {
|
match inst.funct3 {
|
||||||
RISCV_OPW_ADDSUBW => if inst.funct7 == RISCV_OPW_ADDSUBW_ADDW {
|
RISCV_OPW_ADDSUBW => if inst.funct7 == RISCV_OPW_ADDSUBW_ADDW {
|
||||||
self.int_reg.set_reg(inst.rd, local_dataa + local_datab);
|
self.int_reg.set_reg(inst.rd, local_dataa + local_datab);
|
||||||
} else { // SUBW
|
} else { // SUBW
|
||||||
self.int_reg.set_reg(inst.rd, local_dataa - local_datab);
|
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_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)),
|
||||||
RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW {
|
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)
|
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f) & self.shiftmask[32 + local_datab as usize] as i64)
|
||||||
} else { // SRAW
|
} else { // SRAW
|
||||||
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f))
|
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f))
|
||||||
},
|
},
|
||||||
_ => panic!("this instruction ({}) doesn't exist", inst.value)
|
_ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(MachineOk::Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes simple RISC-V floating point instructions on the machine
|
/// Executes simple RISC-V floating point instructions on the machine.
|
||||||
fn fp_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
|
///
|
||||||
|
/// 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<MachineOk, MachineError> {
|
||||||
|
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 {
|
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_ADD => set_reg(&core::ops::Add::add),
|
||||||
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_SUB => set_reg(&core::ops::Sub::sub),
|
||||||
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_MUL => set_reg(&core::ops::Mul::mul),
|
||||||
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_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()),
|
RISCV_FP_SQRT => { self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1).sqrt()); Ok(MachineOk::Ok) },
|
||||||
RISCV_FP_FSGN => {
|
RISCV_FP_FSGN => self.fp_fsgn_instruction(inst),
|
||||||
let local_float = self.fp_reg.get_reg(inst.rs1);
|
RISCV_FP_MINMAX => self.fp_minmax_instruction(inst),
|
||||||
match inst.funct3 {
|
RISCV_FP_FCVTW => self.fp_fcvtw_instruction(inst),
|
||||||
RISCV_FP_FSGN_J => if self.fp_reg.get_reg(inst.rs2) < 0f32 {
|
RISCV_FP_FCVTS => self.fp_fcvts_instruction(inst),
|
||||||
self.fp_reg.set_reg(inst.rd, -local_float)
|
RISCV_FP_FMVW => self.fp_fmvw_instruction(inst),
|
||||||
} else {
|
RISCV_FP_FMVXFCLASS => self.fp_fmvxfclass_instruction(inst),
|
||||||
self.fp_reg.set_reg(inst.rd, local_float)
|
RISCV_FP_FCMP => self.fp_fcmp_instruction(inst),
|
||||||
},
|
_ => Err(format!("Unreachable in fp_instruction match! Instruction was {:?}", inst))?
|
||||||
RISCV_FP_FSGN_JN => if self.fp_reg.get_reg(inst.rs2) < 0f32 {
|
|
||||||
self.fp_reg.set_reg(inst.rd, local_float)
|
|
||||||
} else {
|
|
||||||
self.fp_reg.set_reg(inst.rd, -local_float)
|
|
||||||
},
|
|
||||||
RISCV_FP_FSGN_JX => if (self.fp_reg.get_reg(inst.rs2) < 0.0 && self.fp_reg.get_reg(inst.rs1) >= 0.0) ||
|
|
||||||
(self.fp_reg.get_reg(inst.rs2) >= 0.0 && self.fp_reg.get_reg(inst.rs1) < 0.0) {
|
|
||||||
self.fp_reg.set_reg(inst.rd, -local_float)
|
|
||||||
} else {
|
|
||||||
self.fp_reg.set_reg(inst.rd, local_float)
|
|
||||||
},
|
|
||||||
_ => panic!("this instruction ({}) doesn't exists", inst.value)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RISCV_FP_MINMAX => {
|
|
||||||
let r1 = self.fp_reg.get_reg(inst.rs1);
|
|
||||||
let r2 = self.fp_reg.get_reg(inst.rs2);
|
|
||||||
match inst.funct3 {
|
|
||||||
RISCV_FP_MINMAX_MIN => self.fp_reg.set_reg(inst.rd, if r1 < r2 {r1} else {r2}),
|
|
||||||
RISCV_FP_MINMAX_MAX => self.fp_reg.set_reg(inst.rd, if r1 > r2 {r1} else {r2}),
|
|
||||||
_ => panic!("this instruction ({}) doesn't exists", inst.value)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RISCV_FP_FCVTW => {
|
|
||||||
if inst.rs2 == RISCV_FP_FCVTW_W {
|
|
||||||
self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64)
|
|
||||||
} else {
|
|
||||||
self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) as u64) as i64)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RISCV_FP_FCVTS => {
|
|
||||||
if inst.rs2 == RISCV_FP_FCVTS_W {
|
|
||||||
self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32);
|
|
||||||
} else {
|
|
||||||
self.fp_reg.set_reg(inst.rd, (self.int_reg.get_reg(inst.rs1) as u32) as f32);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RISCV_FP_FMVW => self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32),
|
|
||||||
RISCV_FP_FMVXFCLASS => {
|
|
||||||
if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX {
|
|
||||||
self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64);
|
|
||||||
} else {
|
|
||||||
panic!("Fclass instruction is not handled in riscv simulator");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
RISCV_FP_FCMP => {
|
|
||||||
match inst.funct3 {
|
|
||||||
RISCV_FP_FCMP_FEQ => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) == self.fp_reg.get_reg(inst.rs2)) as i64),
|
|
||||||
RISCV_FP_FCMP_FLT => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) < self.fp_reg.get_reg(inst.rs2)) as i64),
|
|
||||||
RISCV_FP_FCMP_FLE => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) <= self.fp_reg.get_reg(inst.rs2)) as i64),
|
|
||||||
_ => panic!("this instruction ({}) doesn't exists", inst.value)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => panic!("this instruction ({}) doesn't exists", inst.value)
|
|
||||||
}
|
}
|
||||||
Ok(())
|
}
|
||||||
|
|
||||||
|
/// Executes RISC-V sign-injection instruction on floating point values on the machine.
|
||||||
|
fn fp_fsgn_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
|
||||||
|
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<MachineOk, MachineError> {
|
||||||
|
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<MachineOk, MachineError> {
|
||||||
|
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<MachineOk, MachineError> {
|
||||||
|
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<MachineOk, MachineError> {
|
||||||
|
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<MachineOk, MachineError> {
|
||||||
|
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<MachineOk, MachineError> {
|
||||||
|
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
|
/// print memory FOR DEBUG
|
||||||
@ -605,6 +677,14 @@ impl Machine {
|
|||||||
pub fn write_fp_register(&mut self, index: usize, value: f32) {
|
pub fn write_fp_register(&mut self, index: usize, value: f32) {
|
||||||
self.fp_reg.set_reg(index as u8, value);
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
pub mod machine;
|
pub mod machine;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod decode;
|
pub mod instruction;
|
||||||
pub mod print;
|
|
||||||
pub mod mem_cmp;
|
pub mod mem_cmp;
|
||||||
pub mod loader;
|
pub mod loader;
|
||||||
pub mod interrupt;
|
pub mod interrupt;
|
||||||
|
@ -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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -6,6 +6,14 @@
|
|||||||
use crate::simulator::machine::{NUM_FP_REGS, NUM_INT_REGS};
|
use crate::simulator::machine::{NUM_FP_REGS, NUM_INT_REGS};
|
||||||
use std::ops::{Add, Sub};
|
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<Output=Self> + Sub<Output=Self> + PartialEq + Copy {}
|
pub trait RegisterNum: Add<Output=Self> + Sub<Output=Self> + PartialEq + Copy {}
|
||||||
|
|
||||||
impl RegisterNum for i64 {}
|
impl RegisterNum for i64 {}
|
||||||
|
@ -65,7 +65,7 @@ __start:
|
|||||||
|
|
||||||
.globl Halt
|
.globl Halt
|
||||||
.type __Halt, @function
|
.type __Halt, @function
|
||||||
Halt:
|
Shutdown:
|
||||||
addi a7,zero,SC_HALT
|
addi a7,zero,SC_HALT
|
||||||
ecall
|
ecall
|
||||||
jr ra
|
jr ra
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
typedef int t_error;
|
typedef int t_error;
|
||||||
|
|
||||||
/* Stop Nachos, and print out performance stats */
|
/* Stop Nachos, and print out performance stats */
|
||||||
void Halt();
|
void Shutdown();
|
||||||
|
|
||||||
|
|
||||||
/* Return the time spent running Nachos */
|
/* Return the time spent running Nachos */
|
||||||
|
21
test/userlib/syscall.rs
Normal file
21
test/userlib/syscall.rs
Normal file
@ -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) -> ();
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user