Compare commits

..

2 Commits

Author SHA1 Message Date
5c008bfc04 Add exception values (what will go in mtval/stval) 2025-12-27 21:33:39 +01:00
b5d36b7969 Initial FENCE implementation 2025-12-27 21:03:24 +01:00
9 changed files with 304 additions and 160 deletions

View File

@@ -14,7 +14,7 @@ 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::{Addr, Byte}; use trve::consts::{Addr, Byte};
use trve::exceptions::MemoryExceptionType; use trve::exceptions::{MemoryException, MemoryExceptionType};
use trve::mem::MemDeviceInterface; use trve::mem::MemDeviceInterface;
/// byte 0: rx/tx /// byte 0: rx/tx
@@ -78,20 +78,26 @@ impl BasicUart {
} }
impl MemDeviceInterface for BasicUart { impl MemDeviceInterface for BasicUart {
fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> { fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryException> {
match addr { match addr {
0 => { 0 => {
self.write(value); self.write(value);
Ok(()) Ok(())
} }
_ => Err(MemoryExceptionType::AccessFault), _ => Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
}),
} }
} }
fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> { fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryException> {
match addr { match addr {
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(MemoryExceptionType::AccessFault), _ => Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
}),
} }
} }
} }

View File

@@ -10,7 +10,7 @@ use crate::{
consts::{Addr, RegId, RegValue}, consts::{Addr, RegId, RegValue},
core::commands::CoreCmd, core::commands::CoreCmd,
decode::Instruction, decode::Instruction,
exceptions::ExceptionType, exceptions::{Exception, ExceptionType, MemoryException},
gdb::{self, DebugCommand, DebugStream, StopReason}, gdb::{self, DebugCommand, DebugStream, StopReason},
instructions::find_and_exec, instructions::find_and_exec,
mem::MemConfig, mem::MemConfig,
@@ -86,7 +86,8 @@ impl Core {
} => { } => {
let data = (0..len) let data = (0..len)
.map(|offset| self.mem.read_byte(addr + offset)) .map(|offset| self.mem.read_byte(addr + offset))
.collect(); .collect::<Result<_, MemoryException>>()
.map_err(Into::into);
responder.send(data)?; responder.send(data)?;
} }
@@ -101,7 +102,7 @@ impl Core {
Ok(_) => gdb::StopReason::Step, Ok(_) => gdb::StopReason::Step,
Err(e) => { Err(e) => {
self.throw_exception(e); self.throw_exception(e);
gdb::StopReason::Exception(e) gdb::StopReason::Exception(e.into())
} }
})?; })?;
} }
@@ -132,14 +133,17 @@ impl Core {
if let Err(e) = self.step() { if let Err(e) = self.step() {
self.throw_exception(e); self.throw_exception(e);
return StopReason::Exception(e); return StopReason::Exception(e.into());
} }
} }
} }
pub(crate) fn step(&mut self) -> Result<(), ExceptionType> { pub(crate) fn step(&mut self) -> Result<(), Exception> {
if !self.pc.is_multiple_of(4) { if !self.pc.is_multiple_of(4) {
self.throw_exception(ExceptionType::InstructionAddressMisaligned); self.throw_exception(Exception {
type_: ExceptionType::InstructionAddressMisaligned,
value: self.pc,
});
} }
let instr = match self.mem.read_word(self.pc) { let instr = match self.mem.read_word(self.pc) {
@@ -149,13 +153,13 @@ impl Core {
} }
}; };
if instr == 0 {
return Err(ExceptionType::IllegalInstruction);
}
if instr & 3 != 3 { if instr & 3 != 3 {
// Compressed instruction - (currently) unsupported // Compressed instruction - (currently) unsupported
return Err(ExceptionType::IllegalInstruction); // Could also be zero instruction, that also matches this
return Err(Exception {
type_: ExceptionType::IllegalInstruction,
value: instr as u64,
});
} }
let instr = Instruction(instr); let instr = Instruction(instr);
@@ -168,8 +172,8 @@ impl Core {
Ok(()) Ok(())
} }
fn throw_exception(&mut self, exception_type: ExceptionType) { fn throw_exception(&mut self, exception: Exception) {
eprintln!("Exception: {exception_type:?}"); eprintln!("Exception: {exception:?}");
dbg!(self.pc, self.x_regs); dbg!(self.pc, self.x_regs);
} }

View File

@@ -6,6 +6,8 @@
use int_enum::IntEnum; use int_enum::IntEnum;
use crate::consts::{Addr, DWord};
#[repr(u8)] #[repr(u8)]
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)] #[derive(Debug, Clone, Copy, PartialEq, Eq, IntEnum)]
@@ -29,6 +31,12 @@ pub enum ExceptionType {
HardwareError = 19, HardwareError = 19,
} }
#[derive(Debug, Clone, Copy)]
pub struct Exception {
pub type_: ExceptionType,
pub value: DWord,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemoryExceptionType { pub enum MemoryExceptionType {
AddressMisaligned, AddressMisaligned,
@@ -36,28 +44,55 @@ pub enum MemoryExceptionType {
PageFault, PageFault,
} }
impl MemoryExceptionType { #[derive(Debug, Clone, Copy)]
pub(crate) fn to_exception_store(&self) -> ExceptionType { pub struct MemoryException {
match self { pub type_: MemoryExceptionType,
Self::AddressMisaligned => ExceptionType::StoreAmoAddressMisaligned, pub addr: Addr,
Self::AccessFault => ExceptionType::StoreAmoAccessFault, }
Self::PageFault => ExceptionType::StoreAmoPageFault,
impl MemoryException {
pub(crate) fn to_exception_store(&self) -> Exception {
Exception {
type_: match self.type_ {
MemoryExceptionType::AddressMisaligned => ExceptionType::StoreAmoAddressMisaligned,
MemoryExceptionType::AccessFault => ExceptionType::StoreAmoAccessFault,
MemoryExceptionType::PageFault => ExceptionType::StoreAmoPageFault,
},
value: self.addr,
} }
} }
pub(crate) fn to_exception_instr(&self) -> ExceptionType { pub(crate) fn to_exception_instr(&self) -> Exception {
match self { Exception {
Self::AddressMisaligned => ExceptionType::InstructionAddressMisaligned, type_: match self.type_ {
Self::AccessFault => ExceptionType::InstructionAccessFault, MemoryExceptionType::AddressMisaligned => ExceptionType::InstructionAccessFault,
Self::PageFault => ExceptionType::InstructionPageFault, MemoryExceptionType::AccessFault => ExceptionType::InstructionAccessFault,
MemoryExceptionType::PageFault => ExceptionType::InstructionPageFault,
},
value: self.addr,
} }
} }
pub(crate) fn to_exception_load(&self) -> ExceptionType { pub(crate) fn to_exception_load(&self) -> Exception {
match self { Exception {
Self::AddressMisaligned => ExceptionType::LoadAddressMisaligned, type_: match self.type_ {
Self::AccessFault => ExceptionType::LoadAccessFault, MemoryExceptionType::AddressMisaligned => ExceptionType::LoadAddressMisaligned,
Self::PageFault => ExceptionType::LoadPageFault, MemoryExceptionType::AccessFault => ExceptionType::LoadAccessFault,
MemoryExceptionType::PageFault => ExceptionType::LoadPageFault,
},
value: self.addr,
} }
} }
} }
impl Into<MemoryExceptionType> for MemoryException {
fn into(self) -> MemoryExceptionType {
self.type_
}
}
impl Into<ExceptionType> for Exception {
fn into(self) -> ExceptionType {
self.type_
}
}

View File

@@ -10,12 +10,20 @@ mod macros;
mod rvi; mod rvi;
use crate::{ use crate::{
consts::DWord,
core::Core, core::Core,
decode::Instruction, decode::Instruction,
exceptions::ExceptionType::{self, IllegalInstruction}, exceptions::{Exception, ExceptionType::IllegalInstruction},
}; };
pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), ExceptionType> { fn illegal(instr: Instruction) -> Result<(), Exception> {
Err(Exception {
type_: IllegalInstruction,
value: instr.0 as DWord,
})
}
pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), Exception> {
match instr.opcode_noncompressed() { match instr.opcode_noncompressed() {
0b01100 => match (instr.funct3(), instr.funct7()) { 0b01100 => match (instr.funct3(), instr.funct7()) {
// OP // OP
@@ -29,7 +37,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
(0b111, 0b0000000) => rvi::and(core, instr), (0b111, 0b0000000) => rvi::and(core, instr),
(0b100, 0b0000000) => rvi::xor(core, instr), (0b100, 0b0000000) => rvi::xor(core, instr),
(0b110, 0b0000000) => rvi::or(core, instr), (0b110, 0b0000000) => rvi::or(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b01110 => match (instr.funct3(), instr.funct7()) { 0b01110 => match (instr.funct3(), instr.funct7()) {
// OP_32 // OP_32
@@ -38,7 +46,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
(0b001, 0b0000000) => rvi::sllw(core, instr), (0b001, 0b0000000) => rvi::sllw(core, instr),
(0b101, 0b0000000) => rvi::srlw(core, instr), (0b101, 0b0000000) => rvi::srlw(core, instr),
(0b101, 0b0100000) => rvi::sraw(core, instr), (0b101, 0b0100000) => rvi::sraw(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b00100 => match instr.funct3() { 0b00100 => match instr.funct3() {
// OP_IMM // OP_IMM
@@ -47,31 +55,31 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
0b011 => rvi::sltiu(core, instr), 0b011 => rvi::sltiu(core, instr),
0b001 => match instr.funct6() { 0b001 => match instr.funct6() {
0 => rvi::slli(core, instr), 0 => rvi::slli(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b101 => match instr.funct6() { 0b101 => match instr.funct6() {
0b000000 => rvi::srli(core, instr), 0b000000 => rvi::srli(core, instr),
0b010000 => rvi::srai(core, instr), 0b010000 => rvi::srai(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b100 => rvi::xori(core, instr), 0b100 => rvi::xori(core, instr),
0b110 => rvi::ori(core, instr), 0b110 => rvi::ori(core, instr),
0b111 => rvi::andi(core, instr), 0b111 => rvi::andi(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b00110 => match instr.funct3() { 0b00110 => match instr.funct3() {
// OP_IMM_32 // OP_IMM_32
0b000 => rvi::addiw(core, instr), 0b000 => rvi::addiw(core, instr),
0b001 => match instr.funct7() { 0b001 => match instr.funct7() {
0 => rvi::slliw(core, instr), 0 => rvi::slliw(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b101 => match instr.funct7() { 0b101 => match instr.funct7() {
0b0000000 => rvi::srliw(core, instr), 0b0000000 => rvi::srliw(core, instr),
0b0100000 => rvi::sraiw(core, instr), 0b0100000 => rvi::sraiw(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b01000 => match instr.funct3() { 0b01000 => match instr.funct3() {
// STORE // STORE
@@ -79,7 +87,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
0b001 => rvi::sh(core, instr), 0b001 => rvi::sh(core, instr),
0b010 => rvi::sw(core, instr), 0b010 => rvi::sw(core, instr),
0b011 => rvi::sd(core, instr), 0b011 => rvi::sd(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b00000 => match instr.funct3() { 0b00000 => match instr.funct3() {
// LOAD // LOAD
@@ -90,7 +98,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
0b010 => rvi::lw(core, instr), 0b010 => rvi::lw(core, instr),
0b110 => rvi::lwu(core, instr), 0b110 => rvi::lwu(core, instr),
0b011 => rvi::ld(core, instr), 0b011 => rvi::ld(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b11000 => match instr.funct3() { 0b11000 => match instr.funct3() {
// BRANCH // BRANCH
@@ -100,7 +108,7 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
0b101 => rvi::bge(core, instr), 0b101 => rvi::bge(core, instr),
0b110 => rvi::bltu(core, instr), 0b110 => rvi::bltu(core, instr),
0b111 => rvi::bgeu(core, instr), 0b111 => rvi::bgeu(core, instr),
_ => Err(IllegalInstruction), _ => illegal(instr),
}, },
0b01101 => rvi::lui(core, instr), 0b01101 => rvi::lui(core, instr),
0b00101 => rvi::auipc(core, instr), 0b00101 => rvi::auipc(core, instr),
@@ -109,9 +117,19 @@ pub(crate) fn find_and_exec(instr: Instruction, core: &mut Core) -> Result<(), E
if instr.funct3() == 0 { if instr.funct3() == 0 {
rvi::jalr(core, instr) rvi::jalr(core, instr)
} else { } else {
Err(IllegalInstruction) illegal(instr)
} }
} }
_ => Err(IllegalInstruction), 0b00011 => match instr.funct3() {
// MISC_MEM
0b000 => {
// FENCE is just implemented as a SeqCst fence always here
// I dont yet care about the potential performance issue this may bring
std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst);
Ok(())
}
_ => illegal(instr),
},
_ => illegal(instr),
} }
} }

View File

@@ -7,7 +7,7 @@
#[macro_export] #[macro_export]
macro_rules! instr_branch { macro_rules! instr_branch {
($name:ident, $cond:expr) => { ($name:ident, $cond:expr) => {
pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
let a = core.reg_read(instr.rs1()); let a = core.reg_read(instr.rs1());
let b = core.reg_read(instr.rs2()); let b = core.reg_read(instr.rs2());
if $cond(a, b) { if $cond(a, b) {
@@ -30,7 +30,7 @@ macro_rules! instr_branch_signed {
#[macro_export] #[macro_export]
macro_rules! instr_op_r { macro_rules! instr_op_r {
($name:ident, $op:expr) => { ($name:ident, $op:expr) => {
pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
let a = core.reg_read(instr.rs1()); let a = core.reg_read(instr.rs1());
let b = core.reg_read(instr.rs2()); let b = core.reg_read(instr.rs2());
let res = $op(a, b); let res = $op(a, b);
@@ -44,7 +44,7 @@ macro_rules! instr_op_r {
#[macro_export] #[macro_export]
macro_rules! instr_op_i { macro_rules! instr_op_i {
($name:ident, $op:expr) => { ($name:ident, $op:expr) => {
pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn $name(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
let a = core.reg_read(instr.rs1()); let a = core.reg_read(instr.rs1());
let b = instr.imm_i(); let b = instr.imm_i();
let res = $op(a, b); let res = $op(a, b);

View File

@@ -4,7 +4,7 @@
// 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::{consts::RegValue, core::Core, decode::Instruction, exceptions::ExceptionType}; use crate::{consts::RegValue, core::Core, decode::Instruction, exceptions::Exception};
use std::ops::{BitAnd, BitOr, BitXor}; use std::ops::{BitAnd, BitOr, BitXor};
@@ -49,25 +49,25 @@ instr_op!(
instr_op!(sltu, sltiu, |a, b| (a < b) as RegValue); instr_op!(sltu, sltiu, |a, b| (a < b) as RegValue);
instr_op!(slt, slti, |a, b| ((a as i64) < (b as i64)) as RegValue); instr_op!(slt, slti, |a, b| ((a as i64) < (b as i64)) as RegValue);
pub fn lui(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lui(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
core.reg_write(instr.rd(), instr.imm_u()); core.reg_write(instr.rd(), instr.imm_u());
core.advance_pc(); core.advance_pc();
Ok(()) Ok(())
} }
pub fn auipc(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn auipc(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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();
Ok(()) Ok(())
} }
pub fn jal(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn jal(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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());
Ok(()) Ok(())
} }
pub fn jalr(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn jalr(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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());
Ok(()) Ok(())

View File

@@ -7,11 +7,11 @@
use crate::{ use crate::{
consts::{Byte, DWord, HWord, Word}, consts::{Byte, DWord, HWord, Word},
core::Core, core::Core,
exceptions::ExceptionType, exceptions::Exception,
instructions::Instruction, instructions::Instruction,
}; };
pub fn sd(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sd(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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 value = core.reg_read(instr.rs2()); let value = core.reg_read(instr.rs2());
core.mem core.mem
@@ -21,7 +21,7 @@ pub fn sd(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn ld(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn ld(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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( core.reg_write(
instr.rd(), instr.rd(),
@@ -33,7 +33,7 @@ pub fn ld(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn sw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sw(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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 value = core.reg_read(instr.rs2()) as Word; let value = core.reg_read(instr.rs2()) as Word;
core.mem core.mem
@@ -43,7 +43,7 @@ pub fn sw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn lw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lw(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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( core.reg_write(
instr.rd(), instr.rd(),
@@ -55,7 +55,7 @@ pub fn lw(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn lwu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lwu(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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( core.reg_write(
instr.rd(), instr.rd(),
@@ -67,7 +67,7 @@ pub fn lwu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn sh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sh(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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 value = core.reg_read(instr.rs2()) as HWord; let value = core.reg_read(instr.rs2()) as HWord;
core.mem core.mem
@@ -77,7 +77,7 @@ pub fn sh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn lh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lh(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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( core.reg_write(
instr.rd(), instr.rd(),
@@ -89,7 +89,7 @@ pub fn lh(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn lhu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lhu(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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( core.reg_write(
instr.rd(), instr.rd(),
@@ -101,7 +101,7 @@ pub fn lhu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn sb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn sb(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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 value = core.reg_read(instr.rs2()) as Byte; let value = core.reg_read(instr.rs2()) as Byte;
core.mem core.mem
@@ -111,7 +111,7 @@ pub fn sb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn lb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lb(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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( core.reg_write(
instr.rd(), instr.rd(),
@@ -123,7 +123,7 @@ pub fn lb(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> {
Ok(()) Ok(())
} }
pub fn lbu(core: &mut Core, instr: Instruction) -> Result<(), ExceptionType> { pub fn lbu(core: &mut Core, instr: Instruction) -> Result<(), Exception> {
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( core.reg_write(
instr.rd(), instr.rd(),

View File

@@ -11,7 +11,7 @@ use clap::Parser;
use trve::{ use trve::{
consts::{Addr, Byte, DWord, HWord, Word}, consts::{Addr, Byte, DWord, HWord, Word},
core::Core, core::Core,
exceptions::MemoryExceptionType, exceptions::MemoryException,
gdb, gdb,
mem::{MemConfig, MemDeviceInterface, MmioRoot, Ram}, mem::{MemConfig, MemDeviceInterface, MmioRoot, Ram},
}; };
@@ -70,22 +70,22 @@ mod basic_uart;
struct DbgOut; struct DbgOut;
impl MemDeviceInterface for DbgOut { impl MemDeviceInterface for DbgOut {
fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> { fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryException> {
eprintln!("Wrote DWord {value:016x} to Debug-Out address {addr:x}"); eprintln!("Wrote DWord {value:016x} to Debug-Out address {addr:x}");
Ok(()) Ok(())
} }
fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> { fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryException> {
eprintln!("Wrote Word {value:08x} to Debug-Out address {addr:x}"); eprintln!("Wrote Word {value:08x} to Debug-Out address {addr:x}");
Ok(()) Ok(())
} }
fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> { fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryException> {
eprintln!("Wrote HWord {value:04x} to Debug-Out address {addr:x}"); eprintln!("Wrote HWord {value:04x} to Debug-Out address {addr:x}");
Ok(()) Ok(())
} }
fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> { fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryException> {
eprintln!("Wrote Byte {value:02x} to Debug-Out address {addr:x}"); eprintln!("Wrote Byte {value:02x} to Debug-Out address {addr:x}");
Ok(()) Ok(())
} }

View File

@@ -13,7 +13,7 @@ use memmap2::MmapMut;
use crate::{ use crate::{
consts::{Addr, Byte, DWord, HWord, Word}, consts::{Addr, Byte, DWord, HWord, Word},
exceptions::MemoryExceptionType, exceptions::{MemoryException, MemoryExceptionType},
}; };
pub type PageNum = usize; pub type PageNum = usize;
@@ -37,119 +37,140 @@ impl MemConfig {
} }
} }
pub fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryExceptionType> { pub fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.read_dword(addr - RAM_START) self.ram.read_dword(addr - RAM_START)
} else { } else {
if !addr.is_multiple_of(8) && self.mmio_root.crosses_boundary(addr, 8) { if !addr.is_multiple_of(8) && self.mmio_root.crosses_boundary(addr, 8) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.read_dword(addr) interface.read_dword(addr)
} }
} }
pub fn read_word(&self, addr: Addr) -> Result<Word, MemoryExceptionType> { pub fn read_word(&self, addr: Addr) -> Result<Word, MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.read_word(addr - RAM_START) self.ram.read_word(addr - RAM_START)
} else { } else {
if !addr.is_multiple_of(4) && self.mmio_root.crosses_boundary(addr, 4) { if !addr.is_multiple_of(4) && self.mmio_root.crosses_boundary(addr, 4) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.read_word(addr) interface.read_word(addr)
} }
} }
pub fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryExceptionType> { pub fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.read_hword(addr - RAM_START) self.ram.read_hword(addr - RAM_START)
} else { } else {
if !addr.is_multiple_of(2) && self.mmio_root.crosses_boundary(addr, 2) { if !addr.is_multiple_of(2) && self.mmio_root.crosses_boundary(addr, 2) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.read_hword(addr) interface.read_hword(addr)
} }
} }
pub fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> { pub fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.read_byte(addr - RAM_START) self.ram.read_byte(addr - RAM_START)
} else { } else {
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.read_byte(addr) interface.read_byte(addr)
} }
} }
pub fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> { pub fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.write_dword(addr - RAM_START, value) self.ram.write_dword(addr - RAM_START, value)
} else { } else {
if !addr.is_multiple_of(8) && self.mmio_root.crosses_boundary(addr, 8) { if !addr.is_multiple_of(8) && self.mmio_root.crosses_boundary(addr, 8) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.write_dword(addr, value) interface.write_dword(addr, value)
} }
} }
pub fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> { pub fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.write_word(addr - RAM_START, value) self.ram.write_word(addr - RAM_START, value)
} else { } else {
if !addr.is_multiple_of(4) && self.mmio_root.crosses_boundary(addr, 4) { if !addr.is_multiple_of(4) && self.mmio_root.crosses_boundary(addr, 4) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.write_word(addr, value) interface.write_word(addr, value)
} }
} }
pub fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> { pub fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.write_hword(addr - RAM_START, value) self.ram.write_hword(addr - RAM_START, value)
} else { } else {
if !addr.is_multiple_of(2) && self.mmio_root.crosses_boundary(addr, 2) { if !addr.is_multiple_of(2) && self.mmio_root.crosses_boundary(addr, 2) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.write_hword(addr, value) interface.write_hword(addr, value)
} }
} }
pub fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> { pub fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryException> {
if addr >= RAM_START { if addr >= RAM_START {
self.ram.write_byte(addr - RAM_START, value) self.ram.write_byte(addr - RAM_START, value)
} else { } else {
let (interface, addr) = self let (interface, addr) = self.mmio_root.get_device(addr).ok_or(MemoryException {
.mmio_root type_: MemoryExceptionType::AccessFault,
.get_device(addr) addr,
.ok_or(MemoryExceptionType::AccessFault)?; })?;
interface.write_byte(addr, value) interface.write_byte(addr, value)
} }
} }
pub fn get_atomic_dword(&self, addr: Addr) -> Result<&AtomicU64, MemoryExceptionType> { pub fn get_atomic_dword(&self, addr: Addr) -> Result<&AtomicU64, MemoryException> {
if !addr.is_multiple_of(8) { if !addr.is_multiple_of(8) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
let index = ((addr - RAM_START) / 8) as usize; let index = ((addr - RAM_START) / 8) as usize;
@@ -157,16 +178,25 @@ impl MemConfig {
self.ram self.ram
.buf_transmuted::<AtomicU64>() .buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
} }
pub fn get_atomic_word(&self, addr: Addr) -> Result<&AtomicU32, MemoryExceptionType> { pub fn get_atomic_word(&self, addr: Addr) -> Result<&AtomicU32, MemoryException> {
if !addr.is_multiple_of(4) { if !addr.is_multiple_of(4) {
return Err(MemoryExceptionType::AddressMisaligned); return Err(MemoryException {
type_: MemoryExceptionType::AddressMisaligned,
addr,
});
} }
if addr < RAM_START { if addr < RAM_START {
return Err(MemoryExceptionType::AccessFault); return Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
});
} }
let index = ((addr - RAM_START) / 4) as usize; let index = ((addr - RAM_START) / 4) as usize;
@@ -174,7 +204,10 @@ impl MemConfig {
self.ram self.ram
.buf_transmuted::<AtomicU32>() .buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
} }
} }
@@ -229,7 +262,7 @@ impl Ram {
} }
#[inline] #[inline]
pub fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryExceptionType> { pub fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryException> {
if !addr.is_multiple_of(8) { if !addr.is_multiple_of(8) {
let high_word_addr = addr.wrapping_add(4); let high_word_addr = addr.wrapping_add(4);
@@ -243,12 +276,15 @@ impl Ram {
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU64>() self.buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_word(&self, addr: Addr) -> Result<Word, MemoryExceptionType> { pub fn read_word(&self, addr: Addr) -> Result<Word, MemoryException> {
if !addr.is_multiple_of(4) { if !addr.is_multiple_of(4) {
let high_hword_addr = addr.wrapping_add(2); let high_hword_addr = addr.wrapping_add(2);
@@ -262,12 +298,15 @@ impl Ram {
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU32>() self.buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryExceptionType> { pub fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryException> {
if !addr.is_multiple_of(2) { if !addr.is_multiple_of(2) {
let high_byte_addr = addr.wrapping_add(1); let high_byte_addr = addr.wrapping_add(1);
@@ -281,21 +320,27 @@ impl Ram {
Ok(unsafe { Ok(unsafe {
self.buf_transmuted::<AtomicU16>() self.buf_transmuted::<AtomicU16>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
}? }?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> { pub fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryException> {
Ok(self Ok(self
.buf_atomic() .buf_atomic()
.get(addr as usize) .get(addr as usize)
.ok_or(MemoryExceptionType::AccessFault)? .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})?
.load(Relaxed)) .load(Relaxed))
} }
#[inline] #[inline]
pub fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> { pub fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryException> {
if !addr.is_multiple_of(8) { if !addr.is_multiple_of(8) {
let low_word = value as Word; let low_word = value as Word;
let high_word = (value >> 32) as Word; let high_word = (value >> 32) as Word;
@@ -311,13 +356,16 @@ impl Ram {
unsafe { unsafe {
self.buf_transmuted::<AtomicU64>() self.buf_transmuted::<AtomicU64>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> { pub fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryException> {
if !addr.is_multiple_of(4) { if !addr.is_multiple_of(4) {
let low_hword = value as HWord; let low_hword = value as HWord;
let high_hword = (value >> 16) as HWord; let high_hword = (value >> 16) as HWord;
@@ -333,13 +381,16 @@ impl Ram {
unsafe { unsafe {
self.buf_transmuted::<AtomicU32>() self.buf_transmuted::<AtomicU32>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> { pub fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryException> {
if !addr.is_multiple_of(2) { if !addr.is_multiple_of(2) {
let low_byte = value as Byte; let low_byte = value as Byte;
let high_byte = (value >> 8) as Byte; let high_byte = (value >> 8) as Byte;
@@ -355,16 +406,22 @@ impl Ram {
unsafe { unsafe {
self.buf_transmuted::<AtomicU16>() self.buf_transmuted::<AtomicU16>()
.get(index) .get(index)
.ok_or(MemoryExceptionType::AccessFault) .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
}? }?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
#[inline] #[inline]
pub fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> { pub fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryException> {
self.buf_atomic() self.buf_atomic()
.get(addr as usize) .get(addr as usize)
.ok_or(MemoryExceptionType::AccessFault)? .ok_or(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})?
.store(value, Relaxed); .store(value, Relaxed);
Ok(()) Ok(())
} }
@@ -477,29 +534,53 @@ impl Default for MmioSecondLevel {
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait MemDeviceInterface { pub trait MemDeviceInterface {
fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryExceptionType> { fn write_dword(&self, addr: Addr, value: DWord) -> Result<(), MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryExceptionType> { fn write_word(&self, addr: Addr, value: Word) -> Result<(), MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryExceptionType> { fn write_hword(&self, addr: Addr, value: HWord) -> Result<(), MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryExceptionType> { fn write_byte(&self, addr: Addr, value: Byte) -> Result<(), MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryExceptionType> { fn read_dword(&self, addr: Addr) -> Result<DWord, MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
fn read_word(&self, addr: Addr) -> Result<Word, MemoryExceptionType> { fn read_word(&self, addr: Addr) -> Result<Word, MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryExceptionType> { fn read_hword(&self, addr: Addr) -> Result<HWord, MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryExceptionType> { fn read_byte(&self, addr: Addr) -> Result<Byte, MemoryException> {
Err(MemoryExceptionType::AccessFault) Err(MemoryException {
type_: MemoryExceptionType::AccessFault,
addr,
})
} }
} }