EXCEPTION SYSTEM (initial version - may change later)

This commit is contained in:
2025-12-24 13:56:41 +01:00
parent 3f789442c0
commit 09d9064372
11 changed files with 338 additions and 332 deletions

31
Cargo.lock generated
View File

@@ -37,6 +37,18 @@ dependencies = [
"scroll", "scroll",
] ]
[[package]]
name = "int-enum"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e366a1634cccc76b4cfd3e7580de9b605e4d93f1edac48d786c1f867c0def495"
dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
"syn",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.176" version = "0.2.176"
@@ -85,6 +97,18 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "proc-macro2-diagnostics"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.42" version = "1.0.42"
@@ -131,6 +155,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"goblin", "goblin",
"int-enum",
"memmap2", "memmap2",
"nix", "nix",
] ]
@@ -140,3 +165,9 @@ name = "unicode-ident"
version = "1.0.22" version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"

View File

@@ -6,5 +6,6 @@ edition = "2024"
[dependencies] [dependencies]
anyhow = "1.0.100" anyhow = "1.0.100"
goblin = "0.10.4" goblin = "0.10.4"
int-enum = "1.2.0"
memmap2 = "0.9.8" memmap2 = "0.9.8"
nix = { version = "0.30.1", features = ["fs"] } nix = { version = "0.30.1", features = ["fs"] }

View File

@@ -14,7 +14,8 @@ 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::{Byte, DWord, HWord, Word};
use trve::mem::{MemAccessFault, MemDeviceInterface, PageNum}; use trve::exceptions::ExceptionType;
use trve::mem::{MemDeviceInterface, PageNum};
/// 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
@@ -82,12 +83,12 @@ impl MemDeviceInterface for BasicUart {
_page: PageNum, _page: PageNum,
_offset: u16, _offset: u16,
_value: DWord, _value: DWord,
) -> Result<(), MemAccessFault> { ) -> Result<(), ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::StoreAmoAccessFault)
} }
fn write_word(&self, _page: PageNum, _offset: u16, _value: Word) -> Result<(), MemAccessFault> { fn write_word(&self, _page: PageNum, _offset: u16, _value: Word) -> Result<(), ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::StoreAmoAccessFault)
} }
fn write_hword( fn write_hword(
@@ -95,13 +96,13 @@ impl MemDeviceInterface for BasicUart {
_page: PageNum, _page: PageNum,
_offset: u16, _offset: u16,
_value: HWord, _value: HWord,
) -> Result<(), MemAccessFault> { ) -> Result<(), ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::StoreAmoAccessFault)
} }
fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), MemAccessFault> { fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
if page > 0 { if page > 0 {
return Err(MemAccessFault); return Err(ExceptionType::StoreAmoAccessFault);
} }
match offset { match offset {
@@ -109,31 +110,31 @@ impl MemDeviceInterface for BasicUart {
self.write(value); self.write(value);
Ok(()) Ok(())
} }
_ => Err(MemAccessFault), _ => Err(ExceptionType::StoreAmoAccessFault),
} }
} }
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, MemAccessFault> { fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::LoadAccessFault)
} }
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, MemAccessFault> { fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::LoadAccessFault)
} }
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, MemAccessFault> { fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::LoadAccessFault)
} }
fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, MemAccessFault> { fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType> {
if page > 0 { if page > 0 {
return Err(MemAccessFault); return Err(ExceptionType::LoadAccessFault);
} }
match offset { 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(MemAccessFault), _ => Err(ExceptionType::LoadAccessFault),
} }
} }
@@ -141,15 +142,15 @@ impl MemDeviceInterface for BasicUart {
&self, &self,
_page: PageNum, _page: PageNum,
_offset: u16, _offset: u16,
) -> Result<&std::sync::atomic::AtomicU32, MemAccessFault> { ) -> Result<&std::sync::atomic::AtomicU32, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::StoreAmoAccessFault)
} }
fn get_atomic_dword( fn get_atomic_dword(
&self, &self,
_page: PageNum, _page: PageNum,
_offset: u16, _offset: u16,
) -> Result<&std::sync::atomic::AtomicU64, MemAccessFault> { ) -> Result<&std::sync::atomic::AtomicU64, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::StoreAmoAccessFault)
} }
} }

View File

@@ -7,19 +7,11 @@
use crate::{ use crate::{
consts::{Addr, RegId, RegValue}, consts::{Addr, RegId, RegValue},
decode::Instruction, decode::Instruction,
exceptions::ExceptionType,
instructions::find_and_exec, instructions::find_and_exec,
mem::MemConfig, mem::MemConfig,
}; };
// placeholder - change when exception system is in place
pub(crate) type Exception = ();
pub(crate) enum InstructionResult {
Normal,
Exception(Exception),
// Pause,
}
pub struct Core { pub struct Core {
pub(crate) x_regs: [RegValue; 32], pub(crate) x_regs: [RegValue; 32],
pub(crate) pc: Addr, pub(crate) pc: Addr,
@@ -40,48 +32,44 @@ impl Core {
let page = (self.pc / 4096) as usize; let page = (self.pc / 4096) as usize;
let offset = (self.pc % 4096 / 4) as u16; let offset = (self.pc % 4096 / 4) as u16;
if !self.pc.is_multiple_of(4) { if !self.pc.is_multiple_of(4) {
//replace eprint with logging, replace break with exception self.throw_exception(ExceptionType::InstructionAccessMisaligned);
eprintln!("PC not aligned");
break; break;
} }
let instr = match self.mem.read_word(page, offset) { let instr = match self.mem.read_word(page, offset) {
Ok(i) => i, Ok(i) => i,
Err(_) => { Err(_) => {
eprintln!("Memory access fault while fetching instruction"); self.throw_exception(ExceptionType::InstructionAccessFault);
eprintln!("PC: {:x}", self.pc);
break; break;
} }
}; };
if instr == 0 { if instr == 0 {
eprintln!("Executing 0 instruction at {:x}", self.pc); self.throw_exception(ExceptionType::IllegalInstruction);
break; break;
} }
assert_eq!(instr & 3, 3, "Compressed instructions not supported"); if instr & 3 != 3 {
self.throw_exception(ExceptionType::IllegalInstruction);
break;
}
let instr = Instruction(instr); let instr = Instruction(instr);
let res = find_and_exec(instr, self); match find_and_exec(instr, self) {
Ok(()) => {}
Err(e) => {
self.throw_exception(e);
eprintln!("instr: {:08x}", instr.0);
break;
}
}
}
}
if let Some(res) = res { fn throw_exception(&mut self, exception_type: ExceptionType) {
match res { eprintln!("Exception: {exception_type:?}");
InstructionResult::Normal => {} dbg!(self.pc, self.x_regs);
InstructionResult::Exception(_e) => {
eprintln!("Exception from instruction");
eprintln!("PC: {:016x}, instr: {:08x}", self.pc, instr.0);
break;
} // InstructionResult::Pause => {
// eprintln!("Instruction asked for pause");
// break;
// }
}
} else {
eprintln!("Invalid Instruction {:08x} at PC: {:x}", instr.0, self.pc);
break;
}
}
} }
pub fn reset(&mut self, pc: Addr) { pub fn reset(&mut self, pc: Addr) {

30
src/exceptions.rs Normal file
View File

@@ -0,0 +1,30 @@
// Copyright (c) 2025 taitep
// SPDX-License-Identifier: MIT
//
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
// See LICENSE file in the project root for full license text.
use int_enum::IntEnum;
#[repr(u8)]
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)]
pub enum ExceptionType {
InstructionAccessMisaligned = 0,
InstructionAccessFault = 1,
IllegalInstruction = 2,
Breakpoint = 3,
LoadAddressMisaligned = 4,
LoadAccessFault = 5,
StoreAmoAddressMisaligned = 6,
StoreAmoAccessFault = 7,
EnvironmentCallFromUMode = 8,
EnvironmentCallFromSMode = 9,
EnvironmentCallFromMMode = 11,
InstructionPageFault = 12,
LoadPageFault = 13,
StoreAmoPageFault = 15,
DoubleTrap = 16,
SoftwareCheck = 18,
HardwareError = 19,
}

View File

@@ -7,67 +7,81 @@
mod rvi; mod rvi;
use crate::{ use crate::{
core::{Core, InstructionResult}, core::Core,
decode::Instruction, decode::Instruction,
exceptions::ExceptionType::{self, IllegalInstruction},
}; };
pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Option<InstructionResult> { pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), ExceptionType> {
match instr.opcode_noncompressed() { match instr.opcode_noncompressed() {
0b01100 => match (instr.funct7(), instr.funct3()) { 0b01100 => match (instr.funct7(), instr.funct3()) {
// OP // OP
(0b0000000, 0b000) => Some(rvi::add(core, instr)), (0b0000000, 0b000) => rvi::add(core, instr),
(0b0100000, 0b000) => Some(rvi::sub(core, instr)), (0b0100000, 0b000) => rvi::sub(core, instr),
(0b0000000, 0b111) => Some(rvi::and(core, instr)), (0b0000000, 0b111) => rvi::and(core, instr),
(0b0000000, 0b110) => Some(rvi::or(core, instr)), (0b0000000, 0b110) => rvi::or(core, instr),
_ => None, _ => Err(IllegalInstruction),
}, },
0b00100 => match instr.funct3() { 0b00100 => match instr.funct3() {
// OP_IMM // OP_IMM
0b000 => Some(rvi::addi(core, instr)), 0b000 => rvi::addi(core, instr),
0b001 => (instr.funct6() == 0).then(|| rvi::slli(core, instr)), 0b001 => {
if instr.funct6() == 0 {
rvi::slli(core, instr)
} else {
Err(IllegalInstruction)
}
}
0b101 => match instr.funct6() { 0b101 => match instr.funct6() {
// immediate right-shift // immediate right-shift
0b000000 => Some(rvi::srli(core, instr)), 0b000000 => rvi::srli(core, instr),
_ => None, _ => Err(IllegalInstruction),
}, },
0b111 => Some(rvi::andi(core, instr)), 0b111 => rvi::andi(core, instr),
_ => None, _ => Err(IllegalInstruction),
}, },
0b00110 => match instr.funct3() { 0b00110 => match instr.funct3() {
// OP_IMM_32 // OP_IMM_32
0b000 => Some(rvi::addiw(core, instr)), 0b000 => rvi::addiw(core, instr),
_ => None, _ => Err(IllegalInstruction),
}, },
0b01000 => match instr.funct3() { 0b01000 => match instr.funct3() {
// STORE // STORE
0b000 => Some(rvi::sb(core, instr)), 0b000 => rvi::sb(core, instr),
0b001 => Some(rvi::sh(core, instr)), 0b001 => rvi::sh(core, instr),
0b010 => Some(rvi::sw(core, instr)), 0b010 => rvi::sw(core, instr),
0b011 => Some(rvi::sd(core, instr)), 0b011 => rvi::sd(core, instr),
_ => None, _ => Err(IllegalInstruction),
}, },
0b00000 => match instr.funct3() { 0b00000 => match instr.funct3() {
// LOAD // LOAD
0b000 => Some(rvi::lb(core, instr)), 0b000 => rvi::lb(core, instr),
0b100 => Some(rvi::lbu(core, instr)), 0b100 => rvi::lbu(core, instr),
0b001 => Some(rvi::lh(core, instr)), 0b001 => rvi::lh(core, instr),
0b010 => Some(rvi::lw(core, instr)), 0b010 => rvi::lw(core, instr),
0b011 => Some(rvi::ld(core, instr)), 0b011 => rvi::ld(core, instr),
_ => None, _ => Err(IllegalInstruction),
}, },
0b11000 => match instr.funct3() { 0b11000 => match instr.funct3() {
// BRANCH // BRANCH
0b000 => Some(rvi::beq(core, instr)), 0b000 => rvi::beq(core, instr),
0b001 => Some(rvi::bne(core, instr)), 0b001 => rvi::bne(core, instr),
0b100 => Some(rvi::blt(core, instr)), 0b100 => rvi::blt(core, instr),
0b110 => Some(rvi::bltu(core, instr)), 0b110 => rvi::bltu(core, instr),
0b111 => Some(rvi::bgeu(core, instr)), 0b111 => rvi::bgeu(core, instr),
_ => None, _ => Err(IllegalInstruction),
}, },
0b01101 => Some(rvi::lui(core, instr)), 0b01101 => rvi::lui(core, instr),
0b00101 => Some(rvi::auipc(core, instr)), 0b00101 => rvi::auipc(core, instr),
0b11011 => Some(rvi::jal(core, instr)), 0b11011 => rvi::jal(core, instr),
0b11001 => (instr.funct3() == 0).then(|| rvi::jalr(core, instr)), // 0b11001 => (instr.funct3() == 0).then(|| rvi::jalr(core, instr)),
_ => None, 0b11001 => {
if instr.funct3() == 0 {
rvi::jalr(core, instr)
} else {
Err(IllegalInstruction)
}
}
_ => Err(IllegalInstruction),
} }
} }

View File

@@ -4,157 +4,154 @@
// 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 crate::{ use crate::{core::Core, decode::Instruction, exceptions::ExceptionType};
core::{Core, InstructionResult},
decode::Instruction,
};
mod mem; mod mem;
pub use mem::*; pub use mem::*;
pub fn add(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn add(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.reg_read(instr.rs1()) core.reg_read(instr.rs1())
.wrapping_add(core.reg_read(instr.rs2())), .wrapping_add(core.reg_read(instr.rs2())),
); );
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn sub(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn sub(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.reg_read(instr.rs1()) core.reg_read(instr.rs1())
.wrapping_sub(core.reg_read(instr.rs2())), .wrapping_sub(core.reg_read(instr.rs2())),
); );
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn addi(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn addi(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()), core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()),
); );
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn addiw(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn addiw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
let res = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()) as i32; let res = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()) as i32;
core.reg_write(instr.rd(), res as i64 as u64); core.reg_write(instr.rd(), res as i64 as u64);
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn and(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn and(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.reg_read(instr.rs1()) & core.reg_read(instr.rs2()), core.reg_read(instr.rs1()) & core.reg_read(instr.rs2()),
); );
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn andi(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn andi(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), core.reg_read(instr.rs1()) & instr.imm_i()); core.reg_write(instr.rd(), core.reg_read(instr.rs1()) & instr.imm_i());
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn or(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn or(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write( core.reg_write(
instr.rd(), instr.rd(),
core.reg_read(instr.rs1()) | core.reg_read(instr.rs2()), core.reg_read(instr.rs1()) | core.reg_read(instr.rs2()),
); );
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn slli(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn slli(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), core.reg_read(instr.rs1()) << instr.imm_shamt()); core.reg_write(instr.rd(), core.reg_read(instr.rs1()) << instr.imm_shamt());
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn srli(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn srli(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), core.reg_read(instr.rs1()) >> instr.imm_shamt()); core.reg_write(instr.rd(), core.reg_read(instr.rs1()) >> instr.imm_shamt());
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn lui(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn lui(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), instr.imm_u()); core.reg_write(instr.rd(), instr.imm_u());
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn auipc(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn auipc(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), core.pc.wrapping_add(instr.imm_u())); core.reg_write(instr.rd(), core.pc.wrapping_add(instr.imm_u()));
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
} }
pub fn jal(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn jal(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), core.pc.wrapping_add(4)); core.reg_write(instr.rd(), core.pc.wrapping_add(4));
core.pc = core.pc.wrapping_add(instr.imm_j()); core.pc = core.pc.wrapping_add(instr.imm_j());
InstructionResult::Normal Ok(())
} }
pub fn jalr(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn jalr(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
core.reg_write(instr.rd(), core.pc.wrapping_add(4)); core.reg_write(instr.rd(), core.pc.wrapping_add(4));
core.pc = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()); core.pc = core.reg_read(instr.rs1()).wrapping_add(instr.imm_i());
InstructionResult::Normal Ok(())
} }
pub fn beq(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn beq(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
if core.reg_read(instr.rs1()) == core.reg_read(instr.rs2()) { if core.reg_read(instr.rs1()) == core.reg_read(instr.rs2()) {
core.pc = core.pc.wrapping_add(instr.imm_b()); core.pc = core.pc.wrapping_add(instr.imm_b());
} else { } else {
core.advance_pc(); core.advance_pc();
} }
InstructionResult::Normal Ok(())
} }
pub fn bne(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn bne(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
if core.reg_read(instr.rs1()) != core.reg_read(instr.rs2()) { if core.reg_read(instr.rs1()) != core.reg_read(instr.rs2()) {
core.pc = core.pc.wrapping_add(instr.imm_b()); core.pc = core.pc.wrapping_add(instr.imm_b());
} else { } else {
core.advance_pc(); core.advance_pc();
} }
InstructionResult::Normal Ok(())
} }
pub fn blt(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn blt(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
if (core.reg_read(instr.rs1()) as i64) < (core.reg_read(instr.rs2()) as i64) { if (core.reg_read(instr.rs1()) as i64) < (core.reg_read(instr.rs2()) as i64) {
core.pc = core.pc.wrapping_add(instr.imm_b()); core.pc = core.pc.wrapping_add(instr.imm_b());
} else { } else {
core.advance_pc(); core.advance_pc();
} }
InstructionResult::Normal Ok(())
} }
pub fn bgeu(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn bgeu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
if core.reg_read(instr.rs1()) >= core.reg_read(instr.rs2()) { if core.reg_read(instr.rs1()) >= core.reg_read(instr.rs2()) {
core.pc = core.pc.wrapping_add(instr.imm_b()); core.pc = core.pc.wrapping_add(instr.imm_b());
} else { } else {
core.advance_pc(); core.advance_pc();
} }
InstructionResult::Normal Ok(())
} }
pub fn bltu(core: &mut Core, instr: Instruction) -> InstructionResult { pub fn bltu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
if core.reg_read(instr.rs1()) < core.reg_read(instr.rs2()) { if core.reg_read(instr.rs1()) < core.reg_read(instr.rs2()) {
core.pc = core.pc.wrapping_add(instr.imm_b()); core.pc = core.pc.wrapping_add(instr.imm_b());
} else { } else {
core.advance_pc(); core.advance_pc();
} }
InstructionResult::Normal Ok(())
} }

View File

@@ -7,177 +7,145 @@
use crate::{ use crate::{
consts::{Addr, Byte, DWord, HWord, Word}, consts::{Addr, Byte, DWord, HWord, Word},
core::Core, core::Core,
instructions::{Instruction, InstructionResult}, exceptions::ExceptionType,
instructions::Instruction,
mem::PageNum, mem::PageNum,
}; };
// TODO: Support misaligned memory access // TODO: Support misaligned memory access
pub fn sd(core: &mut Core, instr: Instruction) -> InstructionResult { 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) { if !addr.is_multiple_of(std::mem::size_of::<DWord>() as Addr) {
return InstructionResult::Exception(()); return Err(ExceptionType::StoreAmoAddressMisaligned);
} }
let page = (addr / 4096) as PageNum; let page = (addr / 4096) as PageNum;
let offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16; 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());
match core.mem.write_dword(page, offset, value) { core.mem.write_dword(page, offset, value)?;
Ok(_) => {
core.advance_pc(); core.advance_pc();
InstructionResult::Normal
} Ok(())
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn ld(core: &mut Core, instr: Instruction) -> InstructionResult { 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());
if !addr.is_multiple_of(std::mem::size_of::<DWord>() as Addr) { if !addr.is_multiple_of(std::mem::size_of::<DWord>() as Addr) {
return InstructionResult::Exception(()); return Err(ExceptionType::LoadAddressMisaligned);
} }
let page = (addr / 4096) as PageNum; let page = (addr / 4096) as PageNum;
let offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16; let offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16;
match core.mem.read_dword(page, offset) { core.reg_write(instr.rd(), core.mem.read_dword(page, offset)?);
Ok(x) => {
core.reg_write(instr.rd(), x);
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn sw(core: &mut Core, instr: Instruction) -> InstructionResult { 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) { if !addr.is_multiple_of(std::mem::size_of::<Word>() as Addr) {
return InstructionResult::Exception(()); return Err(ExceptionType::StoreAmoAddressMisaligned);
} }
let page = (addr / 4096) as PageNum; let page = (addr / 4096) as PageNum;
let offset = (addr / 4 & ((4096 / 4 as Addr) - 1)) as u16; 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;
match core.mem.write_word(page, offset, value) { core.mem.write_word(page, offset, value)?;
Ok(_) => {
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn lw(core: &mut Core, instr: Instruction) -> InstructionResult { 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) { if !addr.is_multiple_of(std::mem::size_of::<Word>() as Addr) {
return InstructionResult::Exception(()); return Err(ExceptionType::LoadAddressMisaligned);
} }
let page = (addr / 4096) as PageNum; let page = (addr / 4096) as PageNum;
let offset = (addr / 4 & ((4096 / 4 as Addr) - 1)) as u16; let offset = (addr / 4 & ((4096 / 4 as Addr) - 1)) as u16;
match core.mem.read_word(page, offset) { core.reg_write(
Ok(x) => { instr.rd(),
core.reg_write(instr.rd(), x as i32 as i64 as DWord); core.mem.read_word(page, offset)? as i32 as i64 as DWord,
);
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn sh(core: &mut Core, instr: Instruction) -> InstructionResult { 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) { if !addr.is_multiple_of(std::mem::size_of::<HWord>() as Addr) {
return InstructionResult::Exception(()); return Err(ExceptionType::StoreAmoAddressMisaligned);
} }
let page = (addr / 4096) as PageNum; let page = (addr / 4096) as PageNum;
let offset = (addr / 2 & ((4096 / 2 as Addr) - 1)) as u16; 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;
match core.mem.write_hword(page, offset, value) { core.mem.write_hword(page, offset, value)?;
Ok(_) => {
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn lh(core: &mut Core, instr: Instruction) -> InstructionResult { 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) { if !addr.is_multiple_of(std::mem::size_of::<HWord>() as Addr) {
return InstructionResult::Exception(()); return Err(ExceptionType::LoadAddressMisaligned);
} }
let page = (addr / 4096) as PageNum; let page = (addr / 4096) as PageNum;
let offset = (addr / 2 & ((4096 / 2 as Addr) - 1)) as u16; let offset = (addr / 2 & ((4096 / 2 as Addr) - 1)) as u16;
match core.mem.read_hword(page, offset) { core.reg_write(
Ok(x) => { instr.rd(),
core.reg_write(instr.rd(), x as i16 as i64 as DWord); core.mem.read_hword(page, offset)? as i16 as i64 as DWord,
);
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn sb(core: &mut Core, instr: Instruction) -> InstructionResult { 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 page = (addr / 4096) as PageNum;
let offset = (addr & (4096 as Addr - 1)) as u16; 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;
match core.mem.write_byte(page, offset, value) { core.mem.write_byte(page, offset, value)?;
Ok(_) => {
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn lb(core: &mut Core, instr: Instruction) -> InstructionResult { 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 page = (addr / 4096) as PageNum;
let offset = (addr & (4096 as Addr - 1)) as u16; let offset = (addr & (4096 as Addr - 1)) as u16;
match core.mem.read_byte(page, offset) { core.reg_write(
Ok(x) => { instr.rd(),
let x = x as i8 as i64 as DWord; core.mem.read_byte(page, offset)? as i8 as i64 as DWord,
core.reg_write(instr.rd(), x); );
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }
pub fn lbu(core: &mut Core, instr: Instruction) -> InstructionResult { 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());
let page = (addr / 4096) as PageNum; let page = (addr / 4096) as PageNum;
let offset = (addr & (4096 as Addr - 1)) as u16; let offset = (addr & (4096 as Addr - 1)) as u16;
match core.mem.read_byte(page, offset) { core.reg_write(instr.rd(), core.mem.read_byte(page, offset)? as DWord);
Ok(x) => {
let x = x as DWord;
core.reg_write(instr.rd(), x);
core.advance_pc(); core.advance_pc();
InstructionResult::Normal Ok(())
}
Err(_) => InstructionResult::Exception(()),
}
} }

View File

@@ -1,5 +1,6 @@
pub mod consts; pub mod consts;
pub mod core; pub mod core;
mod decode; mod decode;
pub mod exceptions;
mod instructions; mod instructions;
pub mod mem; pub mod mem;

View File

@@ -9,7 +9,8 @@ use std::{env, sync::Arc, time::Duration};
use trve::{ use trve::{
consts::{Byte, DWord, HWord, Word}, consts::{Byte, DWord, HWord, Word},
core::Core, core::Core,
mem::{DeviceEntry, MemAccessFault, MemConfig, MemDeviceInterface, PageNum, Ram}, exceptions::ExceptionType,
mem::{DeviceEntry, MemConfig, MemDeviceInterface, PageNum, Ram},
}; };
use anyhow::{Result, bail}; use anyhow::{Result, bail};
@@ -63,12 +64,7 @@ mod basic_uart;
struct DbgOut; struct DbgOut;
impl MemDeviceInterface for DbgOut { impl MemDeviceInterface for DbgOut {
fn write_dword( fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: DWord,
) -> Result<(), trve::mem::MemAccessFault> {
eprintln!( eprintln!(
"Wrote DWord {value:016x} to Debug-Out page {page}, offset {offset} (byte {})", "Wrote DWord {value:016x} to Debug-Out page {page}, offset {offset} (byte {})",
offset * 8 offset * 8
@@ -76,12 +72,7 @@ impl MemDeviceInterface for DbgOut {
Ok(()) Ok(())
} }
fn write_word( fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: Word,
) -> Result<(), trve::mem::MemAccessFault> {
eprintln!( eprintln!(
"Wrote Word {value:08x} to Debug-Out page {page}, offset {offset} (byte {})", "Wrote Word {value:08x} to Debug-Out page {page}, offset {offset} (byte {})",
offset * 4 offset * 4
@@ -89,12 +80,7 @@ impl MemDeviceInterface for DbgOut {
Ok(()) Ok(())
} }
fn write_hword( fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: HWord,
) -> Result<(), trve::mem::MemAccessFault> {
eprintln!( eprintln!(
"Wrote HWord {value:04x} to Debug-Out page {page}, offset {offset} (byte {})", "Wrote HWord {value:04x} to Debug-Out page {page}, offset {offset} (byte {})",
offset * 2 offset * 2
@@ -102,45 +88,40 @@ impl MemDeviceInterface for DbgOut {
Ok(()) Ok(())
} }
fn write_byte( fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: Byte,
) -> Result<(), trve::mem::MemAccessFault> {
eprintln!("Wrote Byte {value:02x} to Debug-Out page {page}, offset {offset}"); eprintln!("Wrote Byte {value:02x} to Debug-Out page {page}, offset {offset}");
Ok(()) Ok(())
} }
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, trve::mem::MemAccessFault> { fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::LoadAccessFault)
} }
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, trve::mem::MemAccessFault> { fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::LoadAccessFault)
} }
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, trve::mem::MemAccessFault> { fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::LoadAccessFault)
} }
fn read_byte(&self, _page: PageNum, _offset: u16) -> Result<Byte, trve::mem::MemAccessFault> { fn read_byte(&self, _page: PageNum, _offset: u16) -> Result<Byte, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::LoadAccessFault)
} }
fn get_atomic_word( fn get_atomic_word(
&self, &self,
_page: PageNum, _page: PageNum,
_offset: u16, _offset: u16,
) -> Result<&std::sync::atomic::AtomicU32, trve::mem::MemAccessFault> { ) -> Result<&std::sync::atomic::AtomicU32, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::StoreAmoAccessFault)
} }
fn get_atomic_dword( fn get_atomic_dword(
&self, &self,
_page: PageNum, _page: PageNum,
_offset: u16, _offset: u16,
) -> Result<&std::sync::atomic::AtomicU64, trve::mem::MemAccessFault> { ) -> Result<&std::sync::atomic::AtomicU64, ExceptionType> {
Err(MemAccessFault) Err(ExceptionType::StoreAmoAccessFault)
} }
} }

View File

@@ -11,7 +11,10 @@ use std::sync::{
use memmap2::MmapMut; use memmap2::MmapMut;
use crate::consts::{Byte, DWord, HWord, Word}; use crate::{
consts::{Byte, DWord, HWord, Word},
exceptions::ExceptionType,
};
pub type PageNum = usize; pub type PageNum = usize;
@@ -45,38 +48,46 @@ impl MemConfig {
} }
} }
pub fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, MemAccessFault> { pub fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.read_dword(page - self.ram_start, offset) self.ram.read_dword(page - self.ram_start, offset)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_dword(page - entry.base, offset) entry.interface.read_dword(page - entry.base, offset)
} }
} }
pub fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, MemAccessFault> { pub fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.read_word(page - self.ram_start, offset) self.ram.read_word(page - self.ram_start, offset)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_word(page - entry.base, offset) entry.interface.read_word(page - entry.base, offset)
} }
} }
pub fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, MemAccessFault> { pub fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.read_hword(page - self.ram_start, offset) self.ram.read_hword(page - self.ram_start, offset)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_hword(page - entry.base, offset) entry.interface.read_hword(page - entry.base, offset)
} }
} }
pub fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, MemAccessFault> { pub fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.read_byte(page - self.ram_start, offset) self.ram.read_byte(page - self.ram_start, offset)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::LoadAccessFault)?;
entry.interface.read_byte(page - entry.base, offset) entry.interface.read_byte(page - entry.base, offset)
} }
@@ -87,26 +98,25 @@ impl MemConfig {
page: PageNum, page: PageNum,
offset: u16, offset: u16,
value: DWord, value: DWord,
) -> Result<(), MemAccessFault> { ) -> Result<(), ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_dword(page - self.ram_start, offset, value) self.ram.write_dword(page - self.ram_start, offset, value)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry entry
.interface .interface
.write_dword(page - entry.base, offset, value) .write_dword(page - entry.base, offset, value)
} }
} }
pub fn write_word( pub fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: Word,
) -> Result<(), MemAccessFault> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_word(page - self.ram_start, offset, value) self.ram.write_word(page - self.ram_start, offset, value)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry.interface.write_word(page - entry.base, offset, value) entry.interface.write_word(page - entry.base, offset, value)
} }
} }
@@ -115,26 +125,25 @@ impl MemConfig {
page: PageNum, page: PageNum,
offset: u16, offset: u16,
value: HWord, value: HWord,
) -> Result<(), MemAccessFault> { ) -> Result<(), ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_hword(page - self.ram_start, offset, value) self.ram.write_hword(page - self.ram_start, offset, value)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry entry
.interface .interface
.write_hword(page - entry.base, offset, value) .write_hword(page - entry.base, offset, value)
} }
} }
pub fn write_byte( pub fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: Byte,
) -> Result<(), MemAccessFault> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
self.ram.write_byte(page - self.ram_start, offset, value) self.ram.write_byte(page - self.ram_start, offset, value)
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry.interface.write_byte(page - entry.base, offset, value) entry.interface.write_byte(page - entry.base, offset, value)
} }
} }
@@ -143,7 +152,7 @@ impl MemConfig {
&self, &self,
page: PageNum, page: PageNum,
offset: u16, offset: u16,
) -> Result<&AtomicU64, MemAccessFault> { ) -> Result<&AtomicU64, ExceptionType> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
debug_assert!(((offset * 8) as usize) < PAGE_SIZE); debug_assert!(((offset * 8) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 8) + (offset as usize); let index = page * (PAGE_SIZE / 8) + (offset as usize);
@@ -151,18 +160,16 @@ impl MemConfig {
self.ram self.ram
.buf_transmuted::<AtomicU64>() .buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::HardwareError)
} }
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry.interface.get_atomic_dword(page - entry.base, offset) entry.interface.get_atomic_dword(page - entry.base, offset)
} }
} }
pub fn get_atomic_word( pub fn get_atomic_word(&self, page: PageNum, offset: u16) -> Result<&AtomicU32, ExceptionType> {
&self,
page: PageNum,
offset: u16,
) -> Result<&AtomicU32, MemAccessFault> {
if page_in_range(page, self.ram_start, self.ram.pages) { if page_in_range(page, self.ram_start, self.ram.pages) {
debug_assert!(((offset * 4) as usize) < PAGE_SIZE); debug_assert!(((offset * 4) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 4) + (offset as usize); let index = page * (PAGE_SIZE / 4) + (offset as usize);
@@ -170,10 +177,12 @@ impl MemConfig {
self.ram self.ram
.buf_transmuted::<AtomicU32>() .buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::HardwareError)
} }
} else { } else {
let entry = self.find_device_by_page(page).ok_or(MemAccessFault)?; let entry = self
.find_device_by_page(page)
.ok_or(ExceptionType::StoreAmoAccessFault)?;
entry.interface.get_atomic_word(page - entry.base, offset) entry.interface.get_atomic_word(page - entry.base, offset)
} }
} }
@@ -232,46 +241,46 @@ impl Ram {
} }
#[inline] #[inline]
pub fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, MemAccessFault> { pub fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, ExceptionType> {
debug_assert!(((offset * 8) as usize) < PAGE_SIZE); debug_assert!(((offset * 8) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 8) + (offset as usize); let index = page * (PAGE_SIZE / 8) + (offset as usize);
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU64>() self.buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::LoadAccessFault)
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, MemAccessFault> { pub fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, ExceptionType> {
debug_assert!(((offset * 4) as usize) < PAGE_SIZE); debug_assert!(((offset * 4) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 4) + (offset as usize); let index = page * (PAGE_SIZE / 4) + (offset as usize);
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU32>() self.buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::LoadAccessFault)
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, MemAccessFault> { pub fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, ExceptionType> {
debug_assert!(((offset * 2) as usize) < PAGE_SIZE); debug_assert!(((offset * 2) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 2) + (offset as usize); let index = page * (PAGE_SIZE / 2) + (offset as usize);
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU16>() self.buf_transmuted::<AtomicU16>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::LoadAccessFault)
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, MemAccessFault> { pub fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType> {
debug_assert!((offset as usize) < PAGE_SIZE); debug_assert!((offset as usize) < PAGE_SIZE);
let index = page * PAGE_SIZE + (offset as usize); let index = page * PAGE_SIZE + (offset as usize);
Ok(self Ok(self
.buf_atomic() .buf_atomic()
.get(index) .get(index)
.ok_or(MemAccessFault)? .ok_or(ExceptionType::LoadAccessFault)?
.load(Relaxed)) .load(Relaxed))
} }
@@ -281,30 +290,25 @@ impl Ram {
page: PageNum, page: PageNum,
offset: u16, offset: u16,
value: DWord, value: DWord,
) -> Result<(), MemAccessFault> { ) -> Result<(), ExceptionType> {
debug_assert!(((offset * 8) as usize) < PAGE_SIZE); debug_assert!(((offset * 8) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 8) + (offset as usize); let index = page * (PAGE_SIZE / 8) + (offset as usize);
unsafe { unsafe {
self.buf_transmuted::<AtomicU64>() self.buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::StoreAmoAccessFault)
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_word( pub fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: Word,
) -> Result<(), MemAccessFault> {
debug_assert!(((offset * 4) as usize) < PAGE_SIZE); debug_assert!(((offset * 4) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 4) + (offset as usize); let index = page * (PAGE_SIZE / 4) + (offset as usize);
unsafe { unsafe {
self.buf_transmuted::<AtomicU32>() self.buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::StoreAmoAccessFault)
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
@@ -315,29 +319,24 @@ impl Ram {
page: PageNum, page: PageNum,
offset: u16, offset: u16,
value: HWord, value: HWord,
) -> Result<(), MemAccessFault> { ) -> Result<(), ExceptionType> {
debug_assert!(((offset * 2) as usize) < PAGE_SIZE); debug_assert!(((offset * 2) as usize) < PAGE_SIZE);
let index = page * (PAGE_SIZE / 2) + (offset as usize); let index = page * (PAGE_SIZE / 2) + (offset as usize);
unsafe { unsafe {
self.buf_transmuted::<AtomicU16>() self.buf_transmuted::<AtomicU16>()
.get(index) .get(index)
.ok_or(MemAccessFault) .ok_or(ExceptionType::StoreAmoAccessFault)
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_byte( pub fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
&self,
page: PageNum,
offset: u16,
value: Byte,
) -> Result<(), MemAccessFault> {
debug_assert!((offset as usize) < PAGE_SIZE); debug_assert!((offset as usize) < PAGE_SIZE);
let index = page * PAGE_SIZE + (offset as usize); let index = page * PAGE_SIZE + (offset as usize);
self.buf_atomic() self.buf_atomic()
.get(index) .get(index)
.ok_or(MemAccessFault)? .ok_or(ExceptionType::StoreAmoAccessFault)?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
@@ -351,21 +350,16 @@ pub struct DeviceEntry {
} }
pub trait MemDeviceInterface { pub trait MemDeviceInterface {
fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), MemAccessFault>; fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), ExceptionType>;
fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), MemAccessFault>; fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType>;
fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), MemAccessFault>; fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), ExceptionType>;
fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), MemAccessFault>; fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType>;
fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, MemAccessFault>; fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, ExceptionType>;
fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, MemAccessFault>; fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, ExceptionType>;
fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, MemAccessFault>; fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, ExceptionType>;
fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, MemAccessFault>; fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, ExceptionType>;
fn get_atomic_word(&self, page: PageNum, offset: u16) -> Result<&AtomicU32, MemAccessFault>; fn get_atomic_word(&self, page: PageNum, offset: u16) -> Result<&AtomicU32, ExceptionType>;
fn get_atomic_dword(&self, page: PageNum, offset: u16) -> Result<&AtomicU64, MemAccessFault>; fn get_atomic_dword(&self, page: PageNum, offset: u16) -> Result<&AtomicU64, ExceptionType>;
} }
/// Error that means something has gone wrong accessing memory
/// Examples are: Accessing unmapped memory, accessing an MMIO register at the wrong size
#[derive(Debug)]
pub struct MemAccessFault;