@ -1,4 +1,7 @@
|
||||
use crate::mmu::{AddressingMode, Mmu};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
pub use super::mmu::Memory;
|
||||
use super::mmu::{AddressingMode, Mmu};
|
||||
|
||||
const DEFAULT_MEMORY_BASE: u64 = 0x80000000;
|
||||
|
||||
@ -53,10 +56,6 @@ pub const MIP_SEIP: u64 = 0x200;
|
||||
const MIP_STIP: u64 = 0x020;
|
||||
const MIP_SSIP: u64 = 0x002;
|
||||
|
||||
pub trait EventHandler {
|
||||
fn handle_event(&mut self, cpu: &mut Cpu, args: [i64; 8]) -> [i64; 8];
|
||||
}
|
||||
|
||||
/// Emulates a RISC-V CPU core
|
||||
pub struct Cpu {
|
||||
clock: u64,
|
||||
@ -70,13 +69,12 @@ pub struct Cpu {
|
||||
pc: u64,
|
||||
csr: [u64; CSR_CAPACITY],
|
||||
mmu: Mmu,
|
||||
memory: Arc<RwLock<dyn Memory + Send + Sync>>,
|
||||
reservation: u64, // @TODO: Should support multiple address reservations
|
||||
is_reservation_set: bool,
|
||||
_dump_flag: bool,
|
||||
// decode_cache: DecodeCache,
|
||||
unsigned_data_mask: u64,
|
||||
memory_base: u64,
|
||||
handler: Option<Box<dyn EventHandler>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -85,7 +83,7 @@ pub enum Xlen {
|
||||
Bit64, // @TODO: Support Bit128
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum PrivilegeMode {
|
||||
User,
|
||||
Supervisor,
|
||||
@ -146,7 +144,7 @@ fn get_privilege_encoding(mode: &PrivilegeMode) -> u8 {
|
||||
}
|
||||
|
||||
/// Returns `PrivilegeMode` from encoded privilege mode bits
|
||||
pub fn get_privilege_mode(encoding: u64) -> PrivilegeMode {
|
||||
pub fn decode_privilege_mode(encoding: u64) -> PrivilegeMode {
|
||||
match encoding {
|
||||
0 => PrivilegeMode::User,
|
||||
1 => PrivilegeMode::Supervisor,
|
||||
@ -217,18 +215,14 @@ fn get_trap_cause(trap: &Trap, xlen: &Xlen) -> u64 {
|
||||
|
||||
pub struct CpuBuilder {
|
||||
xlen: Xlen,
|
||||
memory_size: u64,
|
||||
memory_base: u64,
|
||||
handler: Option<Box<dyn EventHandler>>,
|
||||
memory: Arc<RwLock<dyn Memory + Send + Sync>>,
|
||||
}
|
||||
|
||||
impl CpuBuilder {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(memory: Arc<RwLock<dyn Memory + Send + Sync>>) -> Self {
|
||||
CpuBuilder {
|
||||
xlen: Xlen::Bit64,
|
||||
memory_size: 0,
|
||||
memory_base: DEFAULT_MEMORY_BASE,
|
||||
handler: None,
|
||||
memory,
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,45 +231,19 @@ impl CpuBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn memory_size(mut self, memory_size: u64) -> Self {
|
||||
self.memory_size = memory_size;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn handler(mut self, handler: Box<dyn EventHandler>) -> Self {
|
||||
self.handler = Some(handler);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Cpu {
|
||||
let mut cpu = Cpu::new(self.memory_base);
|
||||
let mut cpu = Cpu::new(self.memory);
|
||||
cpu.update_xlen(self.xlen.clone());
|
||||
cpu.mmu.init_memory(self.memory_size);
|
||||
if self.handler.is_some() {
|
||||
cpu.set_handler(self.handler);
|
||||
}
|
||||
cpu
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CpuBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Cpu {
|
||||
fn default() -> Self {
|
||||
Self::new(DEFAULT_MEMORY_BASE)
|
||||
}
|
||||
}
|
||||
|
||||
impl Cpu {
|
||||
/// Creates a new `Cpu`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `Terminal`
|
||||
pub fn new(memory_base: u64) -> Self {
|
||||
pub fn new(memory: Arc<RwLock<dyn Memory + Send + Sync>>) -> Self {
|
||||
Cpu {
|
||||
clock: 0,
|
||||
xlen: Xlen::Bit64,
|
||||
@ -285,14 +253,13 @@ impl Cpu {
|
||||
f: [0.0; 32],
|
||||
pc: 0,
|
||||
csr: [0; CSR_CAPACITY],
|
||||
mmu: Mmu::new(Xlen::Bit64, memory_base),
|
||||
mmu: Mmu::new(Xlen::Bit64, memory.clone()),
|
||||
reservation: 0,
|
||||
is_reservation_set: false,
|
||||
_dump_flag: false,
|
||||
// decode_cache: DecodeCache::new(),
|
||||
unsigned_data_mask: 0xffffffffffffffff,
|
||||
memory_base,
|
||||
handler: None,
|
||||
memory,
|
||||
}
|
||||
// let mut cpu = ;
|
||||
// cpu.x[0xb] = 0x1020; // I don't know why but Linux boot seems to require this initialization
|
||||
@ -300,14 +267,6 @@ impl Cpu {
|
||||
// cpu
|
||||
}
|
||||
|
||||
/// Assigns an event handler to the CPU.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `handler` An object that implements the [`EventHandler`](trait.EventHandler.html) trait
|
||||
pub fn set_handler(&mut self, handler: Option<Box<dyn EventHandler>>) {
|
||||
self.handler = handler;
|
||||
}
|
||||
|
||||
/// Updates Program Counter content
|
||||
///
|
||||
/// # Arguments
|
||||
@ -1507,13 +1466,13 @@ impl Cpu {
|
||||
&mut self.mmu
|
||||
}
|
||||
|
||||
pub fn memory_base(&self) -> u64 {
|
||||
self.memory_base
|
||||
}
|
||||
// pub fn memory_base(&self) -> u64 {
|
||||
// self.memory_base
|
||||
// }
|
||||
|
||||
pub fn memory_size(&self) -> u64 {
|
||||
self.mmu.memory_size()
|
||||
}
|
||||
// pub fn memory_size(&self) -> u64 {
|
||||
// self.mmu.memory_size()
|
||||
// }
|
||||
|
||||
pub fn phys_read_u32(&self, address: u64) -> u32 {
|
||||
self.mmu.load_word_raw(address)
|
||||
@ -2455,30 +2414,27 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
||||
mask: 0xffffffff,
|
||||
data: 0x00000073,
|
||||
name: "ECALL",
|
||||
operation: |cpu, _word, address| {
|
||||
if let Some(mut handler) = cpu.handler.take() {
|
||||
let mut args = [0i64; 8];
|
||||
for (src, dest) in cpu.x[10..].iter().zip(args.iter_mut()) {
|
||||
*dest = *src;
|
||||
}
|
||||
let result = handler.handle_event(cpu, args);
|
||||
for (src, dest) in result.iter().zip(cpu.x[10..].iter_mut()) {
|
||||
*dest = *src;
|
||||
}
|
||||
cpu.handler = Some(handler);
|
||||
return Ok(());
|
||||
operation: |cpu, _word, _address| {
|
||||
let mut args = [0i64; 8];
|
||||
for (src, dest) in cpu.x[10..].iter().zip(args.iter_mut()) {
|
||||
*dest = *src;
|
||||
}
|
||||
let result = cpu.memory.write().unwrap().syscall(args);
|
||||
for (src, dest) in result.iter().zip(cpu.x[10..].iter_mut()) {
|
||||
*dest = *src;
|
||||
}
|
||||
Ok(())
|
||||
|
||||
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"),
|
||||
};
|
||||
Err(Trap {
|
||||
trap_type: exception_type,
|
||||
value: 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"),
|
||||
// };
|
||||
// Err(Trap {
|
||||
// trap_type: exception_type,
|
||||
// value: address,
|
||||
// })
|
||||
},
|
||||
disassemble: dump_empty,
|
||||
},
|
||||
@ -3102,7 +3058,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
||||
let status = cpu.read_csr_raw(CSR_MSTATUS_ADDRESS);
|
||||
let mpie = (status >> 7) & 1;
|
||||
let mpp = (status >> 11) & 0x3;
|
||||
let mprv = match get_privilege_mode(mpp) {
|
||||
let mprv = match decode_privilege_mode(mpp) {
|
||||
PrivilegeMode::Machine => (status >> 17) & 1,
|
||||
_ => 0,
|
||||
};
|
||||
@ -3470,7 +3426,7 @@ const INSTRUCTIONS: [Instruction; INSTRUCTION_NUM] = [
|
||||
let status = cpu.read_csr_raw(CSR_SSTATUS_ADDRESS);
|
||||
let spie = (status >> 5) & 1;
|
||||
let spp = (status >> 8) & 1;
|
||||
let mprv = match get_privilege_mode(spp) {
|
||||
let mprv = match decode_privilege_mode(spp) {
|
||||
PrivilegeMode::Machine => (status >> 17) & 1,
|
||||
_ => 0,
|
||||
};
|
||||
|
@ -1,10 +1,23 @@
|
||||
use std::{collections::HashMap, num::NonZeroU64};
|
||||
|
||||
use crate::{
|
||||
cpu::{get_privilege_mode, PrivilegeMode, Trap, TrapType, Xlen},
|
||||
memory::Memory,
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use crate::cpu::{decode_privilege_mode, PrivilegeMode, Trap, TrapType, Xlen};
|
||||
|
||||
pub trait Memory {
|
||||
fn read_u8(&self, p_address: u64) -> u8;
|
||||
fn read_u16(&self, p_address: u64) -> u16;
|
||||
fn read_u32(&self, p_address: u64) -> u32;
|
||||
fn read_u64(&self, p_address: u64) -> u64;
|
||||
fn write_u8(&mut self, p_address: u64, value: u8);
|
||||
fn write_u16(&mut self, p_address: u64, value: u16);
|
||||
fn write_u32(&mut self, p_address: u64, value: u32);
|
||||
fn write_u64(&mut self, p_address: u64, value: u64);
|
||||
fn validate_address(&self, address: u64) -> bool;
|
||||
fn syscall(&mut self, args: [i64; 8]) -> [i64; 8];
|
||||
}
|
||||
|
||||
/// Emulates Memory Management Unit. It holds the Main memory and peripheral
|
||||
/// devices, maps address to them, and accesses them depending on address.
|
||||
/// It also manages virtual-physical address translation and memoty protection.
|
||||
@ -16,11 +29,10 @@ pub struct Mmu {
|
||||
ppn: u64,
|
||||
addressing_mode: AddressingMode,
|
||||
privilege_mode: PrivilegeMode,
|
||||
memory: MemoryWrapper,
|
||||
|
||||
/// The size of main memory (if initialized)
|
||||
memory_length: Option<NonZeroU64>,
|
||||
memory: Arc<RwLock<dyn Memory + Send + Sync>>,
|
||||
|
||||
// /// The size of main memory (if initialized)
|
||||
// memory_length: Option<NonZeroU64>,
|
||||
/// Address translation can be affected `mstatus` (MPRV, MPP in machine mode)
|
||||
/// then `Mmu` has copy of it.
|
||||
mstatus: u64,
|
||||
@ -71,27 +83,19 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `xlen`
|
||||
/// * `terminal`
|
||||
pub fn new(xlen: Xlen, dram_base: u64) -> Self {
|
||||
// // Load default device tree binary content
|
||||
// let content = include_bytes!("./device/dtb.dtb");
|
||||
// for i in 0..content.len() {
|
||||
// dtb[i] = content[i];
|
||||
// }
|
||||
|
||||
pub fn new(xlen: Xlen, memory: Arc<RwLock<dyn Memory + Send + Sync>>) -> Self {
|
||||
Mmu {
|
||||
// clock: 0,
|
||||
xlen,
|
||||
ppn: 0,
|
||||
addressing_mode: AddressingMode::None,
|
||||
privilege_mode: PrivilegeMode::Machine,
|
||||
memory: MemoryWrapper::new(dram_base),
|
||||
memory,
|
||||
mstatus: 0,
|
||||
page_cache_enabled: false,
|
||||
fetch_page_cache: HashMap::default(),
|
||||
load_page_cache: HashMap::default(),
|
||||
store_page_cache: HashMap::default(),
|
||||
memory_length: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,19 +108,19 @@ impl Mmu {
|
||||
self.clear_page_cache();
|
||||
}
|
||||
|
||||
/// Initializes Main memory. This method is expected to be called only once.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `capacity`
|
||||
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);
|
||||
}
|
||||
// /// Initializes Main memory. This method is expected to be called only once.
|
||||
// ///
|
||||
// /// # Arguments
|
||||
// /// * `capacity`
|
||||
// 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);
|
||||
// }
|
||||
|
||||
pub fn memory_size(&self) -> u64 {
|
||||
self.memory_length.unwrap().get()
|
||||
}
|
||||
// pub fn memory_size(&self) -> u64 {
|
||||
// self.memory_length.unwrap().get()
|
||||
// }
|
||||
|
||||
/// Enables or disables page cache optimization.
|
||||
///
|
||||
@ -185,7 +189,7 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
fn fetch(&mut self, v_address: u64) -> Result<u8, Trap> {
|
||||
fn fetch(&self, v_address: u64) -> Result<u8, Trap> {
|
||||
self.translate_address(v_address, &MemoryAccessType::Execute)
|
||||
.map(|p_address| self.load_raw(p_address))
|
||||
.map_err(|()| Trap {
|
||||
@ -199,7 +203,7 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
pub fn fetch_word(&mut self, v_address: u64) -> Result<u32, Trap> {
|
||||
pub fn fetch_word(&self, v_address: u64) -> Result<u32, Trap> {
|
||||
let width = 4;
|
||||
if (v_address & 0xfff) <= (0x1000 - width) {
|
||||
// Fast path. All bytes fetched are in the same page so
|
||||
@ -228,7 +232,7 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
pub fn load(&mut self, v_address: u64) -> Result<u8, Trap> {
|
||||
pub fn load(&self, v_address: u64) -> Result<u8, Trap> {
|
||||
let effective_address = self.trim_to_xlen(v_address);
|
||||
match self.translate_address(effective_address, &MemoryAccessType::Read) {
|
||||
Ok(p_address) => Ok(self.load_raw(p_address)),
|
||||
@ -245,7 +249,7 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
/// * `width` Must be 1, 2, 4, or 8
|
||||
fn load_bytes(&mut self, v_address: u64, width: u64) -> Result<u64, Trap> {
|
||||
fn load_bytes(&self, v_address: u64, width: u64) -> Result<u64, Trap> {
|
||||
debug_assert!(
|
||||
width == 1 || width == 2 || width == 4 || width == 8,
|
||||
"Width must be 1, 2, 4, or 8. {:X}",
|
||||
@ -287,7 +291,7 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
pub fn load_halfword(&mut self, v_address: u64) -> Result<u16, Trap> {
|
||||
pub fn load_halfword(&self, v_address: u64) -> Result<u16, Trap> {
|
||||
self.load_bytes(v_address, 2).map(|data| data as u16)
|
||||
}
|
||||
|
||||
@ -296,7 +300,7 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
pub fn load_word(&mut self, v_address: u64) -> Result<u32, Trap> {
|
||||
pub fn load_word(&self, v_address: u64) -> Result<u32, Trap> {
|
||||
self.load_bytes(v_address, 4).map(|data| data as u32)
|
||||
}
|
||||
|
||||
@ -305,7 +309,7 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
pub fn load_doubleword(&mut self, v_address: u64) -> Result<u64, Trap> {
|
||||
pub fn load_doubleword(&self, v_address: u64) -> Result<u64, Trap> {
|
||||
self.load_bytes(v_address, 8)
|
||||
}
|
||||
|
||||
@ -315,7 +319,7 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
/// * `value`
|
||||
pub fn store(&mut self, v_address: u64, value: u8) -> Result<(), Trap> {
|
||||
pub fn store(&self, v_address: u64, value: u8) -> Result<(), Trap> {
|
||||
self.translate_address(v_address, &MemoryAccessType::Write)
|
||||
.map(|p_address| self.store_raw(p_address, value))
|
||||
.map_err(|()| Trap {
|
||||
@ -331,7 +335,7 @@ impl Mmu {
|
||||
/// * `v_address` Virtual address
|
||||
/// * `value` data written
|
||||
/// * `width` Must be 1, 2, 4, or 8
|
||||
fn store_bytes(&mut self, v_address: u64, value: u64, width: u64) -> Result<(), Trap> {
|
||||
fn store_bytes(&self, v_address: u64, value: u64, width: u64) -> Result<(), Trap> {
|
||||
debug_assert!(
|
||||
width == 1 || width == 2 || width == 4 || width == 8,
|
||||
"Width must be 1, 2, 4, or 8. {:X}",
|
||||
@ -374,7 +378,7 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
/// * `value` data written
|
||||
pub fn store_halfword(&mut self, v_address: u64, value: u16) -> Result<(), Trap> {
|
||||
pub fn store_halfword(&self, v_address: u64, value: u16) -> Result<(), Trap> {
|
||||
self.store_bytes(v_address, value as u64, 2)
|
||||
}
|
||||
|
||||
@ -384,7 +388,7 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
/// * `value` data written
|
||||
pub fn store_word(&mut self, v_address: u64, value: u32) -> Result<(), Trap> {
|
||||
pub fn store_word(&self, v_address: u64, value: u32) -> Result<(), Trap> {
|
||||
self.store_bytes(v_address, value as u64, 4)
|
||||
}
|
||||
|
||||
@ -394,7 +398,7 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
/// * `value` data written
|
||||
pub fn store_doubleword(&mut self, v_address: u64, value: u64) -> Result<(), Trap> {
|
||||
pub fn store_doubleword(&self, v_address: u64, value: u64) -> Result<(), Trap> {
|
||||
self.store_bytes(v_address, value, 8)
|
||||
}
|
||||
|
||||
@ -404,7 +408,10 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
pub(crate) fn load_raw(&self, p_address: u64) -> u8 {
|
||||
self.memory.read_byte(self.trim_to_xlen(p_address))
|
||||
self.memory
|
||||
.read()
|
||||
.unwrap()
|
||||
.read_u8(self.trim_to_xlen(p_address))
|
||||
}
|
||||
|
||||
/// Loads two bytes from main memory or peripheral devices depending on
|
||||
@ -413,7 +420,10 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
fn load_halfword_raw(&self, p_address: u64) -> u16 {
|
||||
self.memory.read_halfword(self.trim_to_xlen(p_address))
|
||||
self.memory
|
||||
.read()
|
||||
.unwrap()
|
||||
.read_u16(self.trim_to_xlen(p_address))
|
||||
}
|
||||
|
||||
/// Loads four bytes from main memory or peripheral devices depending on
|
||||
@ -422,7 +432,10 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
pub fn load_word_raw(&self, p_address: u64) -> u32 {
|
||||
self.memory.read_word(self.trim_to_xlen(p_address))
|
||||
self.memory
|
||||
.read()
|
||||
.unwrap()
|
||||
.read_u32(self.trim_to_xlen(p_address))
|
||||
}
|
||||
|
||||
/// Loads eight bytes from main memory or peripheral devices depending on
|
||||
@ -431,7 +444,10 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
fn load_doubleword_raw(&self, p_address: u64) -> u64 {
|
||||
self.memory.read_doubleword(self.trim_to_xlen(p_address))
|
||||
self.memory
|
||||
.read()
|
||||
.unwrap()
|
||||
.read_u64(self.trim_to_xlen(p_address))
|
||||
}
|
||||
|
||||
/// Stores a byte to main memory or peripheral devices depending on
|
||||
@ -440,8 +456,11 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
/// * `value` data written
|
||||
pub(crate) fn store_raw(&mut self, p_address: u64, value: u8) {
|
||||
self.memory.write_byte(self.trim_to_xlen(p_address), value)
|
||||
pub(crate) fn store_raw(&self, p_address: u64, value: u8) {
|
||||
self.memory
|
||||
.write()
|
||||
.unwrap()
|
||||
.write_u8(self.trim_to_xlen(p_address), value)
|
||||
}
|
||||
|
||||
/// Stores two bytes to main memory or peripheral devices depending on
|
||||
@ -450,9 +469,11 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
/// * `value` data written
|
||||
pub(crate) fn store_halfword_raw(&mut self, p_address: u64, value: u16) {
|
||||
pub(crate) fn store_halfword_raw(&self, p_address: u64, value: u16) {
|
||||
self.memory
|
||||
.write_halfword(self.trim_to_xlen(p_address), value)
|
||||
.write()
|
||||
.unwrap()
|
||||
.write_u16(self.trim_to_xlen(p_address), value)
|
||||
}
|
||||
|
||||
/// Stores four bytes to main memory or peripheral devices depending on
|
||||
@ -461,8 +482,11 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
/// * `value` data written
|
||||
pub(crate) fn store_word_raw(&mut self, p_address: u64, value: u32) {
|
||||
self.memory.write_word(self.trim_to_xlen(p_address), value)
|
||||
pub(crate) fn store_word_raw(&self, p_address: u64, value: u32) {
|
||||
self.memory
|
||||
.write()
|
||||
.unwrap()
|
||||
.write_u32(self.trim_to_xlen(p_address), value)
|
||||
}
|
||||
|
||||
/// Stores eight bytes to main memory or peripheral devices depending on
|
||||
@ -471,9 +495,11 @@ impl Mmu {
|
||||
/// # Arguments
|
||||
/// * `p_address` Physical address
|
||||
/// * `value` data written
|
||||
fn store_doubleword_raw(&mut self, p_address: u64, value: u64) {
|
||||
fn store_doubleword_raw(&self, p_address: u64, value: u64) {
|
||||
self.memory
|
||||
.write_doubleword(self.trim_to_xlen(p_address), value)
|
||||
.write()
|
||||
.unwrap()
|
||||
.write_u64(self.trim_to_xlen(p_address), value)
|
||||
}
|
||||
|
||||
/// Checks if passed virtual address is valid (pointing a certain device) or not.
|
||||
@ -481,18 +507,26 @@ impl Mmu {
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v_address` Virtual address
|
||||
pub fn validate_address(&mut self, v_address: u64) -> Option<bool> {
|
||||
if let Ok(p_address) = self.translate_address(v_address, &MemoryAccessType::DontCare) {
|
||||
Some(self.memory.validate_address(self.trim_to_xlen(p_address)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
pub fn validate_address(&self, v_address: u64) -> Option<bool> {
|
||||
self.translate_address(v_address, &MemoryAccessType::DontCare)
|
||||
.ok()
|
||||
.map(|p_address| {
|
||||
self.memory
|
||||
.write()
|
||||
.unwrap()
|
||||
.validate_address(self.trim_to_xlen(p_address))
|
||||
})
|
||||
}
|
||||
|
||||
fn translate_address(
|
||||
&mut self,
|
||||
fn translate_address(&self, v_address: u64, access_type: &MemoryAccessType) -> Result<u64, ()> {
|
||||
self.translate_address_with_privilege_mode(v_address, access_type, self.privilege_mode)
|
||||
}
|
||||
|
||||
fn translate_address_with_privilege_mode(
|
||||
&self,
|
||||
v_address: u64,
|
||||
access_type: &MemoryAccessType,
|
||||
privilege_mode: PrivilegeMode,
|
||||
) -> Result<u64, ()> {
|
||||
let address = self.trim_to_xlen(v_address);
|
||||
let v_page = address & !0xfff;
|
||||
@ -510,28 +544,24 @@ impl Mmu {
|
||||
|
||||
let p_address = match self.addressing_mode {
|
||||
AddressingMode::None => Ok(address),
|
||||
AddressingMode::SV32 => match self.privilege_mode {
|
||||
AddressingMode::SV32 => match privilege_mode {
|
||||
// @TODO: Optimize
|
||||
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::Machine => {
|
||||
if let MemoryAccessType::Execute = access_type {
|
||||
Ok(address)
|
||||
} else if (self.mstatus >> 17) & 1 == 0 {
|
||||
Ok(address)
|
||||
} else {
|
||||
match decode_privilege_mode((self.mstatus >> 9) & 3) {
|
||||
PrivilegeMode::Machine => Ok(address),
|
||||
temp_privilege_mode => self.translate_address_with_privilege_mode(
|
||||
v_address,
|
||||
access_type,
|
||||
temp_privilege_mode,
|
||||
),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
PrivilegeMode::User | PrivilegeMode::Supervisor => {
|
||||
let vpns = [(address >> 12) & 0x3ff, (address >> 22) & 0x3ff];
|
||||
self.traverse_page(address, 2 - 1, self.ppn, &vpns, access_type)
|
||||
@ -541,26 +571,22 @@ impl Mmu {
|
||||
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::Machine => {
|
||||
if let MemoryAccessType::Execute = access_type {
|
||||
Ok(address)
|
||||
} else if (self.mstatus >> 17) & 1 == 0 {
|
||||
Ok(address)
|
||||
} else {
|
||||
match decode_privilege_mode((self.mstatus >> 9) & 3) {
|
||||
PrivilegeMode::Machine => Ok(address),
|
||||
temp_privilege_mode => self.translate_address_with_privilege_mode(
|
||||
v_address,
|
||||
access_type,
|
||||
temp_privilege_mode,
|
||||
),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
PrivilegeMode::User | PrivilegeMode::Supervisor => {
|
||||
let vpns = [
|
||||
(address >> 12) & 0x1ff,
|
||||
@ -576,27 +602,27 @@ impl Mmu {
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
// 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
|
||||
// }
|
||||
}
|
||||
|
||||
fn traverse_page(
|
||||
&mut self,
|
||||
&self,
|
||||
v_address: u64,
|
||||
level: u8,
|
||||
parent_ppn: u64,
|
||||
@ -724,98 +750,98 @@ impl Mmu {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MemoryWrapper {
|
||||
memory: Memory,
|
||||
dram_base: u64,
|
||||
}
|
||||
// pub struct MemoryWrapper {
|
||||
// memory: Memory,
|
||||
// dram_base: u64,
|
||||
// }
|
||||
|
||||
impl MemoryWrapper {
|
||||
fn new(dram_base: u64) -> Self {
|
||||
MemoryWrapper {
|
||||
memory: Memory::new(),
|
||||
dram_base,
|
||||
}
|
||||
}
|
||||
// impl MemoryWrapper {
|
||||
// fn new(dram_base: u64) -> Self {
|
||||
// MemoryWrapper {
|
||||
// memory: Memory::new(),
|
||||
// dram_base,
|
||||
// }
|
||||
// }
|
||||
|
||||
fn init(&mut self, capacity: u64) {
|
||||
self.memory.init(capacity);
|
||||
}
|
||||
// fn init(&mut self, capacity: u64) {
|
||||
// self.memory.init(capacity);
|
||||
// }
|
||||
|
||||
pub fn read_byte(&self, p_address: u64) -> u8 {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory.read_byte(p_address - self.dram_base)
|
||||
}
|
||||
// pub fn read_byte(&self, p_address: u64) -> u8 {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory.read_byte(p_address - self.dram_base)
|
||||
// }
|
||||
|
||||
pub fn read_halfword(&self, p_address: u64) -> u16 {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory.read_halfword(p_address - self.dram_base)
|
||||
}
|
||||
// pub fn read_halfword(&self, p_address: u64) -> u16 {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory.read_halfword(p_address - self.dram_base)
|
||||
// }
|
||||
|
||||
pub fn read_word(&self, p_address: u64) -> u32 {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory.read_word(p_address - self.dram_base)
|
||||
}
|
||||
// pub fn read_word(&self, p_address: u64) -> u32 {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory.read_word(p_address - self.dram_base)
|
||||
// }
|
||||
|
||||
pub fn read_doubleword(&self, p_address: u64) -> u64 {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory.read_doubleword(p_address - self.dram_base)
|
||||
}
|
||||
// pub fn read_doubleword(&self, p_address: u64) -> u64 {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory.read_doubleword(p_address - self.dram_base)
|
||||
// }
|
||||
|
||||
pub fn write_byte(&mut self, p_address: u64, value: u8) {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory.write_byte(p_address - self.dram_base, value)
|
||||
}
|
||||
// pub fn write_byte(&mut self, p_address: u64, value: u8) {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory.write_byte(p_address - self.dram_base, value)
|
||||
// }
|
||||
|
||||
pub fn write_halfword(&mut self, p_address: u64, value: u16) {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory
|
||||
.write_halfword(p_address - self.dram_base, value)
|
||||
}
|
||||
// pub fn write_halfword(&mut self, p_address: u64, value: u16) {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base && p_address.wrapping_add(1) >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory
|
||||
// .write_halfword(p_address - self.dram_base, value)
|
||||
// }
|
||||
|
||||
pub fn write_word(&mut self, p_address: u64, value: u32) {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory.write_word(p_address - self.dram_base, value)
|
||||
}
|
||||
// pub fn write_word(&mut self, p_address: u64, value: u32) {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base && p_address.wrapping_add(3) >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory.write_word(p_address - self.dram_base, value)
|
||||
// }
|
||||
|
||||
pub fn write_doubleword(&mut self, p_address: u64, value: u64) {
|
||||
debug_assert!(
|
||||
p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
||||
"Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
p_address
|
||||
);
|
||||
self.memory
|
||||
.write_doubleword(p_address - self.dram_base, value)
|
||||
}
|
||||
// pub fn write_doubleword(&mut self, p_address: u64, value: u64) {
|
||||
// debug_assert!(
|
||||
// p_address >= self.dram_base && p_address.wrapping_add(7) >= self.dram_base,
|
||||
// "Memory address must equals to or bigger than self.dram_base. {:X}",
|
||||
// p_address
|
||||
// );
|
||||
// self.memory
|
||||
// .write_doubleword(p_address - self.dram_base, value)
|
||||
// }
|
||||
|
||||
pub fn validate_address(&self, address: u64) -> bool {
|
||||
self.memory.validate_address(address - self.dram_base)
|
||||
}
|
||||
}
|
||||
// pub fn validate_address(&self, address: u64) -> bool {
|
||||
// self.memory.validate_address(address - self.dram_base)
|
||||
// }
|
||||
// }
|
||||
|
Reference in New Issue
Block a user