(BIG CHANGE) memory handling has changed, MMIO is now a 2 level page table, misaligned access supported, addresses not internally split to page and offset immediately, all load/store instructions implemented. Might still have bugs

This commit is contained in:
2025-12-26 14:20:27 +01:00
parent 6d9efb7eb8
commit 528b519ce9
9 changed files with 478 additions and 456 deletions

View File

@@ -12,10 +12,10 @@ The emulator will load a raw binary image or static ELF executable from a file s
which starts at 0x80000000 and is currently 16MiB, which starts at 0x80000000 and is currently 16MiB,
and start execution at the start of the image/ram or the ELF entry point. and start execution at the start of the image/ram or the ELF entry point.
There is also a debug out page starting at `0x00000000`-`0x00001000`. There is also a debug out section at `0x00000000`-`0x00010000`.
Anything written to it will be logged out in hex. Anything written to it will be logged out in hex.
There is also a UART at `0x00001000`-`0x00002000`, the interface is quite simple: There is also a UART at `0x00010000`-`0x00010002`, the interface is quite simple:
- byte `0`: Data. When written, writes out the character - byte `0`: Data. When written, writes out the character
When read, reads a character from the buffer, or 0 if empty. When read, reads a character from the buffer, or 0 if empty.
- byte `1`: Status. Read-only. Least significant bit is `TX_READY` and indicates whether - byte `1`: Status. Read-only. Least significant bit is `TX_READY` and indicates whether

2
echo.S
View File

@@ -7,7 +7,7 @@
.equ UART_TX_READY, 0b01 .equ UART_TX_READY, 0b01
_start: _start:
li a0, 0x1000 li a0, 0x10000
loop: loop:
lbu t0, UART_STATUS(a0) lbu t0, UART_STATUS(a0)

View File

@@ -13,9 +13,9 @@ use std::time::Duration;
use nix::fcntl::fcntl; use nix::fcntl::fcntl;
use nix::fcntl::{FcntlArg, OFlag}; use nix::fcntl::{FcntlArg, OFlag};
use trve::consts::{Byte, DWord, HWord, Word}; use trve::consts::{Addr, Byte};
use trve::exceptions::ExceptionType; use trve::exceptions::MemoryExceptionType;
use trve::mem::{MemDeviceInterface, PageNum}; use trve::mem::MemDeviceInterface;
/// byte 0: rx/tx /// byte 0: rx/tx
/// byte 1: status (------rt, r=rxready, t=txready)/none /// byte 1: status (------rt, r=rxready, t=txready)/none
@@ -78,79 +78,20 @@ impl BasicUart {
} }
impl MemDeviceInterface for BasicUart { impl MemDeviceInterface for BasicUart {
fn write_dword( fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> {
&self, match addr {
_page: PageNum,
_offset: u16,
_value: DWord,
) -> Result<(), ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
fn write_word(&self, _page: PageNum, _offset: u16, _value: Word) -> Result<(), ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
fn write_hword(
&self,
_page: PageNum,
_offset: u16,
_value: HWord,
) -> Result<(), ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
if page > 0 {
return Err(ExceptionType::StoreAmoAccessFault);
}
match offset {
0 => { 0 => {
self.write(value); self.write(value);
Ok(()) Ok(())
} }
_ => Err(ExceptionType::StoreAmoAccessFault), _ => Err(MemoryExceptionType::AccessFault),
} }
} }
fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> {
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, ExceptionType> { match addr {
Err(ExceptionType::LoadAccessFault)
}
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, ExceptionType> {
Err(ExceptionType::LoadAccessFault)
}
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, ExceptionType> {
Err(ExceptionType::LoadAccessFault)
}
fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType> {
if page > 0 {
return Err(ExceptionType::LoadAccessFault);
}
match offset {
0 => Ok(self.read()), 0 => Ok(self.read()),
1 => Ok(1 | (self.can_read() as u8) << 1), 1 => Ok(1 | (self.can_read() as u8) << 1),
_ => Err(ExceptionType::LoadAccessFault), _ => Err(MemoryExceptionType::AccessFault),
} }
} }
fn get_atomic_word(
&self,
_page: PageNum,
_offset: u16,
) -> Result<&std::sync::atomic::AtomicU32, ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
fn get_atomic_dword(
&self,
_page: PageNum,
_offset: u16,
) -> Result<&std::sync::atomic::AtomicU64, ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
} }

View File

@@ -4,6 +4,8 @@
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve) // This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
// See LICENSE file in the project root for full license text. // See LICENSE file in the project root for full license text.
use std::fmt::format;
use crate::{ use crate::{
consts::{Addr, RegId, RegValue}, consts::{Addr, RegId, RegValue},
decode::Instruction, decode::Instruction,
@@ -29,17 +31,15 @@ impl Core {
pub fn run(&mut self) { pub fn run(&mut self) {
loop { loop {
let page = (self.pc / 4096) as usize;
let offset = (self.pc % 4096 / 4) as u16;
if !self.pc.is_multiple_of(4) { if !self.pc.is_multiple_of(4) {
self.throw_exception(ExceptionType::InstructionAccessMisaligned); self.throw_exception(ExceptionType::InstructionAddressMisaligned);
break; break;
} }
let instr = match self.mem.read_word(page, offset) { let instr = match self.mem.read_word(self.pc) {
Ok(i) => i, Ok(i) => i,
Err(_) => { Err(e) => {
self.throw_exception(ExceptionType::InstructionAccessFault); self.throw_exception(e.to_exception_instr());
break; break;
} }
}; };

View File

@@ -10,7 +10,7 @@ use int_enum::IntEnum;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)] #[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)]
pub enum ExceptionType { pub enum ExceptionType {
InstructionAccessMisaligned = 0, InstructionAddressMisaligned = 0,
InstructionAccessFault = 1, InstructionAccessFault = 1,
IllegalInstruction = 2, IllegalInstruction = 2,
Breakpoint = 3, Breakpoint = 3,
@@ -28,3 +28,35 @@ pub enum ExceptionType {
SoftwareCheck = 18, SoftwareCheck = 18,
HardwareError = 19, HardwareError = 19,
} }
pub enum MemoryExceptionType {
AddressMisaligned,
AccessFault,
PageFault,
}
impl MemoryExceptionType {
pub(crate) fn to_exception_store(&self) -> ExceptionType {
match self {
Self::AddressMisaligned => ExceptionType::StoreAmoAddressMisaligned,
Self::AccessFault => ExceptionType::StoreAmoAccessFault,
Self::PageFault => ExceptionType::StoreAmoPageFault,
}
}
pub(crate) fn to_exception_instr(&self) -> ExceptionType {
match self {
Self::AddressMisaligned => ExceptionType::InstructionAddressMisaligned,
Self::AccessFault => ExceptionType::InstructionAccessFault,
Self::PageFault => ExceptionType::InstructionPageFault,
}
}
pub(crate) fn to_exception_load(&self) -> ExceptionType {
match self {
Self::AddressMisaligned => ExceptionType::LoadAddressMisaligned,
Self::AccessFault => ExceptionType::LoadAccessFault,
Self::PageFault => ExceptionType::LoadPageFault,
}
}
}

View File

@@ -58,7 +58,9 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
0b000 => rvi::lb(core, instr), 0b000 => rvi::lb(core, instr),
0b100 => rvi::lbu(core, instr), 0b100 => rvi::lbu(core, instr),
0b001 => rvi::lh(core, instr), 0b001 => rvi::lh(core, instr),
0b101 => rvi::lhu(core, instr),
0b010 => rvi::lw(core, instr), 0b010 => rvi::lw(core, instr),
0b110 => rvi::lwu(core, instr),
0b011 => rvi::ld(core, instr), 0b011 => rvi::ld(core, instr),
_ => Err(IllegalInstruction), _ => Err(IllegalInstruction),
}, },
@@ -74,7 +76,6 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
0b01101 => rvi::lui(core, instr), 0b01101 => rvi::lui(core, instr),
0b00101 => rvi::auipc(core, instr), 0b00101 => rvi::auipc(core, instr),
0b11011 => rvi::jal(core, instr), 0b11011 => rvi::jal(core, instr),
// 0b11001 => (instr.funct3() == 0).then(|| rvi::jalr(core, instr)),
0b11001 => { 0b11001 => {
if instr.funct3() == 0 { if instr.funct3() == 0 {
rvi::jalr(core, instr) rvi::jalr(core, instr)

View File

@@ -5,75 +5,63 @@
// See LICENSE file in the project root for full license text. // See LICENSE file in the project root for full license text.
use crate::{ use crate::{
consts::{Addr, Byte, DWord, HWord, Word}, consts::{Byte, DWord, HWord, Word},
core::Core, core::Core,
exceptions::ExceptionType, exceptions::ExceptionType,
instructions::Instruction, instructions::Instruction,
mem::PageNum,
}; };
// TODO: Support misaligned memory access
pub fn sd(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sd(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s());
if !addr.is_multiple_of(std::mem::size_of::<DWord>() as Addr) {
return Err(ExceptionType::StoreAmoAddressMisaligned);
}
let page = (addr / 4096) as PageNum;
let offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16;
let value = core.reg_read(instr.rs2()); let value = core.reg_read(instr.rs2());
core.mem
core.mem.write_dword(page, offset, value)?; .write_dword(addr, value)
.map_err(|e| e.to_exception_store())?;
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
} }
pub fn ld(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn ld(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
core.reg_write(
if !addr.is_multiple_of(std::mem::size_of::<DWord>() as Addr) { instr.rd(),
return Err(ExceptionType::LoadAddressMisaligned); core.mem
} .read_dword(addr)
.map_err(|e| e.to_exception_load())?,
let page = (addr / 4096) as PageNum; );
let offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16;
core.reg_write(instr.rd(), core.mem.read_dword(page, offset)?);
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
} }
pub fn sw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s());
if !addr.is_multiple_of(std::mem::size_of::<Word>() as Addr) {
return Err(ExceptionType::StoreAmoAddressMisaligned);
}
let page = (addr / 4096) as PageNum;
let offset = (addr / 4 & ((4096 / 4 as Addr) - 1)) as u16;
let value = core.reg_read(instr.rs2()) as Word; let value = core.reg_read(instr.rs2()) as Word;
core.mem
core.mem.write_word(page, offset, value)?; .write_word(addr, value)
.map_err(|e| e.to_exception_store())?;
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
} }
pub fn lw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
if !addr.is_multiple_of(std::mem::size_of::<Word>() as Addr) {
return Err(ExceptionType::LoadAddressMisaligned);
}
let page = (addr / 4096) as PageNum;
let offset = (addr / 4 & ((4096 / 4 as Addr) - 1)) as u16;
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.mem.read_word(page, offset)? as i32 as i64 as DWord, core.mem
.read_word(addr)
.map_err(|e| e.to_exception_load())? as i32 as i64 as DWord,
);
core.advance_pc();
Ok(())
}
pub fn lwu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
core.reg_write(
instr.rd(),
core.mem
.read_word(addr)
.map_err(|e| e.to_exception_load())? as DWord,
); );
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
@@ -81,33 +69,33 @@ pub fn lw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
pub fn sh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s());
if !addr.is_multiple_of(std::mem::size_of::<HWord>() as Addr) {
return Err(ExceptionType::StoreAmoAddressMisaligned);
}
let page = (addr / 4096) as PageNum;
let offset = (addr / 2 & ((4096 / 2 as Addr) - 1)) as u16;
let value = core.reg_read(instr.rs2()) as HWord; let value = core.reg_read(instr.rs2()) as HWord;
core.mem
core.mem.write_hword(page, offset, value)?; .write_hword(addr, value)
.map_err(|e| e.to_exception_store())?;
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
} }
pub fn lh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
if !addr.is_multiple_of(std::mem::size_of::<HWord>() as Addr) {
return Err(ExceptionType::LoadAddressMisaligned);
}
let page = (addr / 4096) as PageNum;
let offset = (addr / 2 & ((4096 / 2 as Addr) - 1)) as u16;
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.mem.read_hword(page, offset)? as i16 as i64 as DWord, core.mem
.read_hword(addr)
.map_err(|e| e.to_exception_load())? as i16 as i64 as DWord,
);
core.advance_pc();
Ok(())
}
pub fn lhu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
core.reg_write(
instr.rd(),
core.mem
.read_hword(addr)
.map_err(|e| e.to_exception_load())? as DWord,
); );
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
@@ -115,25 +103,21 @@ pub fn lh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
pub fn sb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_s());
let page = (addr / 4096) as PageNum;
let offset = (addr & (4096 as Addr - 1)) as u16;
let value = core.reg_read(instr.rs2()) as Byte; let value = core.reg_read(instr.rs2()) as Byte;
core.mem
core.mem.write_byte(page, offset, value)?; .write_byte(addr, value)
.map_err(|e| e.to_exception_store())?;
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
} }
pub fn lb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
let page = (addr / 4096) as PageNum;
let offset = (addr & (4096 as Addr - 1)) as u16;
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.mem.read_byte(page, offset)? as i8 as i64 as DWord, core.mem
.read_byte(addr)
.map_err(|e| e.to_exception_load())? as i8 as i64 as DWord,
); );
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
@@ -141,11 +125,12 @@ pub fn lb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
pub fn lbu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lbu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()); let addr = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
core.reg_write(
let page = (addr / 4096) as PageNum; instr.rd(),
let offset = (addr & (4096 as Addr - 1)) as u16; core.mem
.read_byte(addr)
core.reg_write(instr.rd(), core.mem.read_byte(page, offset)? as DWord); .map_err(|e| e.to_exception_load())? as DWord,
);
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
} }

View File

@@ -7,10 +7,10 @@
use std::{env, sync::Arc, time::Duration}; use std::{env, sync::Arc, time::Duration};
use trve::{ use trve::{
consts::{Byte, DWord, HWord, Word}, consts::{Addr, Byte, DWord, HWord, Word},
core::Core, core::Core,
exceptions::ExceptionType, exceptions::MemoryExceptionType,
mem::{DeviceEntry, MemConfig, MemDeviceInterface, PageNum, Ram}, mem::{MemConfig, MemDeviceInterface, MmioRoot, Ram},
}; };
use anyhow::{Result, bail}; use anyhow::{Result, bail};
@@ -20,7 +20,7 @@ use crate::basic_uart::BasicUart;
mod execload; mod execload;
fn main() -> Result<()> { fn main() -> Result<()> {
let mut ram = Ram::try_new(16 * 1024 * 1024 / 4096)?; let mut ram = Ram::try_new(16 * 1024 * 1024)?;
let buf = ram.buf_mut(); let buf = ram.buf_mut();
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
@@ -32,24 +32,16 @@ fn main() -> Result<()> {
let entry_point = execload::load(&args[1], buf, 0x8000_0000)?; let entry_point = execload::load(&args[1], buf, 0x8000_0000)?;
let mut mmio_root = MmioRoot::default();
mmio_root.insert(0, Arc::new(DbgOut));
let uart = BasicUart::new(); let uart = BasicUart::new();
let uart = uart.spawn_poller(Duration::from_millis(10)); let uart = uart.spawn_poller(Duration::from_millis(10));
mmio_root.insert(0x10000, uart);
let mem_cfg = MemConfig { let mem_cfg = MemConfig {
ram: Arc::new(ram), ram: Arc::new(ram),
ram_start: 0x8000_0000 / 4096, mmio_root,
devices: Box::new([
DeviceEntry {
base: 0,
size: 1,
interface: Arc::new(DbgOut),
},
DeviceEntry {
base: 1,
size: 1,
interface: uart,
},
]),
}; };
let mut core = Core::new(mem_cfg); let mut core = Core::new(mem_cfg);
@@ -64,64 +56,23 @@ mod basic_uart;
struct DbgOut; struct DbgOut;
impl MemDeviceInterface for DbgOut { impl MemDeviceInterface for DbgOut {
fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), ExceptionType> { fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> {
eprintln!( eprintln!("Wrote DWord {value:016x} to Debug-Out address {addr:x}");
"Wrote DWord {value:016x} to Debug-Out page {page}, offset {offset} (byte {})",
offset * 8
);
Ok(()) Ok(())
} }
fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> { fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> {
eprintln!( eprintln!("Wrote Word {value:08x} to Debug-Out address {addr:x}");
"Wrote Word {value:08x} to Debug-Out page {page}, offset {offset} (byte {})",
offset * 4
);
Ok(()) Ok(())
} }
fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), ExceptionType> { fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> {
eprintln!( eprintln!("Wrote HWord {value:04x} to Debug-Out address {addr:x}");
"Wrote HWord {value:04x} to Debug-Out page {page}, offset {offset} (byte {})",
offset * 2
);
Ok(()) Ok(())
} }
fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> { fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> {
eprintln!("Wrote Byte {value:02x} to Debug-Out page {page}, offset {offset}"); eprintln!("Wrote Byte {value:02x} to Debug-Out address {addr:x}");
Ok(()) Ok(())
} }
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, ExceptionType> {
Err(ExceptionType::LoadAccessFault)
}
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, ExceptionType> {
Err(ExceptionType::LoadAccessFault)
}
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, ExceptionType> {
Err(ExceptionType::LoadAccessFault)
}
fn read_byte(&self, _page: PageNum, _offset: u16) -> Result<Byte, ExceptionType> {
Err(ExceptionType::LoadAccessFault)
}
fn get_atomic_word(
&self,
_page: PageNum,
_offset: u16,
) -> Result<&std::sync::atomic::AtomicU32, ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
fn get_atomic_dword(
&self,
_page: PageNum,
_offset: u16,
) -> Result<&std::sync::atomic::AtomicU64, ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
} }

View File

@@ -12,184 +12,171 @@ use std::sync::{
use memmap2::MmapMut; use memmap2::MmapMut;
use crate::{ use crate::{
consts::{Byte, DWord, HWord, Word}, consts::{Addr, Byte, DWord, HWord, Word},
exceptions::ExceptionType, exceptions::MemoryExceptionType,
}; };
pub type PageNum = usize; pub type PageNum = usize;
const PAGE_SIZE: usize = 4096; pub const RAM_START: Addr = 0x8000_0000;
#[derive(Clone)] #[derive(Clone)]
pub struct MemConfig { pub struct MemConfig {
pub ram: Arc<Ram>, pub ram: Arc<Ram>,
pub ram_start: PageNum, pub mmio_root: MmioRoot,
pub devices: Box<[DeviceEntry]>,
} }
impl MemConfig { impl MemConfig {
#[allow(clippy::needless_borrow)] pub fn memory_mapping_type(&self, addr: Addr) -> Option<MemoryMappingType> {
pub fn find_device_by_page(&self, page: PageNum) -> Option<&DeviceEntry> { if addr >= RAM_START {
for entry in self.devices.iter() {
if page_in_range(page, entry.base, entry.size) {
return Some(&entry);
}
}
None
}
pub fn memory_mapping_type(&self, page: PageNum) -> Option<MemoryMappingType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
Some(MemoryMappingType::RAM) Some(MemoryMappingType::RAM)
} else { } else {
self.find_device_by_page(page) self.mmio_root
.map(|_x| MemoryMappingType::MMIO) .get_device(addr)
.map(|_| MemoryMappingType::MMIO)
} }
} }
pub fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, ExceptionType> { pub fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if addr >= RAM_START {
self.ram.read_dword(page - self.ram_start, offset) self.ram.read_dword(addr - RAM_START)
} else { } else {
let entry = self if !addr.is_multiple_of(8) && self.mmio_root.crosses_boundary(addr, 8) {
.find_device_by_page(page) return Err(MemoryExceptionType::AddressMisaligned);
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_dword(page - entry.base, offset)
}
}
pub fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.read_word(page - self.ram_start, offset)
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_word(page - entry.base, offset)
}
}
pub fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.read_hword(page - self.ram_start, offset)
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_hword(page - entry.base, offset)
}
}
pub fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.read_byte(page - self.ram_start, offset)
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_byte(page - entry.base, offset)
}
}
pub fn write_dword(
&self,
page: PageNum,
offset: u16,
value: DWord,
) -> Result<(), ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_dword(page - self.ram_start, offset, value)
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry
.interface
.write_dword(page - entry.base, offset, value)
}
}
pub fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_word(page - self.ram_start, offset, value)
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry.interface.write_word(page - entry.base, offset, value)
}
}
pub fn write_hword(
&self,
page: PageNum,
offset: u16,
value: HWord,
) -> Result<(), ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_hword(page - self.ram_start, offset, value)
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry
.interface
.write_hword(page - entry.base, offset, value)
}
}
pub fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_byte(page - self.ram_start, offset, value)
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry.interface.write_byte(page - entry.base, offset, value)
}
}
pub fn get_atomic_dword(
&self,
page: PageNum,
offset: u16,
) -> Result<&AtomicU64, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
debug_assert!(((offset * 8) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 8) + (offset as usize);
unsafe {
self.ram
.buf_transmuted::<AtomicU64>()
.get(index)
.ok_or(ExceptionType::HardwareError)
} }
} else { let (interface, addr) = self
let entry = self .mmio_root
.find_device_by_page(page) .get_device(addr)
.ok_or(ExceptionType::StoreAmoAccessFault)?; .ok_or(MemoryExceptionType::AccessFault)?;
entry.interface.get_atomic_dword(page - entry.base, offset)
}
}
pub fn get_atomic_word(&self, page: PageNum, offset: u16) -> Result<&AtomicU32, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) {
debug_assert!(((offset * 4) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 4) + (offset as usize);
unsafe {
self.ram
.buf_transmuted::<AtomicU32>()
.get(index)
.ok_or(ExceptionType::HardwareError)
}
} else {
let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry.interface.get_atomic_word(page - entry.base, offset)
}
}
}
fn page_in_range(page: PageNum, start: PageNum, pages: PageNum) -> bool { interface.read_dword(addr)
page >= start && page - start < pages }
}
pub fn read_word(&self, addr: Addr) -> Result<Word, MemoryExceptionType> {
if addr >= RAM_START {
self.ram.read_word(addr - RAM_START)
} else {
if !addr.is_multiple_of(4) && self.mmio_root.crosses_boundary(addr, 4) {
return Err(MemoryExceptionType::AddressMisaligned);
}
let (interface, addr) = self
.mmio_root
.get_device(addr)
.ok_or(MemoryExceptionType::AccessFault)?;
interface.read_word(addr)
}
}
pub fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryExceptionType> {
if addr >= RAM_START {
self.ram.read_hword(addr - RAM_START)
} else {
if !addr.is_multiple_of(2) && self.mmio_root.crosses_boundary(addr, 2) {
return Err(MemoryExceptionType::AddressMisaligned);
}
let (interface, addr) = self
.mmio_root
.get_device(addr)
.ok_or(MemoryExceptionType::AccessFault)?;
interface.read_hword(addr)
}
}
pub fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> {
if addr >= RAM_START {
self.ram.read_byte(addr - RAM_START)
} else {
let (interface, addr) = self
.mmio_root
.get_device(addr)
.ok_or(MemoryExceptionType::AccessFault)?;
interface.read_byte(addr)
}
}
pub fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> {
if addr >= RAM_START {
self.ram.write_dword(addr - RAM_START, value)
} else {
if !addr.is_multiple_of(8) && self.mmio_root.crosses_boundary(addr, 8) {
return Err(MemoryExceptionType::AddressMisaligned);
}
let (interface, addr) = self
.mmio_root
.get_device(addr)
.ok_or(MemoryExceptionType::AccessFault)?;
interface.write_dword(addr, value)
}
}
pub fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> {
if addr >= RAM_START {
self.ram.write_word(addr - RAM_START, value)
} else {
if !addr.is_multiple_of(4) && self.mmio_root.crosses_boundary(addr, 4) {
return Err(MemoryExceptionType::AddressMisaligned);
}
let (interface, addr) = self
.mmio_root
.get_device(addr)
.ok_or(MemoryExceptionType::AccessFault)?;
interface.write_word(addr, value)
}
}
pub fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> {
if addr >= RAM_START {
self.ram.write_hword(addr - RAM_START, value)
} else {
if !addr.is_multiple_of(2) && self.mmio_root.crosses_boundary(addr, 2) {
return Err(MemoryExceptionType::AddressMisaligned);
}
let (interface, addr) = self
.mmio_root
.get_device(addr)
.ok_or(MemoryExceptionType::AccessFault)?;
interface.write_hword(addr, value)
}
}
pub fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> {
if addr >= RAM_START {
self.ram.write_byte(addr - RAM_START, value)
} else {
let (interface, addr) = self
.mmio_root
.get_device(addr)
.ok_or(MemoryExceptionType::AccessFault)?;
interface.write_byte(addr, value)
}
}
pub fn get_atomic_dword(&self, addr: Addr) -> Result<&AtomicU64, MemoryExceptionType> {
if !addr.is_multiple_of(8) {
return Err(MemoryExceptionType::AddressMisaligned);
}
let index = ((addr - RAM_START) / 8) as usize;
unsafe {
self.ram
.buf_transmuted::<AtomicU64>()
.get(index)
.ok_or(MemoryExceptionType::AccessFault)
}
}
pub fn get_atomic_word(&self, addr: Addr) -> Result<&AtomicU32, MemoryExceptionType> {
if !addr.is_multiple_of(4) {
return Err(MemoryExceptionType::AddressMisaligned);
}
if addr < RAM_START {
return Err(MemoryExceptionType::AccessFault);
}
let index = ((addr - RAM_START) / 4) as usize;
unsafe {
self.ram
.buf_transmuted::<AtomicU32>()
.get(index)
.ok_or(MemoryExceptionType::AccessFault)
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -200,17 +187,15 @@ pub enum MemoryMappingType {
pub struct Ram { pub struct Ram {
buf: MmapMut, buf: MmapMut,
pages: PageNum,
} }
#[cfg(target_endian = "big")] #[cfg(target_endian = "big")]
compile_error!("Current RAM implementation requires a little-endian host."); compile_error!("Current RAM implementation requires a little-endian host.");
impl Ram { impl Ram {
pub fn try_new(pages: PageNum) -> Result<Self, std::io::Error> { pub fn try_new(size: usize) -> Result<Self, std::io::Error> {
Ok(Self { Ok(Self {
buf: MmapMut::map_anon(pages * PAGE_SIZE)?, buf: MmapMut::map_anon(size)?,
pages,
}) })
} }
@@ -218,10 +203,6 @@ impl Ram {
self.buf.as_mut() self.buf.as_mut()
} }
pub fn pages(&self) -> PageNum {
self.pages
}
/// # Safety /// # Safety
/// Safe if T has a size divisible by page size (4kb) (or is known to have a size divisible by the full ram size) and you know that the RAM is made up of valid naturally aligned values of T /// Safe if T has a size divisible by page size (4kb) (or is known to have a size divisible by the full ram size) and you know that the RAM is made up of valid naturally aligned values of T
#[inline] #[inline]
@@ -241,146 +222,277 @@ impl Ram {
} }
#[inline] #[inline]
pub fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, ExceptionType> { pub fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryExceptionType> {
debug_assert!(((offset * 8) as usize) < PAGE_SIZE); if !addr.is_multiple_of(8) {
let index = page * (PAGE_SIZE / 8) + (offset as usize); let high_word_addr = addr.wrapping_add(4);
let low_word = self.read_byte(addr)?;
let high_word = self.read_byte(high_word_addr)?;
return Ok((low_word as DWord) | (high_word as DWord) << 32);
}
let index = (addr / 8) as usize;
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU64>() self.buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(ExceptionType::LoadAccessFault) .ok_or(MemoryExceptionType::AccessFault)
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, ExceptionType> { pub fn read_word(&self, addr: Addr) -> Result<Word, MemoryExceptionType> {
debug_assert!(((offset * 4) as usize) < PAGE_SIZE); if !addr.is_multiple_of(4) {
let index = page * (PAGE_SIZE / 4) + (offset as usize); let high_hword_addr = addr.wrapping_add(2);
let low_hword = self.read_hword(addr)?;
let high_hword = self.read_hword(high_hword_addr)?;
return Ok((low_hword as Word) | (high_hword as Word) << 16);
}
let index = (addr / 4) as usize;
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU32>() self.buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(ExceptionType::LoadAccessFault) .ok_or(MemoryExceptionType::AccessFault)
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, ExceptionType> { pub fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryExceptionType> {
debug_assert!(((offset * 2) as usize) < PAGE_SIZE); if !addr.is_multiple_of(2) {
let index = page * (PAGE_SIZE / 2) + (offset as usize); let high_byte_addr = addr.wrapping_add(1);
let low_byte = self.read_byte(addr)?;
let high_byte = self.read_byte(high_byte_addr)?;
return Ok((low_byte as HWord) | (high_byte as HWord) << 8);
}
let index = (addr / 2) as usize;
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU16>() self.buf_transmuted::<AtomicU16>()
.get(index) .get(index)
.ok_or(ExceptionType::LoadAccessFault) .ok_or(MemoryExceptionType::AccessFault)
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType> { pub fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> {
debug_assert!((offset as usize) < PAGE_SIZE);
let index = page * PAGE_SIZE + (offset as usize);
Ok(self Ok(self
.buf_atomic() .buf_atomic()
.get(index) .get(addr as usize)
.ok_or(ExceptionType::LoadAccessFault)? .ok_or(MemoryExceptionType::AccessFault)?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn write_dword( pub fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> {
&self, if !addr.is_multiple_of(8) {
page: PageNum, let low_word = value as Word;
offset: u16, let high_word = (value >> 32) as Word;
value: DWord,
) -> Result<(), ExceptionType> { let high_word_address = addr.wrapping_add(4);
debug_assert!(((offset * 8) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 8) + (offset as usize); self.write_word(addr, low_word)?;
self.write_word(high_word_address, high_word)?;
return Ok(());
}
let index = (addr / 8) as usize;
unsafe { unsafe {
self.buf_transmuted::<AtomicU64>() self.buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(ExceptionType::StoreAmoAccessFault) .ok_or(MemoryExceptionType::AccessFault)
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> { pub fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> {
debug_assert!(((offset * 4) as usize) < PAGE_SIZE); if !addr.is_multiple_of(4) {
let index = page * (PAGE_SIZE / 4) + (offset as usize); let low_hword = value as HWord;
let high_hword = (value >> 16) as HWord;
let high_hword_address = addr.wrapping_add(2);
self.write_hword(addr, low_hword)?;
self.write_hword(high_hword_address, high_hword)?;
return Ok(());
}
let index = (addr / 4) as usize;
unsafe { unsafe {
self.buf_transmuted::<AtomicU32>() self.buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(ExceptionType::StoreAmoAccessFault) .ok_or(MemoryExceptionType::AccessFault)
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_hword( pub fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> {
&self, if !addr.is_multiple_of(2) {
page: PageNum, let low_byte = value as Byte;
offset: u16, let high_byte = (value >> 8) as Byte;
value: HWord,
) -> Result<(), ExceptionType> { let high_byte_address = addr.wrapping_add(1);
debug_assert!(((offset * 2) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 2) + (offset as usize); self.write_byte(addr, low_byte)?;
self.write_byte(high_byte_address, high_byte)?;
return Ok(());
}
let index = (addr / 2) as usize;
unsafe { unsafe {
self.buf_transmuted::<AtomicU16>() self.buf_transmuted::<AtomicU16>()
.get(index) .get(index)
.ok_or(ExceptionType::StoreAmoAccessFault) .ok_or(MemoryExceptionType::AccessFault)
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> { pub fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> {
debug_assert!((offset as usize) < PAGE_SIZE);
let index = page * PAGE_SIZE + (offset as usize);
self.buf_atomic() self.buf_atomic()
.get(index) .get(addr as usize)
.ok_or(ExceptionType::StoreAmoAccessFault)? .ok_or(MemoryExceptionType::AccessFault)?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
} }
pub const MMIO_SECOND_LEVEL_PAGE_SIZE: usize = 64 * 1024;
pub const MMIO_ROOT_PAGE_SIZE: usize = MMIO_SECOND_LEVEL_PAGE_SIZE * 64;
const MMIO_ROOT_ENTRIES: usize = RAM_START as usize / MMIO_ROOT_PAGE_SIZE;
const MMIO_SECOND_LEVEL_ENTRIES: usize = MMIO_ROOT_PAGE_SIZE / MMIO_SECOND_LEVEL_PAGE_SIZE;
#[derive(Clone)] #[derive(Clone)]
pub struct DeviceEntry { pub struct MmioRoot(Box<[Option<MmioSecondLevel>; MMIO_ROOT_ENTRIES]>);
pub base: PageNum,
pub size: PageNum, impl MmioRoot {
pub interface: Arc<dyn MemDeviceInterface>, pub fn insert(&mut self, base_addr: Addr, interface: Arc<dyn MemDeviceInterface>) {
assert!(base_addr.is_multiple_of(MMIO_SECOND_LEVEL_PAGE_SIZE as u64));
assert!(base_addr < RAM_START);
let page_id = base_addr as usize / MMIO_SECOND_LEVEL_PAGE_SIZE;
let root_page_id = page_id / MMIO_SECOND_LEVEL_ENTRIES;
let second_level_page_id = page_id % MMIO_SECOND_LEVEL_ENTRIES;
let second_level = self.0[root_page_id].get_or_insert_default();
if let MmioSecondLevel::SubTable(t) = second_level {
t[second_level_page_id] = Some(interface);
}
}
pub fn insert_full(&mut self, base_addr: Addr, interface: Arc<dyn MemDeviceInterface>) {
assert!(base_addr.is_multiple_of(MMIO_ROOT_PAGE_SIZE as u64));
assert!(base_addr < RAM_START);
let page_id = base_addr as usize / MMIO_ROOT_PAGE_SIZE;
self.0[page_id] = Some(MmioSecondLevel::Interface(interface));
}
fn get_device(&self, addr: Addr) -> Option<(Arc<dyn MemDeviceInterface>, Addr)> {
debug_assert!(addr < RAM_START);
let page_id = addr as usize / MMIO_SECOND_LEVEL_PAGE_SIZE;
let root_page_id = page_id / MMIO_SECOND_LEVEL_ENTRIES;
self.0[root_page_id]
.as_ref()
.and_then(|s| s.get_device(addr % MMIO_ROOT_PAGE_SIZE as Addr))
}
fn crosses_boundary(&self, addr: Addr, size: Addr) -> bool {
if addr >= RAM_START {
return false;
}
if addr + size > RAM_START {
return true;
}
let page_id = addr as usize / MMIO_SECOND_LEVEL_PAGE_SIZE;
let root_page_id = page_id / MMIO_SECOND_LEVEL_ENTRIES;
let end = addr + size - 1;
match self.0[root_page_id].as_ref() {
Some(s) => match s {
MmioSecondLevel::SubTable(_) => {
let end_page_id = end as usize / MMIO_SECOND_LEVEL_PAGE_SIZE;
page_id != end_page_id
}
MmioSecondLevel::Interface(_) => {
let end_root_page_id = end as usize / MMIO_ROOT_PAGE_SIZE;
root_page_id != end_root_page_id
}
},
None => false,
}
}
}
impl Default for MmioRoot {
fn default() -> Self {
Self(Box::new([(); MMIO_ROOT_ENTRIES].map(|_| None)))
}
}
#[derive(Clone)]
enum MmioSecondLevel {
SubTable(Box<[Option<Arc<dyn MemDeviceInterface>>; MMIO_SECOND_LEVEL_ENTRIES]>),
Interface(Arc<dyn MemDeviceInterface>),
}
impl MmioSecondLevel {
fn get_device(&self, addr: Addr) -> Option<(Arc<dyn MemDeviceInterface>, Addr)> {
let page_id = addr as usize / MMIO_SECOND_LEVEL_PAGE_SIZE;
match self {
Self::SubTable(t) => t[page_id]
.as_ref()
.map(|i| (i.clone(), addr % MMIO_SECOND_LEVEL_PAGE_SIZE as Addr)),
Self::Interface(i) => Some((i.clone(), addr)),
}
}
}
impl Default for MmioSecondLevel {
fn default() -> Self {
Self::SubTable(Box::new([(); MMIO_SECOND_LEVEL_ENTRIES].map(|_| None)))
}
} }
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait MemDeviceInterface { pub trait MemDeviceInterface {
fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), ExceptionType> { fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> {
Err(ExceptionType::StoreAmoAccessFault) Err(MemoryExceptionType::AccessFault)
} }
fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> { fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> {
Err(ExceptionType::StoreAmoAccessFault) Err(MemoryExceptionType::AccessFault)
} }
fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), ExceptionType> { fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> {
Err(ExceptionType::StoreAmoAccessFault) Err(MemoryExceptionType::AccessFault)
} }
fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> { fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> {
Err(ExceptionType::StoreAmoAccessFault) Err(MemoryExceptionType::AccessFault)
} }
fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, ExceptionType> { fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryExceptionType> {
Err(ExceptionType::LoadAccessFault) Err(MemoryExceptionType::AccessFault)
} }
fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, ExceptionType> { fn read_word(&self, addr: Addr) -> Result<Word, MemoryExceptionType> {
Err(ExceptionType::LoadAccessFault) Err(MemoryExceptionType::AccessFault)
} }
fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, ExceptionType> { fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryExceptionType> {
Err(ExceptionType::LoadAccessFault) Err(MemoryExceptionType::AccessFault)
} }
fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType> { fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> {
Err(ExceptionType::LoadAccessFault) Err(MemoryExceptionType::AccessFault)
}
fn get_atomic_word(&self, page: PageNum, offset: u16) -> Result<&AtomicU32, ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
}
fn get_atomic_dword(&self, page: PageNum, offset: u16) -> Result<&AtomicU64, ExceptionType> {
Err(ExceptionType::StoreAmoAccessFault)
} }
} }