EXCEPTION SYSTEM (initial version - may change later)
This commit is contained in:
31
Cargo.lock
generated
31
Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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"] }
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
54
src/core.rs
54
src/core.rs
@@ -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
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;
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
55
src/main.rs
55
src/main.rs
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
150
src/mem.rs
150
src/mem.rs
@@ -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;
|
|
||||||
|
|||||||
Reference in New Issue
Block a user