Merge branch 'thread_scheduler' into bin-loader
This commit is contained in:
@ -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)]
|
||||
|
Reference in New Issue
Block a user