use std::collections::HashMap;
use mmu::{AddressingMode, Mmu};
use terminal::Terminal;
const CSR_CAPACITY: usize = 4096;
const CSR_USTATUS_ADDRESS: u16 = 0x000;
const CSR_FFLAGS_ADDRESS: u16 = 0x001;
const CSR_FRM_ADDRESS: u16 = 0x002;
const CSR_FCSR_ADDRESS: u16 = 0x003;
const CSR_UIE_ADDRESS: u16 = 0x004;
const CSR_UTVEC_ADDRESS: u16 = 0x005;
const _CSR_USCRATCH_ADDRESS: u16 = 0x040;
const CSR_UEPC_ADDRESS: u16 = 0x041;
const CSR_UCAUSE_ADDRESS: u16 = 0x042;
const CSR_UTVAL_ADDRESS: u16 = 0x043;
const _CSR_UIP_ADDRESS: u16 = 0x044;
const CSR_SSTATUS_ADDRESS: u16 = 0x100;
const CSR_SEDELEG_ADDRESS: u16 = 0x102;
const CSR_SIDELEG_ADDRESS: u16 = 0x103;
const CSR_SIE_ADDRESS: u16 = 0x104;
const CSR_STVEC_ADDRESS: u16 = 0x105;
const _CSR_SSCRATCH_ADDRESS: u16 = 0x140;
const CSR_SEPC_ADDRESS: u16 = 0x141;
const CSR_SCAUSE_ADDRESS: u16 = 0x142;
const CSR_STVAL_ADDRESS: u16 = 0x143;
const CSR_SIP_ADDRESS: u16 = 0x144;
const CSR_SATP_ADDRESS: u16 = 0x180;
const CSR_MSTATUS_ADDRESS: u16 = 0x300;
const CSR_MISA_ADDRESS: u16 = 0x301;
const CSR_MEDELEG_ADDRESS: u16 = 0x302;
const CSR_MIDELEG_ADDRESS: u16 = 0x303;
const CSR_MIE_ADDRESS: u16 = 0x304;
const CSR_MTVEC_ADDRESS: u16 = 0x305;
const _CSR_MSCRATCH_ADDRESS: u16 = 0x340;
const CSR_MEPC_ADDRESS: u16 = 0x341;
const CSR_MCAUSE_ADDRESS: u16 = 0x342;
const CSR_MTVAL_ADDRESS: u16 = 0x343;
const CSR_MIP_ADDRESS: u16 = 0x344;
const _CSR_PMPCFG0_ADDRESS: u16 = 0x3a0;
const _CSR_PMPADDR0_ADDRESS: u16 = 0x3b0;
const _CSR_MCYCLE_ADDRESS: u16 = 0xb00;
const CSR_CYCLE_ADDRESS: u16 = 0xc00;
const CSR_TIME_ADDRESS: u16 = 0xc01;
const _CSR_INSERT_ADDRESS: u16 = 0xc02;
const _CSR_MHARTID_ADDRESS: u16 = 0xf14;
const MIP_MEIP: u64 = 0x800;
pub const MIP_MTIP: u64 = 0x080;
pub const MIP_MSIP: u64 = 0x008;
pub const MIP_SEIP: u64 = 0x200;
const MIP_STIP: u64 = 0x020;
const MIP_SSIP: u64 = 0x002;
pub struct Cpu {
clock: u64,
xlen: Xlen,
privilege_mode: PrivilegeMode,
wfi: bool,
x: [i64; 32],
f: [f64; 32],
pc: u64,
csr: [u64; CSR_CAPACITY],
mmu: Mmu,
reservation: u64, is_reservation_set: bool,
_dump_flag: bool,
decode_cache: DecodeCache
}
#[derive(Clone)]
pub enum Xlen {
Bit32,
Bit64
}
#[derive(Clone)]
#[allow(dead_code)]
pub enum PrivilegeMode {
User,
Supervisor,
Reserved,
Machine
}
pub struct Trap {
pub trap_type: TrapType,
pub value: u64 }
#[allow(dead_code)]
pub enum TrapType {
InstructionAddressMisaligned,
InstructionAccessFault,
IllegalInstruction,
Breakpoint,
LoadAddressMisaligned,
LoadAccessFault,
StoreAddressMisaligned,
StoreAccessFault,
EnvironmentCallFromUMode,
EnvironmentCallFromSMode,
EnvironmentCallFromMMode,
InstructionPageFault,
LoadPageFault,
StorePageFault,
UserSoftwareInterrupt,
SupervisorSoftwareInterrupt,
MachineSoftwareInterrupt,
UserTimerInterrupt,
SupervisorTimerInterrupt,
MachineTimerInterrupt,
UserExternalInterrupt,
SupervisorExternalInterrupt,
MachineExternalInterrupt
}
fn _get_privilege_mode_name(mode: &PrivilegeMode) -> &'static str {
match mode {
PrivilegeMode::User => "User",
PrivilegeMode::Supervisor => "Supervisor",
PrivilegeMode::Reserved => "Reserved",
PrivilegeMode::Machine => "Machine"
}
}
fn get_privilege_encoding(mode: &PrivilegeMode) -> u8 {
match mode {
PrivilegeMode::User => 0,
PrivilegeMode::Supervisor => 1,
PrivilegeMode::Reserved => panic!(),
PrivilegeMode::Machine => 3
}
}
fn _get_trap_type_name(trap_type: &TrapType) -> &'static str {
match trap_type {
TrapType::InstructionAddressMisaligned => "InstructionAddressMisaligned",
TrapType::InstructionAccessFault => "InstructionAccessFault",
TrapType::IllegalInstruction => "IllegalInstruction",
TrapType::Breakpoint => "Breakpoint",
TrapType::LoadAddressMisaligned => "LoadAddressMisaligned",
TrapType::LoadAccessFault => "LoadAccessFault",
TrapType::StoreAddressMisaligned => "StoreAddressMisaligned",
TrapType::StoreAccessFault => "StoreAccessFault",
TrapType::EnvironmentCallFromUMode => "EnvironmentCallFromUMode",
TrapType::EnvironmentCallFromSMode => "EnvironmentCallFromSMode",
TrapType::EnvironmentCallFromMMode => "EnvironmentCallFromMMode",
TrapType::InstructionPageFault => "InstructionPageFault",
TrapType::LoadPageFault => "LoadPageFault",
TrapType::StorePageFault => "StorePageFault",
TrapType::UserSoftwareInterrupt => "UserSoftwareInterrupt",
TrapType::SupervisorSoftwareInterrupt => "SupervisorSoftwareInterrupt",
TrapType::MachineSoftwareInterrupt => "MachineSoftwareInterrupt",
TrapType::UserTimerInterrupt => "UserTimerInterrupt",
TrapType::SupervisorTimerInterrupt => "SupervisorTimerInterrupt",
TrapType::MachineTimerInterrupt => "MachineTimerInterrupt",
TrapType::UserExternalInterrupt => "UserExternalInterrupt",
TrapType::SupervisorExternalInterrupt => "SupervisorExternalInterrupt",
TrapType::MachineExternalInterrupt => "MachineExternalInterrupt"
}
}
fn get_trap_cause(trap: &Trap, xlen: &Xlen) -> u64 {
let interrupt_bit = match xlen {
Xlen::Bit32 => 0x80000000 as u64,
Xlen::Bit64 => 0x8000000000000000 as u64,
};
match trap.trap_type {
TrapType::InstructionAddressMisaligned => 0,
TrapType::InstructionAccessFault => 1,
TrapType::IllegalInstruction => 2,
TrapType::Breakpoint => 3,
TrapType::LoadAddressMisaligned => 4,
TrapType::LoadAccessFault => 5,
TrapType::StoreAddressMisaligned => 6,
TrapType::StoreAccessFault => 7,
TrapType::EnvironmentCallFromUMode => 8,
TrapType::EnvironmentCallFromSMode => 9,
TrapType::EnvironmentCallFromMMode => 11,
TrapType::InstructionPageFault => 12,
TrapType::LoadPageFault => 13,
TrapType::StorePageFault => 15,
TrapType::UserSoftwareInterrupt => interrupt_bit,
TrapType::SupervisorSoftwareInterrupt => interrupt_bit + 1,
TrapType::MachineSoftwareInterrupt => interrupt_bit + 3,
TrapType::UserTimerInterrupt => interrupt_bit + 4,
TrapType::SupervisorTimerInterrupt => interrupt_bit + 5,
TrapType::MachineTimerInterrupt => interrupt_bit + 7,
TrapType::UserExternalInterrupt => interrupt_bit + 8,
TrapType::SupervisorExternalInterrupt => interrupt_bit + 9,
TrapType::MachineExternalInterrupt => interrupt_bit + 11
}
}
impl Cpu {
pub fn new(terminal: Box<dyn Terminal>) -> Self {
let mut cpu = Cpu {
clock: 0,
xlen: Xlen::Bit64,
privilege_mode: PrivilegeMode::Machine,
wfi: false,
x: [0; 32],
f: [0.0; 32],
pc: 0,
csr: [0; CSR_CAPACITY],
mmu: Mmu::new(Xlen::Bit64, terminal),
reservation: 0,
is_reservation_set: false,
_dump_flag: false,
decode_cache: DecodeCache::new()
};
cpu.x[0xb] = 0x1020; cpu.write_csr_raw(CSR_MISA_ADDRESS, 0x800000008014312f);
cpu
}
pub fn update_pc(&mut self, value: u64) {
self.pc = value;
}
pub fn update_xlen(&mut self, xlen: Xlen) {
self.xlen = xlen.clone();
self.mmu.update_xlen(xlen.clone());
}
pub fn read_register(&self, reg: u8) -> i64 {
assert!(reg <= 31, "reg must be 0-31. {}", reg);
self.x[reg as usize]
}
pub fn read_pc(&self) -> u64 {
self.pc
}
pub fn tick(&mut self) {
let instruction_address = self.pc;
match self.tick_operate() {
Ok(()) => {},
Err(e) => self.handle_exception(e, instruction_address)
}
self.mmu.tick(&mut self.csr[CSR_MIP_ADDRESS as usize]);
self.handle_interrupt(self.pc);
self.clock = self.clock.wrapping_add(1);
self.write_csr_raw(CSR_CYCLE_ADDRESS, self.clock);
}
fn tick_operate(&mut self) -> Result<(), Trap> {
if self.wfi {
return Ok(());
}
let original_word = match self.fetch() {
Ok(word) => word,
Err(e) => return Err(e)
};
let instruction_address = self.pc;
let word = match (original_word & 0x3) == 0x3 {
true => {
self.pc = self.pc.wrapping_add(4); original_word
},
false => {
self.pc = self.pc.wrapping_add(2); self.uncompress(original_word & 0xffff)
}
};
match self.decode(word) {
Ok(inst) => {
let result = (inst.operation)(self, word, instruction_address);
self.x[0] = 0; return result;
},
Err(()) => {
panic!("Unknown instruction PC:{:x} WORD:{:x}", instruction_address, original_word);
}
};
}
fn decode(&mut self, word: u32) -> Result<&Instruction, ()> {
match self.decode_cache.get(word) {
Some(index) => return Ok(&INSTRUCTIONS[index]),
None => match self.decode_and_get_instruction_index(word) {
Ok(index) => {
self.decode_cache.insert(word, index);
Ok(&INSTRUCTIONS[index])
},
Err(()) => Err(())
}
}
}
fn decode_raw(&self, word: u32) -> Result<&Instruction, ()> {
match self.decode_and_get_instruction_index(word) {
Ok(index) => Ok(&INSTRUCTIONS[index]),
Err(()) => Err(())
}
}
fn decode_and_get_instruction_index(&self, word: u32) -> Result<usize, ()> {
for i in 0..INSTRUCTION_NUM {
let inst = &INSTRUCTIONS[i];
if (word & inst.mask) == inst.data {
return Ok(i);
}
}
return Err(())
}
fn handle_interrupt(&mut self, instruction_address: u64) {
let minterrupt = self.read_csr_raw(CSR_MIP_ADDRESS) & self.read_csr_raw(CSR_MIE_ADDRESS);
if (minterrupt & MIP_MEIP) != 0 {
if self.handle_trap(Trap {
trap_type: TrapType::MachineExternalInterrupt,
value: self.pc }, instruction_address, true) {
self.write_csr_raw(CSR_MIP_ADDRESS, self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_MEIP);
self.wfi = false;
return;
}
}
if (minterrupt & MIP_MSIP) != 0 {
if self.handle_trap(Trap {
trap_type: TrapType::MachineSoftwareInterrupt,
value: self.pc }, instruction_address, true) {
self.write_csr_raw(CSR_MIP_ADDRESS, self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_MSIP);
self.wfi = false;
return;
}
}
if (minterrupt & MIP_MTIP) != 0 {
if self.handle_trap(Trap {
trap_type: TrapType::MachineTimerInterrupt,
value: self.pc }, instruction_address, true) {
self.write_csr_raw(CSR_MIP_ADDRESS, self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_MTIP);
self.wfi = false;
return;
}
}
if (minterrupt & MIP_SEIP) != 0 {
if self.handle_trap(Trap {
trap_type: TrapType::SupervisorExternalInterrupt,
value: self.pc }, instruction_address, true) {
self.write_csr_raw(CSR_MIP_ADDRESS, self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_SEIP);
self.wfi = false;
return;
}
}
if (minterrupt & MIP_SSIP) != 0 {
if self.handle_trap(Trap {
trap_type: TrapType::SupervisorSoftwareInterrupt,
value: self.pc }, instruction_address, true) {
self.write_csr_raw(CSR_MIP_ADDRESS, self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_SEIP);
self.wfi = false;
return;
}
}
if (minterrupt & MIP_STIP) != 0 {
if self.handle_trap(Trap {
trap_type: TrapType::SupervisorTimerInterrupt,
value: self.pc }, instruction_address, true) {
self.write_csr_raw(CSR_MIP_ADDRESS, self.read_csr_raw(CSR_MIP_ADDRESS) & !MIP_STIP);
self.wfi = false;
return;
}
}
}
fn handle_exception(&mut self, exception: Trap, instruction_address: u64) {
self.handle_trap(exception, instruction_address, false);
}
fn handle_trap(&mut self, trap: Trap, instruction_address: u64, is_interrupt: bool) -> bool{
let current_privilege_encoding = get_privilege_encoding(&self.privilege_mode) as u64;
let cause = get_trap_cause(&trap, &self.xlen);
let mdeleg = match is_interrupt {
true => self.read_csr_raw(CSR_MIDELEG_ADDRESS),
false => self.read_csr_raw(CSR_MEDELEG_ADDRESS)
};
let sdeleg = match is_interrupt {
true => self.read_csr_raw(CSR_SIDELEG_ADDRESS),
false => self.read_csr_raw(CSR_SEDELEG_ADDRESS)
};
let pos = cause & 0xffff;
let new_privilege_mode = match ((mdeleg >> pos) & 1) == 0 {
true => PrivilegeMode::Machine,
false => match ((sdeleg >> pos) & 1) == 0 {
true => PrivilegeMode::Supervisor,
false => PrivilegeMode::User
}
};
let new_privilege_encoding = get_privilege_encoding(&new_privilege_mode) as u64;
let current_status = match self.privilege_mode {
PrivilegeMode::Machine => self.read_csr_raw(CSR_MSTATUS_ADDRESS),
PrivilegeMode::Supervisor => self.read_csr_raw(CSR_SSTATUS_ADDRESS),
PrivilegeMode::User => self.read_csr_raw(CSR_USTATUS_ADDRESS),
PrivilegeMode::Reserved => panic!(),
};
if is_interrupt {
let ie = match new_privilege_mode {
PrivilegeMode::Machine => self.read_csr_raw(CSR_MIE_ADDRESS),
PrivilegeMode::Supervisor => self.read_csr_raw(CSR_SIE_ADDRESS),
PrivilegeMode::User => self.read_csr_raw(CSR_UIE_ADDRESS),
PrivilegeMode::Reserved => panic!(),
};
let current_mie = (current_status >> 3) & 1;
let current_sie = (current_status >> 1) & 1;
let current_uie = current_status & 1;
let msie = (ie >> 3) & 1;
let ssie = (ie >> 1) & 1;
let usie = ie & 1;
let mtie = (ie >> 7) & 1;
let stie = (ie >> 5) & 1;
let utie = (ie >> 4) & 1;
let meie = (ie >> 11) & 1;
let seie = (ie >> 9) & 1;
let ueie = (ie >> 8) & 1;
if new_privilege_encoding < current_privilege_encoding {
return false;
} else if current_privilege_encoding == new_privilege_encoding {
match self.privilege_mode {
PrivilegeMode::Machine => {
if current_mie == 0 {
return false;
}
},
PrivilegeMode::Supervisor => {
if current_sie == 0 {
return false;
}
},
PrivilegeMode::User => {
if current_uie == 0 {
return false;
}
},
PrivilegeMode::Reserved => panic!()
};
}
match trap.trap_type {
TrapType::UserSoftwareInterrupt => {
if usie == 0 {
return false;
}
},
TrapType::SupervisorSoftwareInterrupt => {
if ssie == 0 {
return false;
}
},
TrapType::MachineSoftwareInterrupt => {
if msie == 0 {
return false;
}
},
TrapType::UserTimerInterrupt => {
if utie == 0 {
return false;
}
},
TrapType::SupervisorTimerInterrupt => {
if stie == 0 {
return false;
}
},
TrapType::MachineTimerInterrupt => {
if mtie == 0 {
return false;
}
},
TrapType::UserExternalInterrupt => {
if ueie == 0 {
return false;
}
},
TrapType::SupervisorExternalInterrupt => {
if seie == 0 {
return false;
}
},
TrapType::MachineExternalInterrupt => {
if meie == 0 {
return false;
}
},
_ => {}
};
}
self.privilege_mode = new_privilege_mode;
self.mmu.update_privilege_mode(self.privilege_mode.clone());
let csr_epc_address = match self.privilege_mode {
PrivilegeMode::Machine => CSR_MEPC_ADDRESS,
PrivilegeMode::Supervisor => CSR_SEPC_ADDRESS,
PrivilegeMode::User => CSR_UEPC_ADDRESS,
PrivilegeMode::Reserved => panic!()
};
let csr_cause_address = match self.privilege_mode {
PrivilegeMode::Machine => CSR_MCAUSE_ADDRESS,
PrivilegeMode::Supervisor => CSR_SCAUSE_ADDRESS,
PrivilegeMode::User => CSR_UCAUSE_ADDRESS,
PrivilegeMode::Reserved => panic!()
};
let csr_tval_address = match self.privilege_mode {
PrivilegeMode::Machine => CSR_MTVAL_ADDRESS,
PrivilegeMode::Supervisor => CSR_STVAL_ADDRESS,
PrivilegeMode::User => CSR_UTVAL_ADDRESS,
PrivilegeMode::Reserved => panic!()
};
let csr_tvec_address = match self.privilege_mode {
PrivilegeMode::Machine => CSR_MTVEC_ADDRESS,
PrivilegeMode::Supervisor => CSR_STVEC_ADDRESS,
PrivilegeMode::User => CSR_UTVEC_ADDRESS,
PrivilegeMode::Reserved => panic!()
};
self.write_csr_raw(csr_epc_address, instruction_address);
self.write_csr_raw(csr_cause_address, cause);
self.write_csr_raw(csr_tval_address, trap.value);
self.pc = self.read_csr_raw(csr_tvec_address);
if (self.pc & 0x3) != 0 {
self.pc = (self.pc & !0x3) + 4 * (cause & 0xffff);
}
match self.privilege_mode {
PrivilegeMode::Machine => {
let status = self.read_csr_raw(CSR_MSTATUS_ADDRESS);
let mie = (status >> 3) & 1;
let new_status = (status & !0x1888) | (mie << 7) | (current_privilege_encoding << 11);
self.write_csr_raw(CSR_MSTATUS_ADDRESS, new_status);
},
PrivilegeMode::Supervisor => {
let status = self.read_csr_raw(CSR_SSTATUS_ADDRESS);
let sie = (status >> 1) & 1;
let new_status = (status & !0x122) | (sie << 5) | ((current_privilege_encoding & 1) << 8);
self.write_csr_raw(CSR_SSTATUS_ADDRESS, new_status);
},
PrivilegeMode::User => {
panic!("Not implemented yet");
},
PrivilegeMode::Reserved => panic!() };
true
}
fn fetch(&mut self) -> Result<u32, Trap> {
let word = match self.mmu.fetch_word(self.pc) {
Ok(word) => word,
Err(e) => {
self.pc = self.pc.wrapping_add(4); return Err(e);
}
};
Ok(word)
}
fn has_csr_access_privilege(&self, address: u16) -> bool {
let privilege = (address >> 8) & 0x3; privilege as u8 <= get_privilege_encoding(&self.privilege_mode)
}
fn read_csr(&mut self, address: u16) -> Result<u64, Trap> {
match self.has_csr_access_privilege(address) {
true => Ok(self.read_csr_raw(address)),
false => Err(Trap {
trap_type: TrapType::IllegalInstruction,
value: self.pc.wrapping_sub(4) })
}
}
fn write_csr(&mut self, address: u16, value: u64) -> Result<(), Trap> {
match self.has_csr_access_privilege(address) {
true => {
self.write_csr_raw(address, value);
if address == CSR_SATP_ADDRESS {
self.update_addressing_mode(value);
}
Ok(())
},
false => Err(Trap {
trap_type: TrapType::IllegalInstruction,
value: self.pc.wrapping_sub(4) })
}
}
fn read_csr_raw(&self, address: u16) -> u64 {
match address {
CSR_FFLAGS_ADDRESS => self.csr[CSR_FCSR_ADDRESS as usize] & 0x1f,
CSR_FRM_ADDRESS => (self.csr[CSR_FCSR_ADDRESS as usize] >> 5) & 0x7,
CSR_SSTATUS_ADDRESS => self.csr[CSR_MSTATUS_ADDRESS as usize] & 0x80000003000de162,
CSR_SIE_ADDRESS => self.csr[CSR_MIE_ADDRESS as usize] & 0x222,
CSR_SIP_ADDRESS => self.csr[CSR_MIP_ADDRESS as usize] & 0x222,
CSR_TIME_ADDRESS => self.mmu.get_clint().read_mtime(),
_ => self.csr[address as usize]
}
}
fn write_csr_raw(&mut self, address: u16, value: u64) {
match address {
CSR_FFLAGS_ADDRESS => {
self.csr[CSR_FCSR_ADDRESS as usize] &= !0x1f;
self.csr[CSR_FCSR_ADDRESS as usize] |= value & 0x1f;
},
CSR_FRM_ADDRESS => {
self.csr[CSR_FCSR_ADDRESS as usize] &= !0xe0;
self.csr[CSR_FCSR_ADDRESS as usize] |= (value << 5) & 0xe0;
},
CSR_SSTATUS_ADDRESS => {
self.csr[CSR_MSTATUS_ADDRESS as usize] &= !0x80000003000de162;
self.csr[CSR_MSTATUS_ADDRESS as usize] |= value & 0x80000003000de162;
},
CSR_SIE_ADDRESS => {
self.csr[CSR_MIE_ADDRESS as usize] &= !0x222;
self.csr[CSR_MIE_ADDRESS as usize] |= value & 0x222;
},
CSR_SIP_ADDRESS => {
self.csr[CSR_MIP_ADDRESS as usize] &= !0x222;
self.csr[CSR_MIP_ADDRESS as usize] |= value & 0x222;
},
CSR_MIDELEG_ADDRESS => {
self.csr[address as usize] = value & 0x666; },
CSR_TIME_ADDRESS => {
self.mmu.get_mut_clint().write_mtime(value);
},
_ => {
self.csr[address as usize] = value;
}
};
}
fn _set_fcsr_nv(&mut self) {
self.csr[CSR_FCSR_ADDRESS as usize] |= 0x10;
}
fn set_fcsr_dz(&mut self) {
self.csr[CSR_FCSR_ADDRESS as usize] |= 0x8;
}
fn _set_fcsr_of(&mut self) {
self.csr[CSR_FCSR_ADDRESS as usize] |= 0x4;
}
fn _set_fcsr_uf(&mut self) {
self.csr[CSR_FCSR_ADDRESS as usize] |= 0x2;
}
fn _set_fcsr_nx(&mut self) {
self.csr[CSR_FCSR_ADDRESS as usize] |= 0x1;
}
fn update_addressing_mode(&mut self, value: u64) {
let addressing_mode = match self.xlen {
Xlen::Bit32 => match value & 0x80000000 {
0 => AddressingMode::None,
_ => AddressingMode::SV32
},
Xlen::Bit64 => match value >> 60 {
0 => AddressingMode::None,
8 => AddressingMode::SV39,
9 => AddressingMode::SV48,
_ => {
println!("Unknown addressing_mode {:x}", value >> 60);
panic!();
}
}
};
let ppn = match self.xlen {
Xlen::Bit32 => value & 0x3fffff,
Xlen::Bit64 => value & 0xfffffffffff
};
self.mmu.update_addressing_mode(addressing_mode);
self.mmu.update_ppn(ppn);
}
fn sign_extend(&self, value: i64) -> i64 {
match self.xlen {
Xlen::Bit32 => (match value & 0x80000000 {
0x80000000 => (value as u64) | 0xffffffff00000000,
_ => (value as u64) & 0xffffffff
}) as i64,
Xlen::Bit64 => value
}
}
fn unsigned_data(&self, value: i64) -> u64 {
match self.xlen {
Xlen::Bit32 => (value as u64) & 0xffffffff,
Xlen::Bit64 => value as u64
}
}
fn most_negative(&self) -> i64 {
match self.xlen {
Xlen::Bit32 => std::i32::MIN as i64,
Xlen::Bit64 => std::i64::MIN
}
}
fn uncompress(&self, halfword: u32) -> u32 {
let op = halfword & 0x3; let funct3 = (halfword >> 13) & 0x7;
match op {
0 => match funct3 {
0 => {
let rd = (halfword >> 2) & 0x7; let nzuimm =
((halfword >> 7) & 0x30) | ((halfword >> 1) & 0x3c0) | ((halfword >> 4) & 0x4) | ((halfword >> 2) & 0x8); if nzuimm != 0 {
return (nzuimm << 20) | (2 << 15) | ((rd + 8) << 7) | 0x13;
}
},
1 => {
let rd = (halfword >> 2) & 0x7; let rs1 = (halfword >> 7) & 0x7; let offset =
((halfword >> 7) & 0x38) | ((halfword << 1) & 0xc0); return (offset << 20) | ((rs1 + 8) << 15) | (3 << 12) | ((rd + 8) << 7) | 0x7;
},
2 => {
let rs1 = (halfword >> 7) & 0x7; let rd = (halfword >> 2) & 0x7; let offset =
((halfword >> 7) & 0x38) | ((halfword >> 4) & 0x4) | ((halfword << 1) & 0x40); return (offset << 20) | ((rs1 + 8) << 15) | (2 << 12) | ((rd + 8) << 7) | 0x3;
},
3 => {
let rs1 = (halfword >> 7) & 0x7; let rd = (halfword >> 2) & 0x7; let offset =
((halfword >> 7) & 0x38) | ((halfword << 1) & 0xc0); return (offset << 20) | ((rs1 + 8) << 15) | (3 << 12) | ((rd + 8) << 7) | 0x3;
},
4 => {
},
5 => {
let rs1 = (halfword >> 7) & 0x7; let rs2 = (halfword >> 2) & 0x7; let offset =
((halfword >> 7) & 0x38) | ((halfword << 1) & 0xc0); let imm11_5 = (offset >> 5) & 0x7f;
let imm4_0 = offset & 0x1f;
return (imm11_5 << 25) | ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | (3 << 12) | (imm4_0 << 7) | 0x27;
},
6 => {
let rs1 = (halfword >> 7) & 0x7; let rs2 = (halfword >> 2) & 0x7; let offset =
((halfword >> 7) & 0x38) | ((halfword << 1) & 0x40) | ((halfword >> 4) & 0x4); let imm11_5 = (offset >> 5) & 0x7f;
let imm4_0 = offset & 0x1f;
return (imm11_5 << 25) | ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | (2 << 12) | (imm4_0 << 7) | 0x23;
},
7 => {
let rs1 = (halfword >> 7) & 0x7; let rs2 = (halfword >> 2) & 0x7; let offset =
((halfword >> 7) & 0x38) | ((halfword << 1) & 0xc0); let imm11_5 = (offset >> 5) & 0x7f;
let imm4_0 = offset & 0x1f;
return (imm11_5 << 25) | ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | (3 << 12) | (imm4_0 << 7) | 0x23;
},
_ => {} },
1 => {
match funct3 {
0 => {
let r = (halfword >> 7) & 0x1f; let imm = match halfword & 0x1000 {
0x1000 => 0xffffffc0,
_ => 0
} | ((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1f); if r == 0 && imm == 0 {
return 0x13;
} else if r != 0 {
return (imm << 20) | (r << 15) | (r << 7) | 0x13;
}
},
1 => {
let r = (halfword >> 7) & 0x1f;
let imm = match halfword & 0x1000 {
0x1000 => 0xffffffc0,
_ => 0
} | ((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1f); if r != 0 {
return (imm << 20) | (r << 15) | (r << 7) | 0x1b;
}
},
2 => {
let r = (halfword >> 7) & 0x1f;
let imm = match halfword & 0x1000 {
0x1000 => 0xffffffc0,
_ => 0
} | ((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1f); if r != 0 {
return (imm << 20) | (r << 7) | 0x13;
}
},
3 => {
let r = (halfword >> 7) & 0x1f; if r == 2 {
let imm = match halfword & 0x1000 {
0x1000 => 0xfffffc00,
_ => 0
} | ((halfword >> 3) & 0x200) | ((halfword >> 2) & 0x10) | ((halfword << 1) & 0x40) | ((halfword << 4) & 0x180) | ((halfword << 3) & 0x20); if imm != 0 {
return (imm << 20) | (r << 15) | (r << 7) | 0x13;
}
}
if r != 0 && r != 2 {
let nzimm = match halfword & 0x1000 {
0x1000 => 0xfffc0000,
_ => 0
} | ((halfword << 5) & 0x20000) | ((halfword << 10) & 0x1f000); if nzimm != 0 {
return nzimm | (r << 7) | 0x37;
}
}
},
4 => {
let funct2 = (halfword >> 10) & 0x3; match funct2 {
0 => {
let shamt =
((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1f); let rs1 = (halfword >> 7) & 0x7; return (shamt << 20) | ((rs1 + 8) << 15) | (5 << 12) | ((rs1 + 8) << 7) | 0x13;
},
1 => {
let shamt =
((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1f); let rs1 = (halfword >> 7) & 0x7; return (0x20 << 25) | (shamt << 20) | ((rs1 + 8) << 15) | (5 << 12) | ((rs1 + 8) << 7) | 0x13;
},
2 => {
let r = (halfword >> 7) & 0x7; let imm = match halfword & 0x1000 {
0x1000 => 0xffffffc0,
_ => 0
} | ((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1f); return (imm << 20) | ((r + 8) << 15) | (7 << 12) | ((r + 8) << 7) | 0x13;
},
3 => {
let funct1 = (halfword >> 12) & 1; let funct2_2 = (halfword >> 5) & 0x3; let rs1 = (halfword >> 7) & 0x7;
let rs2 = (halfword >> 2) & 0x7;
match funct1 {
0 => match funct2_2 {
0 => {
return (0x20 << 25) | ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | ((rs1 + 8) << 7) | 0x33;
},
1 => {
return ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | (4 << 12) | ((rs1 + 8) << 7) | 0x33;
},
2 => {
return ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | (6 << 12) | ((rs1 + 8) << 7) | 0x33;
},
3 => {
return ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | (7 << 12) | ((rs1 + 8) << 7) | 0x33;
},
_ => {} },
1 => match funct2_2 {
0 => {
return (0x20 << 25) | ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | ((rs1 + 8) << 7) | 0x3b;
},
1 => {
return ((rs2 + 8) << 20) | ((rs1 + 8) << 15) | ((rs1 + 8) << 7) | 0x3b;
},
2 => {
},
3 => {
},
_ => {} },
_ => {} };
},
_ => {} };
},
5 => {
let offset =
match halfword & 0x1000 {
0x1000 => 0xfffff000,
_ => 0
} | ((halfword >> 1) & 0x800) | ((halfword >> 7) & 0x10) | ((halfword >> 1) & 0x300) | ((halfword << 2) & 0x400) | ((halfword >> 1) & 0x40) | ((halfword << 1) & 0x80) | ((halfword >> 2) & 0xe) | ((halfword << 3) & 0x20); let imm =
((offset >> 1) & 0x80000) | ((offset << 8) & 0x7fe00) | ((offset >> 3) & 0x100) | ((offset >> 12) & 0xff); return (imm << 12) | 0x6f;
},
6 => {
let r = (halfword >> 7) & 0x7;
let offset =
match halfword & 0x1000 {
0x1000 => 0xfffffe00,
_ => 0
} | ((halfword >> 4) & 0x100) | ((halfword >> 7) & 0x18) | ((halfword << 1) & 0xc0) | ((halfword >> 2) & 0x6) | ((halfword << 3) & 0x20); let imm2 =
((offset >> 6) & 0x40) | ((offset >> 5) & 0x3f); let imm1 =
(offset & 0x1e) | ((offset >> 11) & 0x1); return (imm2 << 25) | ((r + 8) << 20) | (imm1 << 7) | 0x63;
},
7 => {
let r = (halfword >> 7) & 0x7;
let offset =
match halfword & 0x1000 {
0x1000 => 0xfffffe00,
_ => 0
} | ((halfword >> 4) & 0x100) | ((halfword >> 7) & 0x18) | ((halfword << 1) & 0xc0) | ((halfword >> 2) & 0x6) | ((halfword << 3) & 0x20); let imm2 =
((offset >> 6) & 0x40) | ((offset >> 5) & 0x3f); let imm1 =
(offset & 0x1e) | ((offset >> 11) & 0x1); return (imm2 << 25) | ((r + 8) << 20) | (1 << 12) | (imm1 << 7) | 0x63;
},
_ => {} };
},
2 => {
match funct3 {
0 => {
let r = (halfword >> 7) & 0x1f;
let shamt =
((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1f); if r != 0 {
return (shamt << 20) | (r << 15) | (1 << 12) | (r << 7) | 0x13;
}
},
1 => {
let rd = (halfword >> 7) & 0x1f;
let offset =
((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x18) | ((halfword << 4) & 0x1c0); if rd != 0 {
return (offset << 20) | (2 << 15) | (3 << 12) | (rd << 7) | 0x7;
}
},
2 => {
let r = (halfword >> 7) & 0x1f;
let offset =
((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x1c) | ((halfword << 4) & 0xc0); if r != 0 {
return (offset << 20) | (2 << 15) | (2 << 12) | (r << 7) | 0x3;
}
},
3 => {
let rd = (halfword >> 7) & 0x1f;
let offset =
((halfword >> 7) & 0x20) | ((halfword >> 2) & 0x18) | ((halfword << 4) & 0x1c0); if rd != 0 {
return (offset << 20) | (2 << 15) | (3 << 12) | (rd << 7) | 0x3;
}
},
4 => {
let funct1 = (halfword >> 12) & 1; let rs1 = (halfword >> 7) & 0x1f; let rs2 = (halfword >> 2) & 0x1f; match funct1 {
0 => {
if rs1 != 0 && rs2 == 0 {
return (rs1 << 15) | 0x67;
}
if rs1 != 0 && rs2 != 0 {
return (rs2 << 20) | (rs1 << 7) | 0x33;
}
},
1 => {
if rs1 == 0 && rs2 == 0 {
return 0x00100073;
}
if rs1 != 0 && rs2 == 0 {
return (rs1 << 15) | (1 << 7) | 0x67;
}
if rs1 != 0 && rs2 != 0 {
return (rs2 << 20) | (rs1 << 15) | (rs1 << 7) | 0x33;
}
},
_ => {} };
},
5 => {
let rs2 = (halfword >> 2) & 0x1f; let offset =
((halfword >> 7) & 0x38) | ((halfword >> 1) & 0x1c0); let imm11_5 = (offset >> 5) & 0x3f;
let imm4_0 = offset & 0x1f;
return (imm11_5 << 25) | (rs2 << 20) | (2 << 15) | (3 << 12) | (imm4_0 << 7) | 0x27;
},
6 => {
let rs2 = (halfword >> 2) & 0x1f; let offset =
((halfword >> 7) & 0x3c) | ((halfword >> 1) & 0xc0); let imm11_5 = (offset >> 5) & 0x3f;
let imm4_0 = offset & 0x1f;
return (imm11_5 << 25) | (rs2 << 20) | (2 << 15) | (2 << 12) | (imm4_0 << 7) | 0x23;
},
7 => {
let rs2 = (halfword >> 2) & 0x1f; let offset =
((halfword >> 7) & 0x38) | ((halfword >> 1) & 0x1c0); let imm11_5 = (offset >> 5) & 0x3f;
let imm4_0 = offset & 0x1f;
return (imm11_5 << 25) | (rs2 << 20) | (2 << 15) | (3 << 12) | (imm4_0 << 7) | 0x23;
},
_ => {} };
},
_ => {} };
0xffffffff }
pub fn disassemble_next_instruction(&mut self) -> String {
let mut original_word = match self.mmu.fetch_word(self.pc) {
Ok(data) => data,
Err(_e) => {
return format!("PC:{:016x}, InstructionPageFault Trap!\n", self.pc);
}
};
let word = match (original_word & 0x3) == 0x3 {
true => original_word,
false => {
original_word &= 0xffff;
self.uncompress(original_word)
}
};
let inst = {match self.decode_raw(word) {
Ok(inst) => inst,
Err(()) => {
return format!("Unknown instruction PC:{:x} WORD:{:x}", self.pc, original_word);
}
}};
let mut s = format!("PC:{:016x} ", self.unsigned_data(self.pc as i64));
s += &format!("{:08x} ", original_word);
s += &format!("{} ", inst.name);
s += &format!("{}", (inst.disassemble)(self, word, self.pc, true));
s
}
pub fn get_mut_mmu(&mut self) -> &mut Mmu {
&mut self.mmu
}
pub fn get_mut_terminal(&mut self) -> &mut Box<dyn Terminal> {
self.mmu.get_mut_uart().get_mut_terminal()
}
}
struct Instruction {
mask: u32,
data: u32, name: &'static str,
operation: fn(cpu: &mut Cpu, word: u32, address: u64) -> Result<(), Trap>,
disassemble: fn(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String
}
struct FormatB {
rs1: usize,
rs2: usize,
imm: u64
}
fn parse_format_b(word: u32) -> FormatB {
FormatB {
rs1: ((word >> 15) & 0x1f) as usize, rs2: ((word >> 20) & 0x1f) as usize, imm: (
match word & 0x80000000 { 0x80000000 => 0xfffff000,
_ => 0
} |
((word << 4) & 0x00000800) | ((word >> 20) & 0x000007e0) | ((word >> 7) & 0x0000001e) ) as i32 as i64 as u64
}
}
fn dump_format_b(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String {
let f = parse_format_b(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(",{}", get_register_name(f.rs2));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs2]);
}
s += &format!(",{:x}", address.wrapping_add(f.imm));
s
}
struct FormatCSR {
csr: u16,
rs: usize,
rd: usize
}
fn parse_format_csr(word: u32) -> FormatCSR {
FormatCSR {
csr: ((word >> 20) & 0xfff) as u16, rs: ((word >> 15) & 0x1f) as usize, rd: ((word >> 7) & 0x1f) as usize }
}
fn dump_format_csr(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_csr(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{:x}", f.csr);
if evaluate {
s += &format!(":{:x}", cpu.read_csr_raw(f.csr));
}
s += &format!(",{}", get_register_name(f.rs));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs]);
}
s
}
struct FormatI {
rd: usize,
rs1: usize,
imm: i64
}
fn parse_format_i(word: u32) -> FormatI {
FormatI {
rd: ((word >> 7) & 0x1f) as usize, rs1: ((word >> 15) & 0x1f) as usize, imm: (
match word & 0x80000000 { 0x80000000 => 0xfffff800,
_ => 0
} |
((word >> 20) & 0x000007ff) ) as i32 as i64
}
}
fn dump_format_i(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_i(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{}", get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(",{:x}", f.imm);
s
}
fn dump_format_i_mem(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_i(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{:x}({}", f.imm, get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(")");
s
}
struct FormatJ {
rd: usize,
imm: u64
}
fn parse_format_j(word: u32) -> FormatJ {
FormatJ {
rd: ((word >> 7) & 0x1f) as usize, imm: (
match word & 0x80000000 { 0x80000000 => 0xfff00000,
_ => 0
} |
(word & 0x000ff000) | ((word & 0x00100000) >> 9) | ((word & 0x7fe00000) >> 20) ) as i32 as i64 as u64
}
}
fn dump_format_j(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String {
let f = parse_format_j(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{:x}", address.wrapping_add(f.imm));
s
}
struct FormatR {
rd: usize,
rs1: usize,
rs2: usize
}
fn parse_format_r(word: u32) -> FormatR {
FormatR {
rd: ((word >> 7) & 0x1f) as usize, rs1: ((word >> 15) & 0x1f) as usize, rs2: ((word >> 20) & 0x1f) as usize }
}
fn dump_format_r(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_r(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{}", get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(",{}", get_register_name(f.rs2));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs2]);
}
s
}
struct FormatR2 {
rd: usize,
rs1: usize,
rs2: usize,
rs3: usize
}
fn parse_format_r2(word: u32) -> FormatR2 {
FormatR2 {
rd: ((word >> 7) & 0x1f) as usize, rs1: ((word >> 15) & 0x1f) as usize, rs2: ((word >> 20) & 0x1f) as usize, rs3: ((word >> 27) & 0x1f) as usize }
}
fn dump_format_r2(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_r2(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{}", get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(",{}", get_register_name(f.rs2));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs2]);
}
s += &format!(",{}", get_register_name(f.rs3));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs3]);
}
s
}
struct FormatS {
rs1: usize,
rs2: usize,
imm: i64
}
fn parse_format_s(word: u32) -> FormatS {
FormatS {
rs1: ((word >> 15) & 0x1f) as usize, rs2: ((word >> 20) & 0x1f) as usize, imm: (
match word & 0x80000000 {
0x80000000 => 0xfffff000,
_ => 0
} | ((word >> 20) & 0xfe0) | ((word >> 7) & 0x1f) ) as i32 as i64
}
}
fn dump_format_s(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_s(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rs2));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs2]);
}
s += &format!(",{:x}({}", f.imm, get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(")");
s
}
struct FormatU {
rd: usize,
imm: u64
}
fn parse_format_u(word: u32) -> FormatU {
FormatU {
rd: ((word >> 7) & 0x1f) as usize, imm: (
match word & 0x80000000 {
0x80000000 => 0xffffffff00000000,
_ => 0
} | ((word as u64) & 0xfffff000) ) as u64
}
}
fn dump_format_u(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_u(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{:x}", f.imm);
s
}
fn dump_empty(_cpu: &mut Cpu, _word: u32, _address: u64, _evaluate: bool) -> String {
String::new()
}
fn get_register_name(num: usize) -> &'static str {
match num {
0 => "zero",
1 => "ra",
2 => "sp",
3 => "gp",
4 => "tp",
5 => "t0",
6 => "t1",
7 => "t2",
8 => "s0",
9 => "s1",
10 => "a0",
11 => "a1",
12 => "a2",
13 => "a3",
14 => "a4",
15 => "a5",
16 => "a6",
17 => "a7",
18 => "s2",
19 => "s3",
20 => "s4",
21 => "s5",
22 => "s6",
23 => "s7",
24 => "s8",
25 => "s9",
26 => "s10",
27 => "s11",
28 => "t3",
29 => "t4",
30 => "t5",
31 => "t6",
_ => panic!("Unknown register num {}", num)
}
}
const INSTRUCTION_NUM: usize = 116;
const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
Instruction {
mask: 0xfe00707f,
data: 0x00000033,
name: "ADD",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_add(cpu.x[f.rs2]));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00000013,
name: "ADDI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_add(f.imm));
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0x0000707f,
data: 0x0000001b,
name: "ADDIW",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.x[f.rs1].wrapping_add(f.imm) as i32 as i64;
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0x0000003b,
name: "ADDW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.x[f.rs1].wrapping_add(cpu.x[f.rs2]) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0000302f,
name: "AMOADD.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, cpu.x[f.rs2].wrapping_add(tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0000202f,
name: "AMOADD.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, cpu.x[f.rs2].wrapping_add(tmp) as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x6000302f,
name: "AMOAND.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] & tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x6000202f,
name: "AMOAND.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] & tmp) as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0xe000302f,
name: "AMOMAXU.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data,
Err(e) => return Err(e)
};
let max = match cpu.x[f.rs2] as u64 >= tmp {
true => cpu.x[f.rs2] as u64,
false => tmp
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, max) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0xe000202f,
name: "AMOMAXU.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data,
Err(e) => return Err(e)
};
let max = match cpu.x[f.rs2] as u32 >= tmp {
true => cpu.x[f.rs2] as u32,
false => tmp
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, max) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x4000302f,
name: "AMOOR.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] | tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x4000202f,
name: "AMOOR.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, (cpu.x[f.rs2] | tmp) as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0800302f,
name: "AMOSWAP.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x0800202f,
name: "AMOSWAP.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let tmp = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
match cpu.mmu.store_word(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u32) {
Ok(()) => {},
Err(e) => return Err(e)
};
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x00007033,
name: "AND",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] & cpu.x[f.rs2]);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00007013,
name: "ANDI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] & f.imm);
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0x0000007f,
data: 0x00000017,
name: "AUIPC",
operation: |cpu, word, address| {
let f = parse_format_u(word);
cpu.x[f.rd] = cpu.sign_extend(address.wrapping_add(f.imm) as i64);
Ok(())
},
disassemble: dump_format_u
},
Instruction {
mask: 0x0000707f,
data: 0x00000063,
name: "BEQ",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) == cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00005063,
name: "BGE",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) >= cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00007063,
name: "BGEU",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.unsigned_data(cpu.x[f.rs1]) >= cpu.unsigned_data(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00004063,
name: "BLT",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) < cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00006063,
name: "BLTU",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.unsigned_data(cpu.x[f.rs1]) < cpu.unsigned_data(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00001063,
name: "BNE",
operation: |cpu, word, address| {
let f = parse_format_b(word);
if cpu.sign_extend(cpu.x[f.rs1]) != cpu.sign_extend(cpu.x[f.rs2]) {
cpu.pc = address.wrapping_add(f.imm);
}
Ok(())
},
disassemble: dump_format_b
},
Instruction {
mask: 0x0000707f,
data: 0x00003073,
name: "CSRRC",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
let tmp = cpu.x[f.rs];
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, (cpu.x[f.rd] & !tmp) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00007073,
name: "CSRRCI",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, (cpu.x[f.rd] & !(f.rs as i64)) as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00002073,
name: "CSRRS",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
let tmp = cpu.x[f.rs];
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, cpu.unsigned_data(cpu.x[f.rd] | tmp)) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00006073,
name: "CSRRSI",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, cpu.unsigned_data(cpu.x[f.rd] | (f.rs as i64))) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00001073,
name: "CSRRW",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
let tmp = cpu.x[f.rs];
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, cpu.unsigned_data(tmp)) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0x0000707f,
data: 0x00005073,
name: "CSRRWI",
operation: |cpu, word, _address| {
let f = parse_format_csr(word);
let data = match cpu.read_csr(f.csr) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
cpu.x[f.rd] = cpu.sign_extend(data);
match cpu.write_csr(f.csr, f.rs as u64) {
Ok(()) => {},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_csr
},
Instruction {
mask: 0xfe00707f,
data: 0x02004033,
name: "DIV",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1];
let divisor = cpu.x[f.rs2];
if divisor == 0 {
cpu.x[f.rd] = -1;
} else if dividend == cpu.most_negative() && divisor == -1 {
cpu.x[f.rd] = dividend;
} else {
cpu.x[f.rd] = cpu.sign_extend(dividend.wrapping_div(divisor))
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02005033,
name: "DIVU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.unsigned_data(cpu.x[f.rs1]);
let divisor = cpu.unsigned_data(cpu.x[f.rs2]);
if divisor == 0 {
cpu.x[f.rd] = -1;
} else {
cpu.x[f.rd] = cpu.sign_extend(dividend.wrapping_div(divisor) as i64)
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200503b,
name: "DIVUW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.unsigned_data(cpu.x[f.rs1]) as u32;
let divisor = cpu.unsigned_data(cpu.x[f.rs2]) as u32;
if divisor == 0 {
cpu.x[f.rd] = -1;
} else {
cpu.x[f.rd] = dividend.wrapping_div(divisor) as i32 as i64
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200403b,
name: "DIVW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1] as i32;
let divisor = cpu.x[f.rs2] as i32;
if divisor == 0 {
cpu.x[f.rd] = -1;
} else if dividend == std::i32::MIN && divisor == -1 {
cpu.x[f.rd] = dividend as i32 as i64;
} else {
cpu.x[f.rd] = dividend.wrapping_div(divisor) as i32 as i64
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xffffffff,
data: 0x00100073,
name: "EBREAK",
operation: |_cpu, _word, _address| {
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xffffffff,
data: 0x00000073,
name: "ECALL",
operation: |cpu, _word, address| {
let exception_type = match cpu.privilege_mode {
PrivilegeMode::User => TrapType::EnvironmentCallFromUMode,
PrivilegeMode::Supervisor => TrapType::EnvironmentCallFromSMode,
PrivilegeMode::Machine => TrapType::EnvironmentCallFromMMode,
PrivilegeMode::Reserved => panic!("Unknown Privilege mode")
};
return Err(Trap {
trap_type: exception_type,
value: address
});
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00007f,
data: 0x02000053,
name: "FADD.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.f[f.rs1] + cpu.f[f.rs2];
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xd2200053,
name: "FCVT.D.L",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.x[f.rs1] as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0x42000053,
name: "FCVT.D.S",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = f32::from_bits(cpu.f[f.rs1].to_bits() as u32) as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xd2000053,
name: "FCVT.D.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.x[f.rs1] as i32 as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xd2100053,
name: "FCVT.D.WU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.x[f.rs1] as u32 as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0x40100053,
name: "FCVT.S.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.f[f.rs1] as f32 as f64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0007f,
data: 0xc2000053,
name: "FCVT.W.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.f[f.rs1] as u32 as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00007f,
data: 0x1a000053,
name: "FDIV.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.f[f.rs1];
let divisor = cpu.f[f.rs2];
if divisor == 0.0 {
cpu.f[f.rd] = std::f64::INFINITY;
cpu.set_fcsr_dz();
} else if divisor == -0.0 {
cpu.f[f.rd] = std::f64::NEG_INFINITY;
cpu.set_fcsr_dz();
} else {
cpu.f[f.rd] = dividend / divisor;
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x0000000f,
name: "FENCE",
operation: |_cpu, _word, _address| {
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0x0000707f,
data: 0x0000100f,
name: "FENCE.I",
operation: |_cpu, _word, _address| {
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0xa2002053,
name: "FEQ.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.f[f.rs1] == cpu.f[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0x0000707f,
data: 0x00003007,
name: "FLD",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.f[f.rd] = match cpu.mmu.load_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => f64::from_bits(data),
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0xa2000053,
name: "FLE.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.f[f.rs1] <= cpu.f[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0xa2001053,
name: "FLT.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.f[f.rs1] < cpu.f[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002007,
name: "FLW",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.f[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => f64::from_bits(data as i32 as i64 as u64),
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0600007f,
data: 0x02000043,
name: "FMADD.D",
operation: |cpu, word, _address| {
let f = parse_format_r2(word);
cpu.f[f.rd] = cpu.f[f.rs1] * cpu.f[f.rs2] + cpu.f[f.rs3];
Ok(())
},
disassemble: dump_format_r2
},
Instruction {
mask: 0xfe00007f,
data: 0x12000053,
name: "FMUL.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.f[f.rs1] * cpu.f[f.rs2];
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xf2000053,
name: "FMV.D.X",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = f64::from_bits(cpu.x[f.rs1] as u64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xe2000053,
name: "FMV.X.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.f[f.rs1].to_bits() as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xe0000053,
name: "FMV.X.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.f[f.rs1].to_bits() as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfff0707f,
data: 0xf0000053,
name: "FMV.W.X",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = f64::from_bits(cpu.x[f.rs1] as u32 as u64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0600007f,
data: 0x0200004b,
name: "FNMSUB.D",
operation: |cpu, word, _address| {
let f = parse_format_r2(word);
cpu.f[f.rd] = -(cpu.f[f.rs1] * cpu.f[f.rs2]) + cpu.f[f.rs3];
Ok(())
},
disassemble: dump_format_r2
},
Instruction {
mask: 0x0000707f,
data: 0x00003027,
name: "FSD",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.f[f.rs2].to_bits())
},
disassemble: dump_format_s
},
Instruction {
mask: 0xfe00707f,
data: 0x22000053,
name: "FSGNJ.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let rs1_bits = cpu.f[f.rs1].to_bits();
let rs2_bits = cpu.f[f.rs2].to_bits();
let sign_bit = rs2_bits & 0x8000000000000000;
cpu.f[f.rd] = f64::from_bits(sign_bit | (rs1_bits & 0x7fffffffffffffff));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x22002053,
name: "FSGNJX.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let rs1_bits = cpu.f[f.rs1].to_bits();
let rs2_bits = cpu.f[f.rs2].to_bits();
let sign_bit = (rs1_bits ^ rs2_bits) & 0x8000000000000000;
cpu.f[f.rd] = f64::from_bits(sign_bit | (rs1_bits & 0x7fffffffffffffff));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00007f,
data: 0x0a000053,
name: "FSUB.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.f[f.rd] = cpu.f[f.rs1] - cpu.f[f.rs2];
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002027,
name: "FSW",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.f[f.rs2].to_bits() as u32)
},
disassemble: dump_format_s
},
Instruction {
mask: 0x0000007f,
data: 0x0000006f,
name: "JAL",
operation: |cpu, word, address| {
let f = parse_format_j(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.pc as i64);
cpu.pc = address.wrapping_add(f.imm);
Ok(())
},
disassemble: dump_format_j
},
Instruction {
mask: 0x0000707f,
data: 0x00000067,
name: "JALR",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
let tmp = cpu.sign_extend(cpu.pc as i64);
cpu.pc = (cpu.x[f.rs1] as u64).wrapping_add(f.imm as u64);
cpu.x[f.rd] = tmp;
Ok(())
},
disassemble: |cpu, word, _address, evaluate| {
let f = parse_format_i(word);
let mut s = String::new();
s += &format!("{}", get_register_name(f.rd));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rd]);
}
s += &format!(",{:x}({}", f.imm, get_register_name(f.rs1));
if evaluate {
s += &format!(":{:x}", cpu.x[f.rs1]);
}
s += &format!(")");
s
}
},
Instruction {
mask: 0x0000707f,
data: 0x00000003,
name: "LB",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i8 as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00004003,
name: "LBU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00003003,
name: "LD",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00001003,
name: "LH",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_halfword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i16 as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00005003,
name: "LHU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_halfword(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0xf9f0707f,
data: 0x1000302f,
name: "LR.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.mmu.load_doubleword(cpu.x[f.rs1] as u64) {
Ok(data) => {
cpu.is_reservation_set = true;
cpu.reservation = cpu.x[f.rs1] as u64; data as i64
},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf9f0707f,
data: 0x1000202f,
name: "LR.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1] as u64) {
Ok(data) => {
cpu.is_reservation_set = true;
cpu.reservation = cpu.x[f.rs1] as u64; data as i32 as i64
},
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000007f,
data: 0x00000037,
name: "LUI",
operation: |cpu, word, _address| {
let f = parse_format_u(word);
cpu.x[f.rd] = f.imm as i64;
Ok(())
},
disassemble: dump_format_u
},
Instruction {
mask: 0x0000707f,
data: 0x00002003,
name: "LW",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i32 as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0x0000707f,
data: 0x00006003,
name: "LWU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.mmu.load_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64) {
Ok(data) => data as i64,
Err(e) => return Err(e)
};
Ok(())
},
disassemble: dump_format_i_mem
},
Instruction {
mask: 0xfe00707f,
data: 0x02000033,
name: "MUL",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_mul(cpu.x[f.rs2]));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02001033,
name: "MULH",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.xlen {
Xlen::Bit32 => {
cpu.sign_extend((cpu.x[f.rs1] * cpu.x[f.rs2]) >> 32)
},
Xlen::Bit64 => {
((cpu.x[f.rs1] as i128) * (cpu.x[f.rs2] as i128) >> 64) as i64
}
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02003033,
name: "MULHU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.xlen {
Xlen::Bit32 => {
cpu.sign_extend((((cpu.x[f.rs1] as u32 as u64) * (cpu.x[f.rs2] as u32 as u64)) >> 32) as i64)
},
Xlen::Bit64 => {
((cpu.x[f.rs1] as u64 as u128).wrapping_mul(cpu.x[f.rs2] as u64 as u128) >> 64) as i64
}
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02002033,
name: "MULHSU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.xlen {
Xlen::Bit32 => {
cpu.sign_extend(((cpu.x[f.rs1] as i64).wrapping_mul(cpu.x[f.rs2] as u32 as i64) >> 32) as i64)
},
Xlen::Bit64 => {
((cpu.x[f.rs1] as u128).wrapping_mul(cpu.x[f.rs2] as u64 as u128) >> 64) as i64
}
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200003b,
name: "MULW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend((cpu.x[f.rs1] as i32).wrapping_mul(cpu.x[f.rs2] as i32) as i64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xffffffff,
data: 0x30200073,
name: "MRET",
operation: |cpu, _word, _address| {
cpu.pc = match cpu.read_csr(CSR_MEPC_ADDRESS) {
Ok(data) => data,
Err(e) => return Err(e)
};
let status = cpu.read_csr_raw(CSR_MSTATUS_ADDRESS);
let mpie = (status >> 7) & 1;
let mpp = (status >> 11) & 0x3;
let new_status = (status & !0x1888) | (mpie << 3) | (1 << 7);
cpu.write_csr_raw(CSR_MSTATUS_ADDRESS, new_status);
cpu.privilege_mode = match mpp {
0 => PrivilegeMode::User,
1 => PrivilegeMode::Supervisor,
3 => PrivilegeMode::Machine,
_ => panic!() };
cpu.mmu.update_privilege_mode(cpu.privilege_mode.clone());
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0x00006033,
name: "OR",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] | cpu.x[f.rs2]);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00006013,
name: "ORI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] | f.imm);
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0x02006033,
name: "REM",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1];
let divisor = cpu.x[f.rs2];
if divisor == 0 {
cpu.x[f.rd] = dividend;
} else if dividend == cpu.most_negative() && divisor == -1 {
cpu.x[f.rd] = 0;
} else {
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_rem(cpu.x[f.rs2]));
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x02007033,
name: "REMU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.unsigned_data(cpu.x[f.rs1]);
let divisor = cpu.unsigned_data(cpu.x[f.rs2]);
cpu.x[f.rd] = match divisor {
0 => cpu.sign_extend(dividend as i64),
_ => cpu.sign_extend(dividend.wrapping_rem(divisor) as i64)
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200703b,
name: "REMUW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1] as u32;
let divisor = cpu.x[f.rs2] as u32;
cpu.x[f.rd] = match divisor {
0 => dividend as i32 as i64,
_ => dividend.wrapping_rem(divisor) as i32 as i64
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0200603b,
name: "REMW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let dividend = cpu.x[f.rs1] as i32;
let divisor = cpu.x[f.rs2] as i32;
if divisor == 0 {
cpu.x[f.rd] = dividend as i64;
} else if dividend == std::i32::MIN && divisor == -1 {
cpu.x[f.rd] = 0;
} else {
cpu.x[f.rd] = dividend.wrapping_rem(divisor) as i64;
}
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00000023,
name: "SB",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u8)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xf800707f,
data: 0x1800302f,
name: "SC.D",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.is_reservation_set && cpu.reservation == (cpu.x[f.rs1] as u64) {
true => match cpu.mmu.store_doubleword(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u64) {
Ok(()) => {
cpu.is_reservation_set = false;
0
},
Err(e) => return Err(e)
},
false => 1
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xf800707f,
data: 0x1800202f,
name: "SC.W",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.is_reservation_set && cpu.reservation == (cpu.x[f.rs1] as u64) {
true => match cpu.mmu.store_word(cpu.x[f.rs1] as u64, cpu.x[f.rs2] as u32) {
Ok(()) => {
cpu.is_reservation_set = false;
0
},
Err(e) => return Err(e)
},
false => 1
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00003023,
name: "SD",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_doubleword(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u64)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xfe007fff,
data: 0x12000073,
name: "SFENCE.VMA",
operation: |_cpu, _word, _address| {
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0x0000707f,
data: 0x00001023,
name: "SH",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_halfword(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u16)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xfe00707f,
data: 0x00001033,
name: "SLL",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_shl(cpu.x[f.rs2] as u32));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x00001013,
name: "SLLI",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] << shamt);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0000101b,
name: "SLLIW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let shamt = f.rs2 as u32;
cpu.x[f.rd] = (cpu.x[f.rs1] << shamt) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0000103b,
name: "SLLW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = (cpu.x[f.rs1] as u32).wrapping_shl(cpu.x[f.rs2] as u32) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x00002033,
name: "SLT",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.x[f.rs1] < cpu.x[f.rs2] {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002013,
name: "SLTI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.x[f.rs1] < f.imm {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0x0000707f,
data: 0x00003013,
name: "SLTIU",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = match cpu.unsigned_data(cpu.x[f.rs1]) < cpu.unsigned_data(f.imm) {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_i
},
Instruction {
mask: 0xfe00707f,
data: 0x00003033,
name: "SLTU",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = match cpu.unsigned_data(cpu.x[f.rs1]) < cpu.unsigned_data(cpu.x[f.rs2]) {
true => 1,
false => 0
};
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x40005033,
name: "SRA",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_shr(cpu.x[f.rs2] as u32));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x40005013,
name: "SRAI",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] >> shamt);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x4000501b,
name: "SRAIW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let shamt = ((word >> 20) & 0x1f) as u32;
cpu.x[f.rd] = ((cpu.x[f.rs1] as i32) >> shamt) as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x4000503b,
name: "SRAW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = (cpu.x[f.rs1] as i32).wrapping_shr(cpu.x[f.rs2] as u32) as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xffffffff,
data: 0x10200073,
name: "SRET",
operation: |cpu, _word, _address| {
cpu.pc = match cpu.read_csr(CSR_SEPC_ADDRESS) {
Ok(data) => data,
Err(e) => return Err(e)
};
let status = cpu.read_csr_raw(CSR_SSTATUS_ADDRESS);
let spie = (status >> 5) & 1;
let spp = (status >> 8) & 1;
let new_status = (status & !0x122) | (spie << 1) | (1 << 5);
cpu.write_csr_raw(CSR_SSTATUS_ADDRESS, new_status);
cpu.privilege_mode = match spp {
0 => PrivilegeMode::User,
1 => PrivilegeMode::Supervisor,
_ => panic!() };
cpu.mmu.update_privilege_mode(cpu.privilege_mode.clone());
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0x00005033,
name: "SRL",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.unsigned_data(cpu.x[f.rs1]).wrapping_shr(cpu.x[f.rs2] as u32) as i64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x00005013,
name: "SRLI",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = cpu.sign_extend((cpu.unsigned_data(cpu.x[f.rs1]) >> shamt) as i64);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfc00707f,
data: 0x0000501b,
name: "SRLIW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
let mask = match cpu.xlen {
Xlen::Bit32 => 0x1f,
Xlen::Bit64 => 0x3f
};
let shamt = (word >> 20) & mask;
cpu.x[f.rd] = ((cpu.x[f.rs1] as u32) >> shamt) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x0000503b,
name: "SRLW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = (cpu.x[f.rs1] as u32).wrapping_shr(cpu.x[f.rs2] as u32) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x40000033,
name: "SUB",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1].wrapping_sub(cpu.x[f.rs2]));
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0xfe00707f,
data: 0x4000003b,
name: "SUBW",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.x[f.rs1].wrapping_sub(cpu.x[f.rs2]) as i32 as i64;
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00002023,
name: "SW",
operation: |cpu, word, _address| {
let f = parse_format_s(word);
cpu.mmu.store_word(cpu.x[f.rs1].wrapping_add(f.imm) as u64, cpu.x[f.rs2] as u32)
},
disassemble: dump_format_s
},
Instruction {
mask: 0xffffffff,
data: 0x00200073,
name: "URET",
operation: |_cpu, _word, _address| {
panic!("URET instruction is not implemented yet.");
},
disassemble: dump_empty
},
Instruction {
mask: 0xffffffff,
data: 0x10500073,
name: "WFI",
operation: |cpu, _word, _address| {
cpu.wfi = true;
Ok(())
},
disassemble: dump_empty
},
Instruction {
mask: 0xfe00707f,
data: 0x00004033,
name: "XOR",
operation: |cpu, word, _address| {
let f = parse_format_r(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] ^ cpu.x[f.rs2]);
Ok(())
},
disassemble: dump_format_r
},
Instruction {
mask: 0x0000707f,
data: 0x00004013,
name: "XORI",
operation: |cpu, word, _address| {
let f = parse_format_i(word);
cpu.x[f.rd] = cpu.sign_extend(cpu.x[f.rs1] ^ f.imm);
Ok(())
},
disassemble: dump_format_i
},
];
const DECODE_CACHE_ENTRY_NUM: usize = 0x1000;
const INVALID_CACHE_ENTRY: usize = INSTRUCTION_NUM;
const NULL_ENTRY: usize = DECODE_CACHE_ENTRY_NUM;
struct DecodeCache {
hash_map: HashMap::<u32, usize>,
entries: Vec<DecodeCacheEntry>,
front_index: usize,
back_index: usize,
hit_count: u64,
miss_count: u64
}
impl DecodeCache {
fn new() -> Self {
let mut entries = Vec::new();
for i in 0..DECODE_CACHE_ENTRY_NUM {
let next_index = match i == DECODE_CACHE_ENTRY_NUM - 1 {
true => NULL_ENTRY,
false => i + 1
};
let prev_index = match i == 0 {
true => NULL_ENTRY,
false => i - 1
};
entries.push(DecodeCacheEntry::new(next_index, prev_index));
}
DecodeCache {
hash_map: HashMap::new(),
entries: entries,
front_index: 0,
back_index: DECODE_CACHE_ENTRY_NUM - 1,
hit_count: 0,
miss_count: 0
}
}
fn get(&mut self, word: u32) -> Option<usize> {
let result = match self.hash_map.get(&word) {
Some(index) => {
self.hit_count += 1;
if self.front_index != *index {
let next_index = self.entries[*index].next_index;
let prev_index = self.entries[*index].prev_index;
if self.back_index == *index {
self.back_index = prev_index;
} else {
self.entries[next_index].prev_index = prev_index;
}
self.entries[prev_index].next_index = next_index;
self.entries[*index].prev_index = NULL_ENTRY;
self.entries[*index].next_index = self.front_index;
self.entries[self.front_index].prev_index = *index;
self.front_index = *index;
}
Some(self.entries[*index].instruction_index)
},
None => {
self.miss_count += 1;
None
}
};
result
}
fn insert(&mut self, word: u32, instruction_index: usize) {
let index = self.back_index;
if self.entries[index].instruction_index != INVALID_CACHE_ENTRY {
self.hash_map.remove(&self.entries[index].word);
}
self.back_index = self.entries[index].prev_index;
self.entries[self.back_index].next_index = NULL_ENTRY;
self.hash_map.insert(word, index);
self.entries[index].prev_index = NULL_ENTRY;
self.entries[index].next_index = self.front_index;
self.entries[index].word = word;
self.entries[index].instruction_index = instruction_index;
self.entries[self.front_index].prev_index = index;
self.front_index = index;
}
}
struct DecodeCacheEntry {
word: u32,
instruction_index: usize,
next_index: usize,
prev_index: usize
}
impl DecodeCacheEntry {
fn new(next_index: usize, prev_index: usize) -> Self {
DecodeCacheEntry {
word: 0,
instruction_index: INVALID_CACHE_ENTRY,
next_index: next_index,
prev_index: prev_index
}
}
}