Merge branch 'thread_scheduler' into bin-loader

This commit is contained in:
Quentin Legot
2023-04-04 15:28:24 +02:00
15 changed files with 989 additions and 713 deletions

View File

@ -16,14 +16,19 @@ use std::{
fs::File
};
use crate::simulator::{
print,
error::MachineError,
decode::*,
instruction::{*, self},
interrupt::Interrupt,
global::*,
register::*
};
use crate::kernel::{
exception
};
use super::error::MachineOk;
/// # Exceptions
///
/// Textual names of the exceptions that can be generated by user program
@ -49,6 +54,16 @@ pub enum ExceptionType {
NumExceptionTypes
}
/// # Machine Status
///
/// The machine can be running kernel code (SystemMode), user code (UserMode),
/// or there can be no running thread if the ready list is empty (IdleMode).
pub enum MachineStatus {
IdleMode,
SystemMode,
UserMode
}
/// ID of the stack register
pub const STACK_REG: usize = 2;
/// Number of available Integer registers
@ -79,9 +94,12 @@ pub struct Machine {
/// Debug data
pub registers_trace : String, // for tests
/// todo: document Interrupts
pub interrupt: Interrupt
pub interrupt: Interrupt,
// futur taille à calculer int memSize = g_cfg->NumPhysPages * g_cfg->PageSize;
//creer une struct cfg(configuration) qui s'initialise avec valeur dans un fichier cfg
/// Current machine status
pub status: MachineStatus
}
@ -106,7 +124,8 @@ impl Machine {
main_memory : vec![0_u8; MEM_SIZE],
shiftmask,
interrupt: Interrupt::new(),
registers_trace : String::from("")
registers_trace : String::from(""),
status: MachineStatus::SystemMode
}
}
@ -179,10 +198,10 @@ impl Machine {
pub fn print_status(&self) {
println!("######### Machine status #########");
for i in (0..32).step_by(3) {
print!(">{0: <4} : {1:<16x} ", print::REG_X[i], self.int_reg.get_reg(i as u8));
print!(">{0: <4} : {1:<16x} ", print::REG_X[i+1], self.int_reg.get_reg((i+1) as u8));
print!(">{0: <4} : {1:<16x} ", instruction::REG_X[i], self.int_reg.get_reg(i as u8));
print!(">{0: <4} : {1:<16x} ", instruction::REG_X[i+1], self.int_reg.get_reg((i+1) as u8));
if i+2 < 32 {
print!(">{0: <4} : {1:<16x} ", print::REG_X[i+2], self.int_reg.get_reg((i+2) as u8));
print!(">{0: <4} : {1:<16x} ", instruction::REG_X[i+2], self.int_reg.get_reg((i+2) as u8));
}
println!();
}
@ -207,6 +226,21 @@ impl Machine {
s
}
pub fn raise_exception(&mut self, exception: ExceptionType, address : u64) -> Result<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
///
/// ### Parameters
@ -215,7 +249,8 @@ impl Machine {
pub fn run(&mut self) {
loop {
match self.one_instruction() {
Ok(_) => println!("hello"),
Ok(MachineOk::Ok) => println!("hello"),
Ok(MachineOk::Shutdown) => break,
Err(e) => { if e.to_string().contains("System") { break; } panic!("FATAL at pc {} -> {}", self.pc, e) }
}
self.write_int_register(0, 0); // In case an instruction write on register 0
@ -227,7 +262,7 @@ impl Machine {
/// ### Parameters
///
/// - **machine** which contains a table of instructions and a pc to the actual instruction
pub fn one_instruction(&mut self) -> Result<(), MachineError> {
pub fn one_instruction(&mut self) -> Result<MachineOk, MachineError> {
if self.main_memory.len() <= self.pc as usize {
panic!("ERROR : number max of instructions rushed");
@ -238,10 +273,10 @@ impl Machine {
}
let val = u32::from_be_bytes(val) as u64;
let inst : Instruction = decode(val);
let inst : Instruction = Instruction::new(val);
self.print_status();
println!("executing instruction : {:016x} at pc 0x{:x}", val, self.pc);
println!("{}", print::print(decode(val), self.pc as i32));
println!("executing instruction : {:016x} at pc {:x}", val, self.pc);
println!("{}", instruction::instruction_debug(&inst, self.pc as i32));
let trace = Self::string_registers(self);
self.registers_trace.push_str(format!("{}\n", trace).as_str());
@ -251,20 +286,20 @@ impl Machine {
// Treatment for: LOAD UPPER IMMEDIATE INSTRUCTION
RISCV_LUI => {
self.int_reg.set_reg(inst.rd, inst.imm31_12 as i64);
Ok(())
Ok(MachineOk::Ok)
},
// Treatment for: ADD UPPER IMMEDIATE TO PC INSTRUCTION
RISCV_AUIPC => {
self.int_reg.set_reg(inst.rd, self.pc as i64 - 4 + inst.imm31_12 as i64);
Ok(())
Ok(MachineOk::Ok)
},
// Treatement for: JUMP AND LINK INSTRUCTIONS (direct jump)
RISCV_JAL => {
self.int_reg.set_reg(inst.rd, self.pc as i64);
self.pc = (self.pc as i64 + inst.imm21_1_signed as i64 - 4) as u64;
Ok(())
Ok((MachineOk::Ok))
},
// Treatment for: JUMP AND LINK REGISTER INSTRUCTIONS (indirect jump)
@ -272,35 +307,35 @@ impl Machine {
let tmp = self.pc;
self.pc = (self.int_reg.get_reg(inst.rs1) + inst.imm12_I_signed as i64) as u64 & 0xfffffffe;
self.int_reg.set_reg(inst.rd, tmp as i64);
Ok(())
Ok((MachineOk::Ok))
},
// Treatment for: BRANCH INSTRUCTIONS
RISCV_BR => self.branch_instruction(inst),
RISCV_BR => self.branch_instruction(inst),
// Treatment for: LOAD INSTRUCTIONS
RISCV_LD => self.load_instruction(inst),
RISCV_LD => self.load_instruction(inst),
// Treatment for: STORE INSTRUCTIONS
RISCV_ST => self.store_instruction(inst),
// Treatment for: OPI INSTRUCTIONS
RISCV_OPI => self.opi_instruction(inst),
RISCV_ST => self.store_instruction(inst),
// Treatment for: OP INSTRUCTIONS
RISCV_OP => self.op_instruction(inst),
RISCV_OP => self.op_instruction(inst),
// Treatment for: OPI INSTRUCTIONS
RISCV_OPI => self.opi_instruction(inst),
// Treatment for: OPW INSTRUCTIONS
RISCV_OPW => self.opw_instruction(inst),
// Treatment for OPIW INSTRUCTIONS
RISCV_OPIW => self.opiw_instruction(inst),
// Treatment for: OPW INSTRUCTIONS
RISCV_OPW => self.opw_instruction(inst),
RISCV_OPIW => self.opiw_instruction(inst),
// Treatment for: FLOATING POINT INSTRUCTIONS
RISCV_FP => self.fp_instruction(inst),
RISCV_FP => self.fp_instruction(inst),
// Treatment for: SYSTEM CALLS
RISCV_SYSTEM => Err(format!("{:x}: System opcode\npc: {:x}", inst.opcode, self.pc))?,
RISCV_SYSTEM => self.raise_exception(ExceptionType::SyscallException, self.pc),
// Default case
_ => Err(format!("{:x}: Unknown opcode\npc: {:x}", inst.opcode, self.pc))?
@ -308,7 +343,7 @@ impl Machine {
}
/// Treatement for Branch instructions
fn branch_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
fn branch_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
let op = match inst.funct3 {
RISCV_BR_BEQ => |a, b| a == b,
RISCV_BR_BNE => |a, b| a != b,
@ -316,152 +351,152 @@ impl Machine {
RISCV_BR_BGE => |a, b| a >= b,
RISCV_BR_BLTU => |a, b| a < b,
RISCV_BR_BGEU => |a, b| a >= b,
_ => unreachable!()
_ => Err(format!("Unreachable in branch_instruction match! Instruction was {:?}", inst))?
};
let rs1 = self.int_reg.get_reg(inst.rs1);
let rs2 = self.int_reg.get_reg(inst.rs2);
if op(rs1, rs2) {
self.pc = (self.pc as i64 + inst.imm13_signed as i64 - 4) as u64;
}
Ok(())
Ok(MachineOk::Ok)
}
/// Executes RISC-V Load Instructions on the machine
fn load_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
fn load_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
let mut set_reg = |rd, size| {
let val = self.read_memory(size, (self.int_reg.get_reg(inst.rs1) + inst.imm12_I_signed as i64) as usize) as i64;
self.int_reg.set_reg(rd, val);
Ok(())
Ok(MachineOk::Ok)
};
match inst.funct3 {
RISCV_LD_LB | RISCV_LD_LBU => set_reg(inst.rd, 1),
RISCV_LD_LH | RISCV_LD_LHU => set_reg(inst.rd, 2),
RISCV_LD_LW | RISCV_LD_LWU => set_reg(inst.rd, 4),
RISCV_LD_LD => set_reg(inst.rd, 8),
_ => Err(format!("In LD switch case, this should never happen... Instr was {}", inst.value).as_str())?
RISCV_LD_LB | RISCV_LD_LBU => set_reg(inst.rd, 1),
RISCV_LD_LH | RISCV_LD_LHU => set_reg(inst.rd, 2),
RISCV_LD_LW | RISCV_LD_LWU => set_reg(inst.rd, 4),
RISCV_LD_LD => set_reg(inst.rd, 8),
_ => Err(format!("Unreachable in load_instruction match! Instruction was {:?}", inst))?
}
}
/// Executes RISC-V Store Instructions on the machine
fn store_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
fn store_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
let mut store = |size| {
self.write_memory(
size,
(self.int_reg.get_reg(inst.rs1) + inst.imm12_S_signed as i64) as usize,
self.int_reg.get_reg(inst.rs2) as u64
);
Ok(())
Ok(MachineOk::Ok)
};
match inst.funct3 {
RISCV_ST_STB => store(1),
RISCV_ST_STH => store(2),
RISCV_ST_STW => store(4),
RISCV_ST_STD => store(8),
_ => Err(format!("In ST switch case, this should never happen... Instr was {}", inst.value).as_str())?
_ => Err(format!("Unreachable in store_instruction match! Instruction was {:?}", inst))?
}
}
/// Executes RISC-V Integer Register-Immediate Instructions on the machine
fn opi_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
fn opi_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
let rs1 = self.int_reg.get_reg(inst.rs1);
let imm12 = inst.imm12_I_signed as i64;
let shamt = inst.shamt as i64;
let mut compute = |operation: &dyn Fn (i64, i64) -> i64, a, b| {
self.int_reg.set_reg(inst.rd, operation(a, b));
Ok(())
Ok(MachineOk::Ok)
};
match inst.funct3 {
RISCV_OPI_ADDI => compute(&std::ops::Add::add, rs1, imm12),
RISCV_OPI_SLTI => compute(&|a, b| (a < b) as i64, rs1, imm12),
RISCV_OPI_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12),
RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12),
RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12),
RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, imm12),
RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI {
compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt)
} else {
compute(&core::ops::Shr::shr, rs1, shamt)
}
_ => Err(format!("In OPI switch case, this should never happen... Instr was %x\n {}", inst.value))?
RISCV_OPI_ADDI => compute(&std::ops::Add::add, rs1, imm12),
RISCV_OPI_SLTI => compute(&|a, b| (a < b) as i64, rs1, imm12),
RISCV_OPI_XORI => compute(&core::ops::BitXor::bitxor, rs1, imm12),
RISCV_OPI_ORI => compute(&core::ops::BitOr::bitor, rs1, imm12),
RISCV_OPI_ANDI => compute(&core::ops::BitAnd::bitand, rs1, imm12),
RISCV_OPI_SLLI => compute(&core::ops::Shl::shl, rs1, imm12),
RISCV_OPI_SRI => if inst.funct7_smaller == RISCV_OPI_SRI_SRLI {
compute(&|a, b| { (a >> b) & self.shiftmask[inst.shamt as usize] as i64 }, rs1, shamt)
} else {
compute(&core::ops::Shr::shr, rs1, shamt)
}
_ => Err(format!("Unreachable in opi_instruction match! Instruction was {:?}", inst))?
}
}
/// Executes simple RISC-V mathematical operations on the machine
fn op_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
fn op_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
let long_result: i128;
let unsigned_reg1: u64;
let unsigned_reg2: u64;
if inst.funct7 == 1 {
match inst.funct3 {
RISCV_OP_M_MUL => {
long_result = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128;
self.int_reg.set_reg(inst.rd, (long_result & 0xffffffffffffffff) as i64)
},
RISCV_OP_M_MULH => {
long_result = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128;
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64)
},
RISCV_OP_M_MULHSU => {
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
long_result = (self.int_reg.get_reg(inst.rs1) as u64 * unsigned_reg2) as i128;
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64)
},
RISCV_OP_M_MULHU => {
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
long_result = (unsigned_reg1 * unsigned_reg2) as i128;
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64);
},
RISCV_OP_M_DIV => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) / self.int_reg.get_reg(inst.rs2)),
_ => panic!("RISCV_OP : funct7 = 1 (Multiplication) :: Error\n")
RISCV_OP_M_MUL => {
long_result = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128;
self.int_reg.set_reg(inst.rd, (long_result & 0xffffffffffffffff) as i64)
},
RISCV_OP_M_MULH => {
long_result = (self.int_reg.get_reg(inst.rs1) * self.int_reg.get_reg(inst.rs2)) as i128;
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64)
},
RISCV_OP_M_MULHSU => {
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
long_result = (self.int_reg.get_reg(inst.rs1) as u64 * unsigned_reg2) as i128;
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64)
},
RISCV_OP_M_MULHU => {
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
long_result = (unsigned_reg1 * unsigned_reg2) as i128;
self.int_reg.set_reg(inst.rd, ((long_result >> 64) & 0xffffffffffffffff) as i64);
},
RISCV_OP_M_DIV => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) / self.int_reg.get_reg(inst.rs2)),
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
}
} else {
match inst.funct3 {
RISCV_OP_ADD => if inst.funct7 == RISCV_OP_ADD_ADD {
self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) + self.int_reg.get_reg(inst.rs2))
} else {
self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) - self.int_reg.get_reg(inst.rs2))
},
RISCV_OP_SLL => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) << (self.int_reg.get_reg(inst.rs2) & 0x3f)),
RISCV_OP_SLT => if self.int_reg.get_reg(inst.rs1) < self.int_reg.get_reg(inst.rs2) {
self.int_reg.set_reg(inst.rd, 1)
} else {
self.int_reg.set_reg(inst.rd, 0)
},
RISCV_OP_SLTU => {
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
if unsigned_reg1 < unsigned_reg2 {
self.int_reg.set_reg(inst.rd, 1)
} else {
self.int_reg.set_reg(inst.rd, 0)
}
},
RISCV_OP_XOR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) ^ self.int_reg.get_reg(inst.rs2)),
RISCV_OP_SR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) >> self.int_reg.get_reg(inst.rs2)), // RISCV_OP_SR_SRL inaccessible
RISCV_OP_OR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) | self.int_reg.get_reg(inst.rs2)),
RISCV_OP_AND => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) & self.int_reg.get_reg(inst.rs2)),
_ => panic!("RISCV_OP undefined case\n")
RISCV_OP_ADD => if inst.funct7 == RISCV_OP_ADD_ADD {
self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) + self.int_reg.get_reg(inst.rs2))
} else {
self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) - self.int_reg.get_reg(inst.rs2))
},
RISCV_OP_SLL => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) << (self.int_reg.get_reg(inst.rs2) & 0x3f)),
RISCV_OP_SLT => if self.int_reg.get_reg(inst.rs1) < self.int_reg.get_reg(inst.rs2) {
self.int_reg.set_reg(inst.rd, 1)
} else {
self.int_reg.set_reg(inst.rd, 0)
},
RISCV_OP_SLTU => {
unsigned_reg1 = self.int_reg.get_reg(inst.rs1) as u64;
unsigned_reg2 = self.int_reg.get_reg(inst.rs2) as u64;
if unsigned_reg1 < unsigned_reg2 {
self.int_reg.set_reg(inst.rd, 1)
} else {
self.int_reg.set_reg(inst.rd, 0)
}
},
RISCV_OP_XOR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) ^ self.int_reg.get_reg(inst.rs2)),
RISCV_OP_SR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) >> self.int_reg.get_reg(inst.rs2)), // RISCV_OP_SR_SRL inaccessible
RISCV_OP_OR => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) | self.int_reg.get_reg(inst.rs2)),
RISCV_OP_AND => self.int_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) & self.int_reg.get_reg(inst.rs2)),
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
}
}
Ok(())
Ok(MachineOk::Ok)
}
/// Exectutes simple RISC-V *iw instructions on the machine
fn opiw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
fn opiw_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
let local_data = self.int_reg.get_reg(inst.rs1);
let result = match inst.funct3 {
RISCV_OPIW_ADDIW => local_data + inst.imm12_I_signed as i64,
RISCV_OPIW_SLLIW => local_data << inst.shamt,
RISCV_OPIW_SRW => (local_data >> inst.shamt) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.shamt as usize] as i64 } else { 1 },
_ => Err("In OPI switch case, this should never happen... Instr was {}\n")?,
RISCV_OPIW_SRW => (local_data >> inst.shamt) & if inst.funct7 == RISCV_OPIW_SRW_SRLIW { self.shiftmask[32 + inst.shamt as usize] as i64 } else { 1 },
_ => Err(format!("Unreachable in op_instruction match! Instruction was {:?}", inst))?
};
self.int_reg.set_reg(inst.rd, result);
Ok(())
Ok(MachineOk::Ok)
}
/// Executes simple RISC-V *w instructions on the machine
fn opw_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
fn opw_instruction(&mut self, inst: Instruction) -> Result<MachineOk, MachineError> {
if inst.funct7 == 1 { // rv64m
let local_data_a = self.int_reg.get_reg(inst.rs1) & 0xffffffff;
let local_data_b = self.int_reg.get_reg(inst.rs2) & 0xffffffff;
@ -470,107 +505,144 @@ impl Machine {
// Match case for multiplication operations (in standard extension RV32M)
match inst.funct3 {
RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, local_data_a * local_data_b),
RISCV_OPW_M_DIVW => self.int_reg.set_reg(inst.rd, local_data_a / local_data_b),
RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned),
RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b),
RISCV_OPW_M_REMUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned % local_data_b_unsigned),
_ => panic!("this instruction ({}) doesn't exists", inst.value)
RISCV_OPW_M_MULW => self.int_reg.set_reg(inst.rd, local_data_a * local_data_b),
RISCV_OPW_M_DIVW => self.int_reg.set_reg(inst.rd, local_data_a / local_data_b),
RISCV_OPW_M_DIVUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned / local_data_b_unsigned),
RISCV_OPW_M_REMW => self.int_reg.set_reg(inst.rd, local_data_a % local_data_b),
RISCV_OPW_M_REMUW => self.int_reg.set_reg(inst.rd, local_data_a_unsigned % local_data_b_unsigned),
_ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
}
} else { // others rv64 OPW operations
let local_dataa = self.int_reg.get_reg(inst.rs1) & 0xffffffff;
let local_datab = self.int_reg.get_reg(inst.rs2) & 0xffffffff;
// Match case for base OP operation
match inst.funct3 {
RISCV_OPW_ADDSUBW => if inst.funct7 == RISCV_OPW_ADDSUBW_ADDW {
self.int_reg.set_reg(inst.rd, local_dataa + local_datab);
} else { // SUBW
self.int_reg.set_reg(inst.rd, local_dataa - local_datab);
},
RISCV_OPW_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)),
RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW {
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f) & self.shiftmask[32 + local_datab as usize] as i64)
} else { // SRAW
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f))
},
_ => panic!("this instruction ({}) doesn't exist", inst.value)
RISCV_OPW_ADDSUBW => if inst.funct7 == RISCV_OPW_ADDSUBW_ADDW {
self.int_reg.set_reg(inst.rd, local_dataa + local_datab);
} else { // SUBW
self.int_reg.set_reg(inst.rd, local_dataa - local_datab);
},
RISCV_OPW_SLLW => self.int_reg.set_reg(inst.rd, local_dataa << (local_datab & 0x1f)),
RISCV_OPW_SRW => if inst.funct7 == RISCV_OPW_SRW_SRLW {
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f) & self.shiftmask[32 + local_datab as usize] as i64)
} else { // SRAW
self.int_reg.set_reg(inst.rd, local_dataa >> (local_datab & 0x1f))
},
_ => Err(format!("Unreachable in opw_instruction match! Instruction was {:?}", inst))?
}
}
Ok(())
Ok(MachineOk::Ok)
}
/// Executes simple RISC-V floating point instructions on the machine
fn fp_instruction(&mut self, inst: Instruction) -> Result<(), MachineError> {
/// Executes simple RISC-V floating point instructions on the machine.
///
/// See Risc-V Spec v2.2 Chapter 8: “F” Standard Extension for Single-Precision Floating-Point, Version 2.0.
fn fp_instruction(&mut self, inst: Instruction) -> Result<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 {
RISCV_FP_ADD => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) + self.fp_reg.get_reg(inst.rs2)),
RISCV_FP_SUB => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) - self.fp_reg.get_reg(inst.rs2)),
RISCV_FP_MUL => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) * self.fp_reg.get_reg(inst.rs2)),
RISCV_FP_DIV => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) / self.fp_reg.get_reg(inst.rs2)),
RISCV_FP_SQRT => self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1).sqrt()),
RISCV_FP_FSGN => {
let local_float = self.fp_reg.get_reg(inst.rs1);
match inst.funct3 {
RISCV_FP_FSGN_J => if self.fp_reg.get_reg(inst.rs2) < 0f32 {
self.fp_reg.set_reg(inst.rd, -local_float)
} else {
self.fp_reg.set_reg(inst.rd, local_float)
},
RISCV_FP_FSGN_JN => if self.fp_reg.get_reg(inst.rs2) < 0f32 {
self.fp_reg.set_reg(inst.rd, local_float)
} else {
self.fp_reg.set_reg(inst.rd, -local_float)
},
RISCV_FP_FSGN_JX => if (self.fp_reg.get_reg(inst.rs2) < 0.0 && self.fp_reg.get_reg(inst.rs1) >= 0.0) ||
(self.fp_reg.get_reg(inst.rs2) >= 0.0 && self.fp_reg.get_reg(inst.rs1) < 0.0) {
self.fp_reg.set_reg(inst.rd, -local_float)
} else {
self.fp_reg.set_reg(inst.rd, local_float)
},
_ => panic!("this instruction ({}) doesn't exists", inst.value)
}
},
RISCV_FP_MINMAX => {
let r1 = self.fp_reg.get_reg(inst.rs1);
let r2 = self.fp_reg.get_reg(inst.rs2);
match inst.funct3 {
RISCV_FP_MINMAX_MIN => self.fp_reg.set_reg(inst.rd, if r1 < r2 {r1} else {r2}),
RISCV_FP_MINMAX_MAX => self.fp_reg.set_reg(inst.rd, if r1 > r2 {r1} else {r2}),
_ => panic!("this instruction ({}) doesn't exists", inst.value)
}
},
RISCV_FP_FCVTW => {
if inst.rs2 == RISCV_FP_FCVTW_W {
self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64)
} else {
self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) as u64) as i64)
}
},
RISCV_FP_FCVTS => {
if inst.rs2 == RISCV_FP_FCVTS_W {
self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32);
} else {
self.fp_reg.set_reg(inst.rd, (self.int_reg.get_reg(inst.rs1) as u32) as f32);
}
},
RISCV_FP_FMVW => self.fp_reg.set_reg(inst.rd, self.int_reg.get_reg(inst.rs1) as f32),
RISCV_FP_FMVXFCLASS => {
if inst.funct3 == RISCV_FP_FMVXFCLASS_FMVX {
self.int_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1) as i64);
} else {
panic!("Fclass instruction is not handled in riscv simulator");
}
},
RISCV_FP_FCMP => {
match inst.funct3 {
RISCV_FP_FCMP_FEQ => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) == self.fp_reg.get_reg(inst.rs2)) as i64),
RISCV_FP_FCMP_FLT => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) < self.fp_reg.get_reg(inst.rs2)) as i64),
RISCV_FP_FCMP_FLE => self.int_reg.set_reg(inst.rd, (self.fp_reg.get_reg(inst.rs1) <= self.fp_reg.get_reg(inst.rs2)) as i64),
_ => panic!("this instruction ({}) doesn't exists", inst.value)
}
},
_ => panic!("this instruction ({}) doesn't exists", inst.value)
RISCV_FP_ADD => set_reg(&core::ops::Add::add),
RISCV_FP_SUB => set_reg(&core::ops::Sub::sub),
RISCV_FP_MUL => set_reg(&core::ops::Mul::mul),
RISCV_FP_DIV => set_reg(&core::ops::Div::div),
RISCV_FP_SQRT => { self.fp_reg.set_reg(inst.rd, self.fp_reg.get_reg(inst.rs1).sqrt()); Ok(MachineOk::Ok) },
RISCV_FP_FSGN => self.fp_fsgn_instruction(inst),
RISCV_FP_MINMAX => self.fp_minmax_instruction(inst),
RISCV_FP_FCVTW => self.fp_fcvtw_instruction(inst),
RISCV_FP_FCVTS => self.fp_fcvts_instruction(inst),
RISCV_FP_FMVW => self.fp_fmvw_instruction(inst),
RISCV_FP_FMVXFCLASS => self.fp_fmvxfclass_instruction(inst),
RISCV_FP_FCMP => self.fp_fcmp_instruction(inst),
_ => Err(format!("Unreachable in fp_instruction match! Instruction was {:?}", inst))?
}
Ok(())
}
/// Executes RISC-V sign-injection instruction on floating point values on the machine.
fn fp_fsgn_instruction(&mut self, inst: Instruction) -> Result<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
@ -605,6 +677,14 @@ impl Machine {
pub fn write_fp_register(&mut self, index: usize, value: f32) {
self.fp_reg.set_reg(index as u8, value);
}
pub fn get_status(&self) -> MachineStatus {
todo!()
}
pub fn set_status(&mut self, new_status: MachineStatus) {
self.status = new_status;
}
}
#[cfg(test)]