EXCEPTION SYSTEM (initial version - may change later)
This commit is contained in:
@@ -14,7 +14,8 @@ use std::time::Duration;
|
||||
use nix::fcntl::fcntl;
|
||||
use nix::fcntl::{FcntlArg, OFlag};
|
||||
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 1: status (------rt, r=rxready, t=txready)/none
|
||||
@@ -82,12 +83,12 @@ impl MemDeviceInterface for BasicUart {
|
||||
_page: PageNum,
|
||||
_offset: u16,
|
||||
_value: DWord,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
) -> Result<(), ExceptionType> {
|
||||
Err(ExceptionType::StoreAmoAccessFault)
|
||||
}
|
||||
|
||||
fn write_word(&self, _page: PageNum, _offset: u16, _value: Word) -> Result<(), MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
fn write_word(&self, _page: PageNum, _offset: u16, _value: Word) -> Result<(), ExceptionType> {
|
||||
Err(ExceptionType::StoreAmoAccessFault)
|
||||
}
|
||||
|
||||
fn write_hword(
|
||||
@@ -95,13 +96,13 @@ impl MemDeviceInterface for BasicUart {
|
||||
_page: PageNum,
|
||||
_offset: u16,
|
||||
_value: HWord,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
) -> Result<(), ExceptionType> {
|
||||
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 {
|
||||
return Err(MemAccessFault);
|
||||
return Err(ExceptionType::StoreAmoAccessFault);
|
||||
}
|
||||
|
||||
match offset {
|
||||
@@ -109,31 +110,31 @@ impl MemDeviceInterface for BasicUart {
|
||||
self.write(value);
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(MemAccessFault),
|
||||
_ => Err(ExceptionType::StoreAmoAccessFault),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, ExceptionType> {
|
||||
Err(ExceptionType::LoadAccessFault)
|
||||
}
|
||||
|
||||
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, ExceptionType> {
|
||||
Err(ExceptionType::LoadAccessFault)
|
||||
}
|
||||
|
||||
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, ExceptionType> {
|
||||
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 {
|
||||
return Err(MemAccessFault);
|
||||
return Err(ExceptionType::LoadAccessFault);
|
||||
}
|
||||
|
||||
match offset {
|
||||
0 => Ok(self.read()),
|
||||
1 => Ok(1 | (self.can_read() as u8) << 1),
|
||||
_ => Err(MemAccessFault),
|
||||
_ => Err(ExceptionType::LoadAccessFault),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,15 +142,15 @@ impl MemDeviceInterface for BasicUart {
|
||||
&self,
|
||||
_page: PageNum,
|
||||
_offset: u16,
|
||||
) -> Result<&std::sync::atomic::AtomicU32, MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
) -> Result<&std::sync::atomic::AtomicU32, ExceptionType> {
|
||||
Err(ExceptionType::StoreAmoAccessFault)
|
||||
}
|
||||
|
||||
fn get_atomic_dword(
|
||||
&self,
|
||||
_page: PageNum,
|
||||
_offset: u16,
|
||||
) -> Result<&std::sync::atomic::AtomicU64, MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
) -> Result<&std::sync::atomic::AtomicU64, ExceptionType> {
|
||||
Err(ExceptionType::StoreAmoAccessFault)
|
||||
}
|
||||
}
|
||||
|
||||
50
src/core.rs
50
src/core.rs
@@ -7,19 +7,11 @@
|
||||
use crate::{
|
||||
consts::{Addr, RegId, RegValue},
|
||||
decode::Instruction,
|
||||
exceptions::ExceptionType,
|
||||
instructions::find_and_exec,
|
||||
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(crate) x_regs: [RegValue; 32],
|
||||
pub(crate) pc: Addr,
|
||||
@@ -40,50 +32,46 @@ impl Core {
|
||||
let page = (self.pc / 4096) as usize;
|
||||
let offset = (self.pc % 4096 / 4) as u16;
|
||||
if !self.pc.is_multiple_of(4) {
|
||||
//replace eprint with logging, replace break with exception
|
||||
eprintln!("PC not aligned");
|
||||
self.throw_exception(ExceptionType::InstructionAccessMisaligned);
|
||||
break;
|
||||
}
|
||||
|
||||
let instr = match self.mem.read_word(page, offset) {
|
||||
Ok(i) => i,
|
||||
Err(_) => {
|
||||
eprintln!("Memory access fault while fetching instruction");
|
||||
eprintln!("PC: {:x}", self.pc);
|
||||
self.throw_exception(ExceptionType::InstructionAccessFault);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if instr == 0 {
|
||||
eprintln!("Executing 0 instruction at {:x}", self.pc);
|
||||
self.throw_exception(ExceptionType::IllegalInstruction);
|
||||
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 res = find_and_exec(instr, self);
|
||||
|
||||
if let Some(res) = res {
|
||||
match res {
|
||||
InstructionResult::Normal => {}
|
||||
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;
|
||||
// }
|
||||
match find_and_exec(instr, self) {
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
self.throw_exception(e);
|
||||
eprintln!("instr: {:08x}", instr.0);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
eprintln!("Invalid Instruction {:08x} at PC: {:x}", instr.0, self.pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn throw_exception(&mut self, exception_type: ExceptionType) {
|
||||
eprintln!("Exception: {exception_type:?}");
|
||||
dbg!(self.pc, self.x_regs);
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, pc: Addr) {
|
||||
self.pc = pc;
|
||||
}
|
||||
|
||||
30
src/exceptions.rs
Normal file
30
src/exceptions.rs
Normal 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,
|
||||
}
|
||||
@@ -7,67 +7,81 @@
|
||||
mod rvi;
|
||||
|
||||
use crate::{
|
||||
core::{Core, InstructionResult},
|
||||
core::Core,
|
||||
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() {
|
||||
0b01100 => match (instr.funct7(), instr.funct3()) {
|
||||
// OP
|
||||
(0b0000000, 0b000) => Some(rvi::add(core, instr)),
|
||||
(0b0100000, 0b000) => Some(rvi::sub(core, instr)),
|
||||
(0b0000000, 0b111) => Some(rvi::and(core, instr)),
|
||||
(0b0000000, 0b110) => Some(rvi::or(core, instr)),
|
||||
_ => None,
|
||||
(0b0000000, 0b000) => rvi::add(core, instr),
|
||||
(0b0100000, 0b000) => rvi::sub(core, instr),
|
||||
(0b0000000, 0b111) => rvi::and(core, instr),
|
||||
(0b0000000, 0b110) => rvi::or(core, instr),
|
||||
_ => Err(IllegalInstruction),
|
||||
},
|
||||
0b00100 => match instr.funct3() {
|
||||
// OP_IMM
|
||||
0b000 => Some(rvi::addi(core, instr)),
|
||||
0b001 => (instr.funct6() == 0).then(|| rvi::slli(core, instr)),
|
||||
0b000 => rvi::addi(core, instr),
|
||||
0b001 => {
|
||||
if instr.funct6() == 0 {
|
||||
rvi::slli(core, instr)
|
||||
} else {
|
||||
Err(IllegalInstruction)
|
||||
}
|
||||
}
|
||||
0b101 => match instr.funct6() {
|
||||
// immediate right-shift
|
||||
0b000000 => Some(rvi::srli(core, instr)),
|
||||
_ => None,
|
||||
0b000000 => rvi::srli(core, instr),
|
||||
_ => Err(IllegalInstruction),
|
||||
},
|
||||
0b111 => Some(rvi::andi(core, instr)),
|
||||
_ => None,
|
||||
0b111 => rvi::andi(core, instr),
|
||||
_ => Err(IllegalInstruction),
|
||||
},
|
||||
0b00110 => match instr.funct3() {
|
||||
// OP_IMM_32
|
||||
0b000 => Some(rvi::addiw(core, instr)),
|
||||
_ => None,
|
||||
0b000 => rvi::addiw(core, instr),
|
||||
_ => Err(IllegalInstruction),
|
||||
},
|
||||
0b01000 => match instr.funct3() {
|
||||
// STORE
|
||||
0b000 => Some(rvi::sb(core, instr)),
|
||||
0b001 => Some(rvi::sh(core, instr)),
|
||||
0b010 => Some(rvi::sw(core, instr)),
|
||||
0b011 => Some(rvi::sd(core, instr)),
|
||||
_ => None,
|
||||
0b000 => rvi::sb(core, instr),
|
||||
0b001 => rvi::sh(core, instr),
|
||||
0b010 => rvi::sw(core, instr),
|
||||
0b011 => rvi::sd(core, instr),
|
||||
_ => Err(IllegalInstruction),
|
||||
},
|
||||
0b00000 => match instr.funct3() {
|
||||
// LOAD
|
||||
0b000 => Some(rvi::lb(core, instr)),
|
||||
0b100 => Some(rvi::lbu(core, instr)),
|
||||
0b001 => Some(rvi::lh(core, instr)),
|
||||
0b010 => Some(rvi::lw(core, instr)),
|
||||
0b011 => Some(rvi::ld(core, instr)),
|
||||
_ => None,
|
||||
0b000 => rvi::lb(core, instr),
|
||||
0b100 => rvi::lbu(core, instr),
|
||||
0b001 => rvi::lh(core, instr),
|
||||
0b010 => rvi::lw(core, instr),
|
||||
0b011 => rvi::ld(core, instr),
|
||||
_ => Err(IllegalInstruction),
|
||||
},
|
||||
0b11000 => match instr.funct3() {
|
||||
// BRANCH
|
||||
0b000 => Some(rvi::beq(core, instr)),
|
||||
0b001 => Some(rvi::bne(core, instr)),
|
||||
0b100 => Some(rvi::blt(core, instr)),
|
||||
0b110 => Some(rvi::bltu(core, instr)),
|
||||
0b111 => Some(rvi::bgeu(core, instr)),
|
||||
_ => None,
|
||||
0b000 => rvi::beq(core, instr),
|
||||
0b001 => rvi::bne(core, instr),
|
||||
0b100 => rvi::blt(core, instr),
|
||||
0b110 => rvi::bltu(core, instr),
|
||||
0b111 => rvi::bgeu(core, instr),
|
||||
_ => Err(IllegalInstruction),
|
||||
},
|
||||
0b01101 => Some(rvi::lui(core, instr)),
|
||||
0b00101 => Some(rvi::auipc(core, instr)),
|
||||
0b11011 => Some(rvi::jal(core, instr)),
|
||||
0b11001 => (instr.funct3() == 0).then(|| rvi::jalr(core, instr)),
|
||||
_ => None,
|
||||
0b01101 => rvi::lui(core, instr),
|
||||
0b00101 => rvi::auipc(core, instr),
|
||||
0b11011 => rvi::jal(core, instr),
|
||||
// 0b11001 => (instr.funct3() == 0).then(|| rvi::jalr(core, instr)),
|
||||
0b11001 => {
|
||||
if instr.funct3() == 0 {
|
||||
rvi::jalr(core, instr)
|
||||
} else {
|
||||
Err(IllegalInstruction)
|
||||
}
|
||||
}
|
||||
_ => Err(IllegalInstruction),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,157 +4,154 @@
|
||||
// This file is part of TRVE (https://gitea.taitep.se/taitep/trve)
|
||||
// See LICENSE file in the project root for full license text.
|
||||
|
||||
use crate::{
|
||||
core::{Core, InstructionResult},
|
||||
decode::Instruction,
|
||||
};
|
||||
use crate::{core::Core, decode::Instruction, exceptions::ExceptionType};
|
||||
|
||||
mod 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(
|
||||
instr.rd(),
|
||||
core.reg_read(instr.rs1())
|
||||
.wrapping_add(core.reg_read(instr.rs2())),
|
||||
);
|
||||
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(
|
||||
instr.rd(),
|
||||
core.reg_read(instr.rs1())
|
||||
.wrapping_sub(core.reg_read(instr.rs2())),
|
||||
);
|
||||
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(
|
||||
instr.rd(),
|
||||
core.reg_read(instr.rs1()).wrapping_add(instr.imm_i()),
|
||||
);
|
||||
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;
|
||||
core.reg_write(instr.rd(), res as i64 as u64);
|
||||
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(
|
||||
instr.rd(),
|
||||
core.reg_read(instr.rs1()) & core.reg_read(instr.rs2()),
|
||||
);
|
||||
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.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(
|
||||
instr.rd(),
|
||||
core.reg_read(instr.rs1()) | core.reg_read(instr.rs2()),
|
||||
);
|
||||
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.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.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.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.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.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.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()) {
|
||||
core.pc = core.pc.wrapping_add(instr.imm_b());
|
||||
} else {
|
||||
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()) {
|
||||
core.pc = core.pc.wrapping_add(instr.imm_b());
|
||||
} else {
|
||||
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) {
|
||||
core.pc = core.pc.wrapping_add(instr.imm_b());
|
||||
} else {
|
||||
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()) {
|
||||
core.pc = core.pc.wrapping_add(instr.imm_b());
|
||||
} else {
|
||||
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()) {
|
||||
core.pc = core.pc.wrapping_add(instr.imm_b());
|
||||
} else {
|
||||
core.advance_pc();
|
||||
}
|
||||
|
||||
InstructionResult::Normal
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -7,177 +7,145 @@
|
||||
use crate::{
|
||||
consts::{Addr, Byte, DWord, HWord, Word},
|
||||
core::Core,
|
||||
instructions::{Instruction, InstructionResult},
|
||||
exceptions::ExceptionType,
|
||||
instructions::Instruction,
|
||||
mem::PageNum,
|
||||
};
|
||||
|
||||
// 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());
|
||||
|
||||
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 offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16;
|
||||
let value = core.reg_read(instr.rs2());
|
||||
|
||||
match core.mem.write_dword(page, offset, value) {
|
||||
Ok(_) => {
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.mem.write_dword(page, offset, value)?;
|
||||
core.advance_pc();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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 offset = (addr / 8 & ((4096 / 8 as Addr) - 1)) as u16;
|
||||
|
||||
match core.mem.read_dword(page, offset) {
|
||||
Ok(x) => {
|
||||
core.reg_write(instr.rd(), x);
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.reg_write(instr.rd(), core.mem.read_dword(page, offset)?);
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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 offset = (addr / 4 & ((4096 / 4 as Addr) - 1)) as u16;
|
||||
let value = core.reg_read(instr.rs2()) as Word;
|
||||
|
||||
match core.mem.write_word(page, offset, value) {
|
||||
Ok(_) => {
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.mem.write_word(page, offset, value)?;
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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 offset = (addr / 4 & ((4096 / 4 as Addr) - 1)) as u16;
|
||||
|
||||
match core.mem.read_word(page, offset) {
|
||||
Ok(x) => {
|
||||
core.reg_write(instr.rd(), x as i32 as i64 as DWord);
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.reg_write(
|
||||
instr.rd(),
|
||||
core.mem.read_word(page, offset)? as i32 as i64 as DWord,
|
||||
);
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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 offset = (addr / 2 & ((4096 / 2 as Addr) - 1)) as u16;
|
||||
let value = core.reg_read(instr.rs2()) as HWord;
|
||||
|
||||
match core.mem.write_hword(page, offset, value) {
|
||||
Ok(_) => {
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.mem.write_hword(page, offset, value)?;
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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 offset = (addr / 2 & ((4096 / 2 as Addr) - 1)) as u16;
|
||||
|
||||
match core.mem.read_hword(page, offset) {
|
||||
Ok(x) => {
|
||||
core.reg_write(instr.rd(), x as i16 as i64 as DWord);
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.reg_write(
|
||||
instr.rd(),
|
||||
core.mem.read_hword(page, offset)? as i16 as i64 as DWord,
|
||||
);
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 page = (addr / 4096) as PageNum;
|
||||
let offset = (addr & (4096 as Addr - 1)) as u16;
|
||||
let value = core.reg_read(instr.rs2()) as Byte;
|
||||
|
||||
match core.mem.write_byte(page, offset, value) {
|
||||
Ok(_) => {
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.mem.write_byte(page, offset, value)?;
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 page = (addr / 4096) as PageNum;
|
||||
let offset = (addr & (4096 as Addr - 1)) as u16;
|
||||
|
||||
match core.mem.read_byte(page, offset) {
|
||||
Ok(x) => {
|
||||
let x = x as i8 as i64 as DWord;
|
||||
core.reg_write(instr.rd(), x);
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.reg_write(
|
||||
instr.rd(),
|
||||
core.mem.read_byte(page, offset)? as i8 as i64 as DWord,
|
||||
);
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 page = (addr / 4096) as PageNum;
|
||||
let offset = (addr & (4096 as Addr - 1)) as u16;
|
||||
|
||||
match core.mem.read_byte(page, offset) {
|
||||
Ok(x) => {
|
||||
let x = x as DWord;
|
||||
core.reg_write(instr.rd(), x);
|
||||
core.advance_pc();
|
||||
InstructionResult::Normal
|
||||
}
|
||||
Err(_) => InstructionResult::Exception(()),
|
||||
}
|
||||
core.reg_write(instr.rd(), core.mem.read_byte(page, offset)? as DWord);
|
||||
core.advance_pc();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod consts;
|
||||
pub mod core;
|
||||
mod decode;
|
||||
pub mod exceptions;
|
||||
mod instructions;
|
||||
pub mod mem;
|
||||
|
||||
55
src/main.rs
55
src/main.rs
@@ -9,7 +9,8 @@ use std::{env, sync::Arc, time::Duration};
|
||||
use trve::{
|
||||
consts::{Byte, DWord, HWord, Word},
|
||||
core::Core,
|
||||
mem::{DeviceEntry, MemAccessFault, MemConfig, MemDeviceInterface, PageNum, Ram},
|
||||
exceptions::ExceptionType,
|
||||
mem::{DeviceEntry, MemConfig, MemDeviceInterface, PageNum, Ram},
|
||||
};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
@@ -63,12 +64,7 @@ mod basic_uart;
|
||||
struct DbgOut;
|
||||
|
||||
impl MemDeviceInterface for DbgOut {
|
||||
fn write_dword(
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: DWord,
|
||||
) -> Result<(), trve::mem::MemAccessFault> {
|
||||
fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), ExceptionType> {
|
||||
eprintln!(
|
||||
"Wrote DWord {value:016x} to Debug-Out page {page}, offset {offset} (byte {})",
|
||||
offset * 8
|
||||
@@ -76,12 +72,7 @@ impl MemDeviceInterface for DbgOut {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_word(
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: Word,
|
||||
) -> Result<(), trve::mem::MemAccessFault> {
|
||||
fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> {
|
||||
eprintln!(
|
||||
"Wrote Word {value:08x} to Debug-Out page {page}, offset {offset} (byte {})",
|
||||
offset * 4
|
||||
@@ -89,12 +80,7 @@ impl MemDeviceInterface for DbgOut {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_hword(
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: HWord,
|
||||
) -> Result<(), trve::mem::MemAccessFault> {
|
||||
fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), ExceptionType> {
|
||||
eprintln!(
|
||||
"Wrote HWord {value:04x} to Debug-Out page {page}, offset {offset} (byte {})",
|
||||
offset * 2
|
||||
@@ -102,45 +88,40 @@ impl MemDeviceInterface for DbgOut {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_byte(
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: Byte,
|
||||
) -> Result<(), trve::mem::MemAccessFault> {
|
||||
fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
|
||||
eprintln!("Wrote Byte {value:02x} to Debug-Out page {page}, offset {offset}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, trve::mem::MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
fn read_dword(&self, _page: PageNum, _offset: u16) -> Result<DWord, ExceptionType> {
|
||||
Err(ExceptionType::LoadAccessFault)
|
||||
}
|
||||
|
||||
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, trve::mem::MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
fn read_word(&self, _page: PageNum, _offset: u16) -> Result<Word, ExceptionType> {
|
||||
Err(ExceptionType::LoadAccessFault)
|
||||
}
|
||||
|
||||
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, trve::mem::MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
fn read_hword(&self, _page: PageNum, _offset: u16) -> Result<HWord, ExceptionType> {
|
||||
Err(ExceptionType::LoadAccessFault)
|
||||
}
|
||||
|
||||
fn read_byte(&self, _page: PageNum, _offset: u16) -> Result<Byte, trve::mem::MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
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, trve::mem::MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
) -> Result<&std::sync::atomic::AtomicU32, ExceptionType> {
|
||||
Err(ExceptionType::StoreAmoAccessFault)
|
||||
}
|
||||
|
||||
fn get_atomic_dword(
|
||||
&self,
|
||||
_page: PageNum,
|
||||
_offset: u16,
|
||||
) -> Result<&std::sync::atomic::AtomicU64, trve::mem::MemAccessFault> {
|
||||
Err(MemAccessFault)
|
||||
) -> Result<&std::sync::atomic::AtomicU64, ExceptionType> {
|
||||
Err(ExceptionType::StoreAmoAccessFault)
|
||||
}
|
||||
}
|
||||
|
||||
150
src/mem.rs
150
src/mem.rs
@@ -11,7 +11,10 @@ use std::sync::{
|
||||
|
||||
use memmap2::MmapMut;
|
||||
|
||||
use crate::consts::{Byte, DWord, HWord, Word};
|
||||
use crate::{
|
||||
consts::{Byte, DWord, HWord, Word},
|
||||
exceptions::ExceptionType,
|
||||
};
|
||||
|
||||
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) {
|
||||
self.ram.read_dword(page - self.ram_start, offset)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
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) {
|
||||
self.ram.read_word(page - self.ram_start, offset)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
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) {
|
||||
self.ram.read_hword(page - self.ram_start, offset)
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
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) {
|
||||
self.ram.read_byte(page - self.ram_start, offset)
|
||||
} 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)
|
||||
}
|
||||
@@ -87,26 +98,25 @@ impl MemConfig {
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: DWord,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
) -> 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(MemAccessFault)?;
|
||||
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<(), MemAccessFault> {
|
||||
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(MemAccessFault)?;
|
||||
let entry = self
|
||||
.find_device_by_page(page)
|
||||
.ok_or(ExceptionType::StoreAmoAccessFault)?;
|
||||
entry.interface.write_word(page - entry.base, offset, value)
|
||||
}
|
||||
}
|
||||
@@ -115,26 +125,25 @@ impl MemConfig {
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: HWord,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
) -> 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(MemAccessFault)?;
|
||||
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<(), MemAccessFault> {
|
||||
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(MemAccessFault)?;
|
||||
let entry = self
|
||||
.find_device_by_page(page)
|
||||
.ok_or(ExceptionType::StoreAmoAccessFault)?;
|
||||
entry.interface.write_byte(page - entry.base, offset, value)
|
||||
}
|
||||
}
|
||||
@@ -143,7 +152,7 @@ impl MemConfig {
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
) -> Result<&AtomicU64, MemAccessFault> {
|
||||
) -> 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);
|
||||
@@ -151,18 +160,16 @@ impl MemConfig {
|
||||
self.ram
|
||||
.buf_transmuted::<AtomicU64>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::HardwareError)
|
||||
}
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
pub fn get_atomic_word(
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
) -> Result<&AtomicU32, MemAccessFault> {
|
||||
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);
|
||||
@@ -170,10 +177,12 @@ impl MemConfig {
|
||||
self.ram
|
||||
.buf_transmuted::<AtomicU32>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::HardwareError)
|
||||
}
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
@@ -232,46 +241,46 @@ impl Ram {
|
||||
}
|
||||
|
||||
#[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);
|
||||
let index = page * (PAGE_SIZE / 8) + (offset as usize);
|
||||
Ok(unsafe {
|
||||
self.buf_transmuted::<AtomicU64>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::LoadAccessFault)
|
||||
}?
|
||||
.load(Relaxed))
|
||||
}
|
||||
#[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);
|
||||
let index = page * (PAGE_SIZE / 4) + (offset as usize);
|
||||
Ok(unsafe {
|
||||
self.buf_transmuted::<AtomicU32>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::LoadAccessFault)
|
||||
}?
|
||||
.load(Relaxed))
|
||||
}
|
||||
#[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);
|
||||
let index = page * (PAGE_SIZE / 2) + (offset as usize);
|
||||
Ok(unsafe {
|
||||
self.buf_transmuted::<AtomicU16>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::LoadAccessFault)
|
||||
}?
|
||||
.load(Relaxed))
|
||||
}
|
||||
#[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);
|
||||
let index = page * PAGE_SIZE + (offset as usize);
|
||||
Ok(self
|
||||
.buf_atomic()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)?
|
||||
.ok_or(ExceptionType::LoadAccessFault)?
|
||||
.load(Relaxed))
|
||||
}
|
||||
|
||||
@@ -281,30 +290,25 @@ impl Ram {
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: DWord,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
) -> Result<(), ExceptionType> {
|
||||
debug_assert!(((offset * 8) as usize) < PAGE_SIZE);
|
||||
let index = page * (PAGE_SIZE / 8) + (offset as usize);
|
||||
unsafe {
|
||||
self.buf_transmuted::<AtomicU64>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::StoreAmoAccessFault)
|
||||
}?
|
||||
.store(value, Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
#[inline]
|
||||
pub fn write_word(
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: Word,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
pub fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), ExceptionType> {
|
||||
debug_assert!(((offset * 4) as usize) < PAGE_SIZE);
|
||||
let index = page * (PAGE_SIZE / 4) + (offset as usize);
|
||||
unsafe {
|
||||
self.buf_transmuted::<AtomicU32>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::StoreAmoAccessFault)
|
||||
}?
|
||||
.store(value, Relaxed);
|
||||
Ok(())
|
||||
@@ -315,29 +319,24 @@ impl Ram {
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: HWord,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
) -> Result<(), ExceptionType> {
|
||||
debug_assert!(((offset * 2) as usize) < PAGE_SIZE);
|
||||
let index = page * (PAGE_SIZE / 2) + (offset as usize);
|
||||
unsafe {
|
||||
self.buf_transmuted::<AtomicU16>()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)
|
||||
.ok_or(ExceptionType::StoreAmoAccessFault)
|
||||
}?
|
||||
.store(value, Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
#[inline]
|
||||
pub fn write_byte(
|
||||
&self,
|
||||
page: PageNum,
|
||||
offset: u16,
|
||||
value: Byte,
|
||||
) -> Result<(), MemAccessFault> {
|
||||
pub fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> Result<(), ExceptionType> {
|
||||
debug_assert!((offset as usize) < PAGE_SIZE);
|
||||
let index = page * PAGE_SIZE + (offset as usize);
|
||||
self.buf_atomic()
|
||||
.get(index)
|
||||
.ok_or(MemAccessFault)?
|
||||
.ok_or(ExceptionType::StoreAmoAccessFault)?
|
||||
.store(value, Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
@@ -351,21 +350,16 @@ pub struct DeviceEntry {
|
||||
}
|
||||
|
||||
pub trait MemDeviceInterface {
|
||||
fn write_dword(&self, page: PageNum, offset: u16, value: DWord) -> Result<(), MemAccessFault>;
|
||||
fn write_word(&self, page: PageNum, offset: u16, value: Word) -> Result<(), MemAccessFault>;
|
||||
fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), MemAccessFault>;
|
||||
fn write_byte(&self, page: PageNum, offset: u16, value: Byte) -> 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<(), ExceptionType>;
|
||||
fn write_hword(&self, page: PageNum, offset: u16, value: HWord) -> Result<(), ExceptionType>;
|
||||
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_word(&self, page: PageNum, offset: u16) -> Result<Word, MemAccessFault>;
|
||||
fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, MemAccessFault>;
|
||||
fn read_byte(&self, page: PageNum, offset: u16) -> Result<Byte, MemAccessFault>;
|
||||
fn read_dword(&self, page: PageNum, offset: u16) -> Result<DWord, ExceptionType>;
|
||||
fn read_word(&self, page: PageNum, offset: u16) -> Result<Word, ExceptionType>;
|
||||
fn read_hword(&self, page: PageNum, offset: u16) -> Result<HWord, ExceptionType>;
|
||||
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_dword(&self, page: PageNum, offset: u16) -> Result<&AtomicU64, MemAccessFault>;
|
||||
fn get_atomic_word(&self, page: PageNum, offset: u16) -> Result<&AtomicU32, ExceptionType>;
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user