wup getting ecall

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2023-12-30 21:29:18 +08:00
parent 141cb2e9dc
commit fc18060bd9
4 changed files with 302 additions and 208 deletions

79
Cargo.lock generated
View File

@ -2,6 +2,47 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "goblin"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134"
dependencies = [
"log",
"plain",
"scroll",
]
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
[[package]]
name = "proc-macro2"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "riscv-cpu" name = "riscv-cpu"
version = "0.1.0" version = "0.1.0"
@ -10,5 +51,43 @@ version = "0.1.0"
name = "rouns" name = "rouns"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"goblin",
"riscv-cpu", "riscv-cpu",
] ]
[[package]]
name = "scroll"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
dependencies = [
"scroll_derive",
]
[[package]]
name = "scroll_derive"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

View File

@ -9,3 +9,4 @@ edition = "2021"
[dependencies] [dependencies]
riscv-cpu = { path = "crates/riscv-cpu" } riscv-cpu = { path = "crates/riscv-cpu" }
goblin = { version = "0.7.1", features = [ "std", "elf32", "alloc" ]}

View File

@ -23,12 +23,12 @@ const CSR_SIDELEG_ADDRESS: u16 = 0x103;
const CSR_SIE_ADDRESS: u16 = 0x104; const CSR_SIE_ADDRESS: u16 = 0x104;
const CSR_STVEC_ADDRESS: u16 = 0x105; const CSR_STVEC_ADDRESS: u16 = 0x105;
const _CSR_SSCRATCH_ADDRESS: u16 = 0x140; const _CSR_SSCRATCH_ADDRESS: u16 = 0x140;
const CSR_SEPC_ADDRESS: u16 = 0x141; pub const CSR_SEPC_ADDRESS: u16 = 0x141;
const CSR_SCAUSE_ADDRESS: u16 = 0x142; const CSR_SCAUSE_ADDRESS: u16 = 0x142;
const CSR_STVAL_ADDRESS: u16 = 0x143; const CSR_STVAL_ADDRESS: u16 = 0x143;
const CSR_SIP_ADDRESS: u16 = 0x144; const CSR_SIP_ADDRESS: u16 = 0x144;
const CSR_SATP_ADDRESS: u16 = 0x180; pub const CSR_SATP_ADDRESS: u16 = 0x180;
const CSR_MSTATUS_ADDRESS: u16 = 0x300; pub const CSR_MSTATUS_ADDRESS: u16 = 0x300;
// const CSR_MISA_ADDRESS: u16 = 0x301; // const CSR_MISA_ADDRESS: u16 = 0x301;
const CSR_MEDELEG_ADDRESS: u16 = 0x302; const CSR_MEDELEG_ADDRESS: u16 = 0x302;
const CSR_MIDELEG_ADDRESS: u16 = 0x303; const CSR_MIDELEG_ADDRESS: u16 = 0x303;
@ -82,8 +82,7 @@ pub enum Xlen {
Bit64, // @TODO: Support Bit128 Bit64, // @TODO: Support Bit128
} }
#[derive(Clone)] #[derive(Clone, Debug)]
#[allow(dead_code)]
pub enum PrivilegeMode { pub enum PrivilegeMode {
User, User,
Supervisor, Supervisor,
@ -91,12 +90,13 @@ pub enum PrivilegeMode {
Machine, Machine,
} }
#[derive(Debug)]
pub struct Trap { pub struct Trap {
pub trap_type: TrapType, pub trap_type: TrapType,
pub value: u64, // Trap type specific value pub value: u64, // Trap type specific value
} }
#[allow(dead_code)] #[derive(Debug)]
pub enum TrapType { pub enum TrapType {
InstructionAddressMisaligned, InstructionAddressMisaligned,
InstructionAccessFault, InstructionAccessFault,
@ -319,6 +319,19 @@ impl Cpu {
} }
} }
/// Writes integer register content
///
/// # Arguments
/// * `reg` Register number. Must be 0-31
/// * `val` 64-bit value
pub fn write_register(&mut self, reg: u8, val: i64) {
debug_assert!(reg <= 31, "reg must be 0-31. {}", reg);
if reg == 0 {
return;
}
self.x[reg as usize] = val;
}
/// Reads Program counter content /// Reads Program counter content
pub fn read_pc(&self) -> u64 { pub fn read_pc(&self) -> u64 {
self.pc self.pc
@ -350,35 +363,37 @@ impl Cpu {
return Ok(()); return Ok(());
} }
let original_word = match self.fetch() { let original_word = self.fetch()?;
Ok(word) => word,
Err(e) => return Err(e),
};
let instruction_address = self.pc; let instruction_address = self.pc;
let word = match (original_word & 0x3) == 0x3 { let word = if (original_word & 0x3) == 0x3 {
true => { self.pc = self.pc.wrapping_add(4); // 32-bit length non-compressed instruction
self.pc = self.pc.wrapping_add(4); // 32-bit length non-compressed instruction original_word
original_word } else {
} self.pc = self.pc.wrapping_add(2); // 16-bit length compressed instruction
false => { self.uncompress(original_word & 0xffff)
self.pc = self.pc.wrapping_add(2); // 16-bit length compressed instruction
self.uncompress(original_word & 0xffff)
}
}; };
match self.decode(word) { let Ok(inst) = self.decode_raw(word) else {
Ok(inst) => { panic!(
let result = (inst.operation)(self, word, instruction_address); "Unknown instruction PC:{:x} WORD:{:x}",
self.x[0] = 0; // hardwired zero instruction_address, original_word
result );
} };
Err(()) => {
panic!( println!(
"Unknown instruction PC:{:x} WORD:{:x}", "pc @ 0x{:08x}: {:08x} {} {}",
instruction_address, original_word instruction_address,
); original_word,
} inst.name,
} (inst.disassemble)(self, original_word, self.pc, true)
);
let result = (inst.operation)(self, word, instruction_address);
self.x[0] = 0; // hardwired zero
result
}
pub fn execute_opcode(&mut self, op: u32) -> Result<(), Trap> {
(self.decode_raw(op)?.operation)(self, op, self.pc)
} }
/// Decodes a word instruction data and returns a reference to /// Decodes a word instruction data and returns a reference to
@ -386,27 +401,27 @@ impl Cpu {
/// so if cache hits this method returns the result very quickly. /// so if cache hits this method returns the result very quickly.
/// The result will be stored to cache. /// The result will be stored to cache.
fn decode(&mut self, word: u32) -> Result<&Instruction, ()> { fn decode(&mut self, word: u32) -> Result<&Instruction, ()> {
match self.decode_cache.get(word) { if let Some(index) = self.decode_cache.get(word) {
Some(index) => Ok(&INSTRUCTIONS[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(()),
},
} }
let Ok(index) = self.decode_and_get_instruction_index(word) else {
return Err(());
};
self.decode_cache.insert(word, index);
Ok(&INSTRUCTIONS[index])
} }
/// Decodes a word instruction data and returns a reference to /// Decodes a word instruction data and returns a reference to
/// [`Instruction`](struct.Instruction.html). Not Using [`DecodeCache`](struct.DecodeCache.html) /// [`Instruction`](struct.Instruction.html). Not Using [`DecodeCache`](struct.DecodeCache.html)
/// so if you don't want to pollute the cache you should use this method /// so if you don't want to pollute the cache you should use this method
/// instead of `decode`. /// instead of `decode`.
fn decode_raw(&self, word: u32) -> Result<&Instruction, ()> { fn decode_raw(&self, word: u32) -> Result<&Instruction, Trap> {
match self.decode_and_get_instruction_index(word) { self.decode_and_get_instruction_index(word)
Ok(index) => Ok(&INSTRUCTIONS[index]), .map(|index| &INSTRUCTIONS[index])
Err(()) => Err(()), .map_err(|_| Trap {
} value: self.pc.wrapping_sub(4),
trap_type: TrapType::IllegalInstruction,
})
} }
/// Decodes a word instruction data and returns an index of /// Decodes a word instruction data and returns an index of
@ -744,14 +759,12 @@ impl Cpu {
} }
fn fetch(&mut self) -> Result<u32, Trap> { fn fetch(&mut self) -> Result<u32, Trap> {
let word = match self.mmu.fetch_word(self.pc) { // println!("Fetching word from {:08x}...", self.pc);
Ok(word) => word, self.mmu.fetch_word(self.pc).map_err(|e| {
Err(e) => { self.pc = self.pc.wrapping_add(4); // @TODO: What if instruction is compressed?
self.pc = self.pc.wrapping_add(4); // @TODO: What if instruction is compressed? println!("Fetch error: {:x?}", e);
return Err(e); e
} })
};
Ok(word)
} }
fn has_csr_access_privilege(&self, address: u16) -> bool { fn has_csr_access_privilege(&self, address: u16) -> bool {
@ -769,7 +782,7 @@ impl Cpu {
} }
} }
fn write_csr(&mut self, address: u16, value: u64) -> Result<(), Trap> { pub fn write_csr(&mut self, address: u16, value: u64) -> Result<(), Trap> {
match self.has_csr_access_privilege(address) { match self.has_csr_access_privilege(address) {
true => { true => {
/* /*
@ -1442,31 +1455,22 @@ impl Cpu {
// for example updating page table entry or update peripheral hardware registers. // for example updating page table entry or update peripheral hardware registers.
// But ideally disassembling doesn't want to cause any side effect. // But ideally disassembling doesn't want to cause any side effect.
// How can we avoid side effect? // How can we avoid side effect?
let mut original_word = match self.mmu.fetch_word(self.pc) { let Ok(mut original_word) = self.mmu.fetch_word(self.pc) else {
Ok(data) => data, return format!("PC:{:016x}, InstructionPageFault Trap!\n", self.pc);
Err(_e) => {
return format!("PC:{:016x}, InstructionPageFault Trap!\n", self.pc);
}
}; };
let word = match (original_word & 0x3) == 0x3 { let word = if (original_word & 0x3) == 0x3 {
true => original_word, original_word
false => { } else {
original_word &= 0xffff; original_word &= 0xffff;
self.uncompress(original_word) self.uncompress(original_word)
}
}; };
let inst = { let Ok(inst) = self.decode_raw(word) else {
match self.decode_raw(word) { return format!(
Ok(inst) => inst, "Unknown instruction PC:{:x} WORD:{:x}",
Err(()) => { self.pc, original_word
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)); let mut s = format!("PC:{:016x} ", self.unsigned_data(self.pc as i64));
@ -1484,6 +1488,18 @@ impl Cpu {
pub fn memory_base(&self) -> u64 { pub fn memory_base(&self) -> u64 {
self.memory_base self.memory_base
} }
pub fn memory_size(&self) -> u64 {
self.mmu.memory_size()
}
pub fn phys_read_u8(&mut self, address: u64) -> u8 {
self.mmu.load_raw(address)
}
pub fn phys_write_u8(&mut self, address: u64, value: u8) {
self.mmu.store_raw(address, value)
}
} }
struct Instruction { struct Instruction {
@ -1491,7 +1507,7 @@ struct Instruction {
data: u32, // @TODO: rename data: u32, // @TODO: rename
name: &'static str, name: &'static str,
operation: fn(cpu: &mut Cpu, word: u32, address: u64) -> Result<(), Trap>, operation: fn(cpu: &mut Cpu, word: u32, address: u64) -> Result<(), Trap>,
disassemble: fn(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String, disassemble: fn(cpu: &Cpu, word: u32, address: u64, evaluate: bool) -> String,
} }
struct FormatB { struct FormatB {
@ -1517,7 +1533,7 @@ fn parse_format_b(word: u32) -> FormatB {
} }
} }
fn dump_format_b(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String { fn dump_format_b(cpu: &Cpu, word: u32, address: u64, evaluate: bool) -> String {
let f = parse_format_b(word); let f = parse_format_b(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rs1); s += get_register_name(f.rs1);
@ -1546,7 +1562,7 @@ fn parse_format_csr(word: u32) -> FormatCSR {
} }
} }
fn dump_format_csr(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { fn dump_format_csr(cpu: &Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_csr(word); let f = parse_format_csr(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rd); s += get_register_name(f.rd);
@ -1586,7 +1602,7 @@ fn parse_format_i(word: u32) -> FormatI {
} }
} }
fn dump_format_i(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { fn dump_format_i(cpu: &Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_i(word); let f = parse_format_i(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rd); s += get_register_name(f.rd);
@ -1601,7 +1617,7 @@ fn dump_format_i(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> Str
s s
} }
fn dump_format_i_mem(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { fn dump_format_i_mem(cpu: &Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_i(word); let f = parse_format_i(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rd); s += get_register_name(f.rd);
@ -1637,7 +1653,7 @@ fn parse_format_j(word: u32) -> FormatJ {
} }
} }
fn dump_format_j(cpu: &mut Cpu, word: u32, address: u64, evaluate: bool) -> String { fn dump_format_j(cpu: &Cpu, word: u32, address: u64, evaluate: bool) -> String {
let f = parse_format_j(word); let f = parse_format_j(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rd); s += get_register_name(f.rd);
@ -1662,7 +1678,7 @@ fn parse_format_r(word: u32) -> FormatR {
} }
} }
fn dump_format_r(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { fn dump_format_r(cpu: &Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_r(word); let f = parse_format_r(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rd); s += get_register_name(f.rd);
@ -1697,7 +1713,7 @@ fn parse_format_r2(word: u32) -> FormatR2 {
} }
} }
fn dump_format_r2(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { fn dump_format_r2(cpu: &Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_r2(word); let f = parse_format_r2(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rd); s += get_register_name(f.rd);
@ -1741,7 +1757,7 @@ fn parse_format_s(word: u32) -> FormatS {
} }
} }
fn dump_format_s(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { fn dump_format_s(cpu: &Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_s(word); let f = parse_format_s(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rs2); s += get_register_name(f.rs2);
@ -1775,7 +1791,7 @@ fn parse_format_u(word: u32) -> FormatU {
} }
} }
fn dump_format_u(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> String { fn dump_format_u(cpu: &Cpu, word: u32, _address: u64, evaluate: bool) -> String {
let f = parse_format_u(word); let f = parse_format_u(word);
let mut s = String::new(); let mut s = String::new();
s += get_register_name(f.rd); s += get_register_name(f.rd);
@ -1786,7 +1802,7 @@ fn dump_format_u(cpu: &mut Cpu, word: u32, _address: u64, evaluate: bool) -> Str
s s
} }
fn dump_empty(_cpu: &mut Cpu, _word: u32, _address: u64, _evaluate: bool) -> String { fn dump_empty(_cpu: &Cpu, _word: u32, _address: u64, _evaluate: bool) -> String {
String::new() String::new()
} }
@ -3424,6 +3440,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
1 => PrivilegeMode::Supervisor, 1 => PrivilegeMode::Supervisor,
_ => panic!(), // Shouldn't happen _ => panic!(), // Shouldn't happen
}; };
println!("Updating privilege mode to {:?}", cpu.privilege_mode);
cpu.mmu.update_privilege_mode(cpu.privilege_mode.clone()); cpu.mmu.update_privilege_mode(cpu.privilege_mode.clone());
Ok(()) Ok(())
}, },

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, num::NonZeroU64};
use crate::{ use crate::{
cpu::{get_privilege_mode, PrivilegeMode, Trap, TrapType, Xlen}, cpu::{get_privilege_mode, PrivilegeMode, Trap, TrapType, Xlen},
@ -18,6 +18,9 @@ pub struct Mmu {
privilege_mode: PrivilegeMode, privilege_mode: PrivilegeMode,
memory: MemoryWrapper, memory: MemoryWrapper,
/// The size of main memory (if initialized)
memory_length: Option<NonZeroU64>,
/// Address translation can be affected `mstatus` (MPRV, MPP in machine mode) /// Address translation can be affected `mstatus` (MPRV, MPP in machine mode)
/// then `Mmu` has copy of it. /// then `Mmu` has copy of it.
mstatus: u64, mstatus: u64,
@ -39,6 +42,7 @@ pub struct Mmu {
store_page_cache: HashMap<u64, u64>, store_page_cache: HashMap<u64, u64>,
} }
#[derive(Debug)]
pub enum AddressingMode { pub enum AddressingMode {
None, None,
SV32, SV32,
@ -87,6 +91,7 @@ impl Mmu {
fetch_page_cache: HashMap::default(), fetch_page_cache: HashMap::default(),
load_page_cache: HashMap::default(), load_page_cache: HashMap::default(),
store_page_cache: HashMap::default(), store_page_cache: HashMap::default(),
memory_length: None,
} }
} }
@ -104,9 +109,15 @@ impl Mmu {
/// # Arguments /// # Arguments
/// * `capacity` /// * `capacity`
pub fn init_memory(&mut self, capacity: u64) { pub fn init_memory(&mut self, capacity: u64) {
assert!(self.memory_length.is_none());
self.memory_length = Some(NonZeroU64::new(capacity).unwrap());
self.memory.init(capacity); self.memory.init(capacity);
} }
pub fn memory_size(&self) -> u64 {
self.memory_length.unwrap().get()
}
/// Enables or disables page cache optimization. /// Enables or disables page cache optimization.
/// ///
/// # Arguments /// # Arguments
@ -190,29 +201,25 @@ impl Mmu {
/// * `v_address` Virtual address /// * `v_address` Virtual address
pub fn fetch_word(&mut self, v_address: u64) -> Result<u32, Trap> { pub fn fetch_word(&mut self, v_address: u64) -> Result<u32, Trap> {
let width = 4; let width = 4;
match (v_address & 0xfff) <= (0x1000 - width) { if (v_address & 0xfff) <= (0x1000 - width) {
true => { // Fast path. All bytes fetched are in the same page so
// Fast path. All bytes fetched are in the same page so // translating an address only once.
// translating an address only once. let effective_address = self.get_effective_address(v_address);
let effective_address = self.get_effective_address(v_address); self.translate_address(effective_address, &MemoryAccessType::Execute)
match self.translate_address(effective_address, &MemoryAccessType::Execute) { .map(|p_address| self.load_word_raw(p_address))
Ok(p_address) => Ok(self.load_word_raw(p_address)), .map_err(|()| Trap {
Err(()) => Err(Trap { trap_type: TrapType::InstructionPageFault,
trap_type: TrapType::InstructionPageFault, value: effective_address,
value: effective_address, })
}), } else {
} let mut data = 0;
} for i in 0..width {
false => { match self.fetch(v_address.wrapping_add(i)) {
let mut data = 0; Ok(byte) => data |= (byte as u32) << (i * 8),
for i in 0..width { Err(e) => return Err(e),
match self.fetch(v_address.wrapping_add(i)) { };
Ok(byte) => data |= (byte as u32) << (i * 8),
Err(e) => return Err(e),
};
}
Ok(data)
} }
Ok(data)
} }
} }
@ -396,7 +403,7 @@ impl Mmu {
/// ///
/// # Arguments /// # Arguments
/// * `p_address` Physical address /// * `p_address` Physical address
fn load_raw(&mut self, p_address: u64) -> u8 { pub(crate) fn load_raw(&mut self, p_address: u64) -> u8 {
self.memory.read_byte(self.get_effective_address(p_address)) self.memory.read_byte(self.get_effective_address(p_address))
} }
@ -416,7 +423,9 @@ impl Mmu {
/// # Arguments /// # Arguments
/// * `p_address` Physical address /// * `p_address` Physical address
pub fn load_word_raw(&mut self, p_address: u64) -> u32 { pub fn load_word_raw(&mut self, p_address: u64) -> u32 {
self.memory.read_word(self.get_effective_address(p_address)) let val = self.memory.read_word(self.get_effective_address(p_address));
// println!("Read value from {:08x}: {:08x}", p_address, val);
val
} }
/// Loads eight bytes from main memory or peripheral devices depending on /// Loads eight bytes from main memory or peripheral devices depending on
@ -435,7 +444,7 @@ impl Mmu {
/// # Arguments /// # Arguments
/// * `p_address` Physical address /// * `p_address` Physical address
/// * `value` data written /// * `value` data written
pub fn store_raw(&mut self, p_address: u64, value: u8) { pub(crate) fn store_raw(&mut self, p_address: u64, value: u8) {
self.memory self.memory
.write_byte(self.get_effective_address(p_address), value) .write_byte(self.get_effective_address(p_address), value)
} }
@ -496,7 +505,7 @@ impl Mmu {
) -> Result<u64, ()> { ) -> Result<u64, ()> {
let address = self.get_effective_address(v_address); let address = self.get_effective_address(v_address);
let v_page = address & !0xfff; let v_page = address & !0xfff;
let cache = match self.page_cache_enabled { if let Some(p_page) = match self.page_cache_enabled {
true => match access_type { true => match access_type {
MemoryAccessType::Execute => self.fetch_page_cache.get(&v_page), MemoryAccessType::Execute => self.fetch_page_cache.get(&v_page),
MemoryAccessType::Read => self.load_page_cache.get(&v_page), MemoryAccessType::Read => self.load_page_cache.get(&v_page),
@ -504,106 +513,94 @@ impl Mmu {
MemoryAccessType::DontCare => None, MemoryAccessType::DontCare => None,
}, },
false => None, false => None,
}; } {
match cache { return Ok(p_page | (address & 0xfff));
Some(p_page) => Ok(p_page | (address & 0xfff)), }
None => {
let p_address = match self.addressing_mode { let p_address = match self.addressing_mode {
AddressingMode::None => Ok(address), AddressingMode::None => Ok(address),
AddressingMode::SV32 => match self.privilege_mode { AddressingMode::SV32 => match self.privilege_mode {
// @TODO: Optimize // @TODO: Optimize
PrivilegeMode::Machine => match access_type { PrivilegeMode::Machine => match access_type {
MemoryAccessType::Execute => Ok(address), MemoryAccessType::Execute => Ok(address),
// @TODO: Remove magic number // @TODO: Remove magic number
_ => match (self.mstatus >> 17) & 1 { _ => match (self.mstatus >> 17) & 1 {
0 => Ok(address), 0 => Ok(address),
_ => {
let privilege_mode = get_privilege_mode((self.mstatus >> 9) & 3);
match privilege_mode {
PrivilegeMode::Machine => Ok(address),
_ => { _ => {
let privilege_mode = let current_privilege_mode = self.privilege_mode.clone();
get_privilege_mode((self.mstatus >> 9) & 3); self.update_privilege_mode(privilege_mode);
match privilege_mode { let result = self.translate_address(v_address, access_type);
PrivilegeMode::Machine => Ok(address), self.update_privilege_mode(current_privilege_mode);
_ => { result
let current_privilege_mode =
self.privilege_mode.clone();
self.update_privilege_mode(privilege_mode);
let result =
self.translate_address(v_address, access_type);
self.update_privilege_mode(current_privilege_mode);
result
}
}
} }
}, }
},
PrivilegeMode::User | PrivilegeMode::Supervisor => {
let vpns = [(address >> 12) & 0x3ff, (address >> 22) & 0x3ff];
self.traverse_page(address, 2 - 1, self.ppn, &vpns, access_type)
} }
_ => Ok(address),
}, },
AddressingMode::SV39 => match self.privilege_mode { },
// @TODO: Optimize PrivilegeMode::User | PrivilegeMode::Supervisor => {
// @TODO: Remove duplicated code with SV32 let vpns = [(address >> 12) & 0x3ff, (address >> 22) & 0x3ff];
PrivilegeMode::Machine => match access_type { self.traverse_page(address, 2 - 1, self.ppn, &vpns, access_type)
MemoryAccessType::Execute => Ok(address),
// @TODO: Remove magic number
_ => match (self.mstatus >> 17) & 1 {
0 => Ok(address),
_ => {
let privilege_mode =
get_privilege_mode((self.mstatus >> 9) & 3);
match privilege_mode {
PrivilegeMode::Machine => Ok(address),
_ => {
let current_privilege_mode =
self.privilege_mode.clone();
self.update_privilege_mode(privilege_mode);
let result =
self.translate_address(v_address, access_type);
self.update_privilege_mode(current_privilege_mode);
result
}
}
}
},
},
PrivilegeMode::User | PrivilegeMode::Supervisor => {
let vpns = [
(address >> 12) & 0x1ff,
(address >> 21) & 0x1ff,
(address >> 30) & 0x1ff,
];
self.traverse_page(address, 3 - 1, self.ppn, &vpns, access_type)
}
_ => Ok(address),
},
AddressingMode::SV48 => {
panic!("AddressingMode SV48 is not supported yet.");
}
};
match self.page_cache_enabled {
true => match p_address {
Ok(p_address) => {
let p_page = p_address & !0xfff;
match access_type {
MemoryAccessType::Execute => {
self.fetch_page_cache.insert(v_page, p_page)
}
MemoryAccessType::Read => {
self.load_page_cache.insert(v_page, p_page)
}
MemoryAccessType::Write => {
self.store_page_cache.insert(v_page, p_page)
}
MemoryAccessType::DontCare => None,
};
Ok(p_address)
}
Err(()) => Err(()),
},
false => p_address,
} }
_ => Ok(address),
},
AddressingMode::SV39 => match self.privilege_mode {
// @TODO: Optimize
// @TODO: Remove duplicated code with SV32
PrivilegeMode::Machine => match access_type {
MemoryAccessType::Execute => Ok(address),
// @TODO: Remove magic number
_ => match (self.mstatus >> 17) & 1 {
0 => Ok(address),
_ => {
let privilege_mode = get_privilege_mode((self.mstatus >> 9) & 3);
match privilege_mode {
PrivilegeMode::Machine => Ok(address),
_ => {
let current_privilege_mode = self.privilege_mode.clone();
self.update_privilege_mode(privilege_mode);
let result = self.translate_address(v_address, access_type);
self.update_privilege_mode(current_privilege_mode);
result
}
}
}
},
},
PrivilegeMode::User | PrivilegeMode::Supervisor => {
let vpns = [
(address >> 12) & 0x1ff,
(address >> 21) & 0x1ff,
(address >> 30) & 0x1ff,
];
self.traverse_page(address, 3 - 1, self.ppn, &vpns, access_type)
}
_ => Ok(address),
},
AddressingMode::SV48 => {
panic!("AddressingMode SV48 is not supported yet.");
} }
};
if self.page_cache_enabled {
match p_address {
Ok(p_address) => {
let p_page = p_address & !0xfff;
match access_type {
MemoryAccessType::Execute => self.fetch_page_cache.insert(v_page, p_page),
MemoryAccessType::Read => self.load_page_cache.insert(v_page, p_page),
MemoryAccessType::Write => self.store_page_cache.insert(v_page, p_page),
MemoryAccessType::DontCare => None,
};
Ok(p_address)
}
Err(()) => Err(()),
}
} else {
p_address
} }
} }