From 8281b84501b36b6ff17e6bdefc66bb09477546d3 Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Fri, 13 Sep 2024 18:35:51 +0100 Subject: [PATCH] RISC-V: split instruction-cache from runnable machine state --- src/riscv/lib/src/interpreter/atomics.rs | 8 +- .../lib/src/interpreter/common_memory.rs | 6 +- src/riscv/lib/src/interpreter/rv32a.rs | 20 +- src/riscv/lib/src/interpreter/rv32c.rs | 30 +- src/riscv/lib/src/interpreter/rv32i.rs | 29 +- src/riscv/lib/src/interpreter/rv64a.rs | 10 +- src/riscv/lib/src/interpreter/rv64c.rs | 6 +- src/riscv/lib/src/interpreter/rv64d.rs | 19 +- src/riscv/lib/src/interpreter/rv64dc.rs | 29 +- src/riscv/lib/src/interpreter/rv64f.rs | 19 +- src/riscv/lib/src/interpreter/rv64i.rs | 19 +- src/riscv/lib/src/interpreter/rv64priv.rs | 15 +- src/riscv/lib/src/interpreter/rv64zifencei.rs | 4 +- src/riscv/lib/src/machine_state.rs | 449 ++++++++++-------- .../src/machine_state/address_translation.rs | 10 +- src/riscv/lib/src/pvm/common.rs | 34 +- src/riscv/lib/src/pvm/sbi.rs | 103 ++-- src/riscv/lib/src/stepper.rs | 7 +- src/riscv/lib/src/stepper/pvm.rs | 8 +- src/riscv/lib/src/stepper/test.rs | 10 +- src/riscv/lib/src/stepper/test/posix.rs | 10 +- .../src/commands/debug/debugger_app.rs | 6 +- 22 files changed, 465 insertions(+), 386 deletions(-) diff --git a/src/riscv/lib/src/interpreter/atomics.rs b/src/riscv/lib/src/interpreter/atomics.rs index a2a9c5019302..ce5e74d105b4 100644 --- a/src/riscv/lib/src/interpreter/atomics.rs +++ b/src/riscv/lib/src/interpreter/atomics.rs @@ -5,10 +5,7 @@ //! Core logic for atomic instructions use crate::{ - machine_state::{ - bus::main_memory::MainMemoryLayout, instruction_cache::InstructionCacheLayout, - registers::XRegister, MachineState, - }, + machine_state::{bus::main_memory::MainMemoryLayout, registers::XRegister, MachineCoreState}, state_backend as backend, traps::Exception, }; @@ -17,10 +14,9 @@ use std::mem; pub const SC_SUCCESS: u64 = 0; pub const SC_FAILURE: u64 = 1; -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// Loads a word or a double from the address in `rs1`, places the diff --git a/src/riscv/lib/src/interpreter/common_memory.rs b/src/riscv/lib/src/interpreter/common_memory.rs index 98d7ae063aec..defac588d9f3 100644 --- a/src/riscv/lib/src/interpreter/common_memory.rs +++ b/src/riscv/lib/src/interpreter/common_memory.rs @@ -6,18 +6,16 @@ use crate::{ machine_state::{ bus::{main_memory::MainMemoryLayout, AddressableRead, AddressableWrite, OutOfBounds}, - instruction_cache::InstructionCacheLayout, registers::XRegister, - AccessType, MachineState, + AccessType, MachineCoreState, }, state_backend as backend, traps::Exception, }; -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// Generic read function for loading `mem::size_of` bytes from `address` diff --git a/src/riscv/lib/src/interpreter/rv32a.rs b/src/riscv/lib/src/interpreter/rv32a.rs index f90c21b5452b..79eb19d576ff 100644 --- a/src/riscv/lib/src/interpreter/rv32a.rs +++ b/src/riscv/lib/src/interpreter/rv32a.rs @@ -8,19 +8,15 @@ //! Chapter 8 - Unprivileged spec use crate::{ - machine_state::{ - bus::main_memory::MainMemoryLayout, instruction_cache::InstructionCacheLayout, - registers::XRegister, MachineState, - }, + machine_state::{bus::main_memory::MainMemoryLayout, registers::XRegister, MachineCoreState}, state_backend as backend, traps::Exception, }; use std::ops::{BitAnd, BitOr, BitXor}; -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `LR.W` R-type instruction @@ -228,7 +224,7 @@ mod test { machine_state::{ bus::{devices::DEVICES_ADDRESS_SPACE_LENGTH, main_memory::tests::T1K}, registers::{a0, a1, a2}, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, }; use proptest::prelude::*; @@ -238,9 +234,8 @@ mod test { macro_rules! test_lrsc { ($name:ident, $lr: ident, $sc: ident, $align: expr, $t: ident) => { backend_test!($name, F, { - use $crate::machine_state::instruction_cache::TestInstructionCacheLayout; - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!(MachineCoreState, MachineCoreStateLayout, F, backend, T1K); let state_cell = std::cell::RefCell::new(state); proptest!(|( @@ -282,9 +277,8 @@ mod test { macro_rules! test_amo { ($instr: ident, $f: expr, $align: expr, $t: ident) => { backend_test!($instr, F, { - use $crate::machine_state::instruction_cache::TestInstructionCacheLayout; - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!(MachineCoreState, MachineCoreStateLayout, F, backend, T1K); let state_cell = std::cell::RefCell::new(state); proptest!(|( diff --git a/src/riscv/lib/src/interpreter/rv32c.rs b/src/riscv/lib/src/interpreter/rv32c.rs index 99461c365763..2fc89c6f6f34 100644 --- a/src/riscv/lib/src/interpreter/rv32c.rs +++ b/src/riscv/lib/src/interpreter/rv32c.rs @@ -11,9 +11,8 @@ use crate::{ machine_state::{ bus::{main_memory::MainMemoryLayout, Address}, hart_state::HartState, - instruction_cache::InstructionCacheLayout, registers::{sp, x0, x1, x2, XRegister, XRegisters}, - MachineState, + MachineCoreState, }, state_backend as backend, traps::Exception, @@ -210,10 +209,9 @@ where } } -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `C.LW` CL-type compressed instruction @@ -275,8 +273,7 @@ mod tests { use crate::{ backend_test, create_backend, create_state, machine_state::{ - bus::main_memory::tests::T1K, instruction_cache::TestInstructionCacheLayout, - registers::a4, MachineState, MachineStateLayout, + bus::main_memory::tests::T1K, registers::a4, MachineCoreState, MachineCoreStateLayout, }, }; use proptest::{prelude::*, prop_assert_eq, proptest}; @@ -290,9 +287,14 @@ mod tests { (u64::MAX - 1, 100, 98_i64 as u64), ]; for (init_pc, imm, res_pc) in test_case { - let mut backend = - create_backend!(MachineStateLayout, F); - let mut state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let mut state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); state.hart.pc.write(init_pc); let new_pc = state.hart.run_cj(imm); @@ -303,8 +305,14 @@ mod tests { }); backend_test!(run_caddi, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let state_cell = std::cell::RefCell::new(state); proptest!(|( diff --git a/src/riscv/lib/src/interpreter/rv32i.rs b/src/riscv/lib/src/interpreter/rv32i.rs index 71108dfe6d4c..11a4642fd5e3 100644 --- a/src/riscv/lib/src/interpreter/rv32i.rs +++ b/src/riscv/lib/src/interpreter/rv32i.rs @@ -10,10 +10,9 @@ use crate::{ machine_state::{ bus::{main_memory::MainMemoryLayout, Address}, hart_state::HartState, - instruction_cache::InstructionCacheLayout, mode::Mode, registers::{XRegister, XRegisters}, - MachineState, + MachineCoreState, }, parser::instruction::FenceSet, state_backend::{self as backend}, @@ -355,10 +354,9 @@ where } } -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerBase, { /// `FENCE` I-Type instruction @@ -382,12 +380,11 @@ mod tests { CSRRepr, CSRegister, }, hart_state::{HartState, HartStateLayout}, - instruction_cache::TestInstructionCacheLayout, mode::Mode, registers::{ a0, a1, a2, a3, a4, fa0, t0, t1, t2, t3, t4, t5, t6, XRegisters, XRegistersLayout, }, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, parser::instruction::FenceSet, traps::Exception, @@ -687,16 +684,28 @@ mod tests { }); backend_test!(test_ebreak, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let ret_val = state.hart.run_ebreak(); assert_eq!(ret_val, Exception::Breakpoint); }); backend_test!(test_fence, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let state_cell = std::cell::RefCell::new(state); proptest!(|( diff --git a/src/riscv/lib/src/interpreter/rv64a.rs b/src/riscv/lib/src/interpreter/rv64a.rs index 2ce714054e50..50a670adbcfa 100644 --- a/src/riscv/lib/src/interpreter/rv64a.rs +++ b/src/riscv/lib/src/interpreter/rv64a.rs @@ -8,19 +8,15 @@ //! Chapter 8 - Unprivileged spec use crate::{ - machine_state::{ - bus::main_memory::MainMemoryLayout, instruction_cache::InstructionCacheLayout, - registers::XRegister, MachineState, - }, + machine_state::{bus::main_memory::MainMemoryLayout, registers::XRegister, MachineCoreState}, state_backend as backend, traps::Exception, }; use std::ops::{BitAnd, BitOr, BitXor}; -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `LR.D` R-type instruction @@ -228,7 +224,7 @@ mod test { machine_state::{ bus::{devices::DEVICES_ADDRESS_SPACE_LENGTH, main_memory::tests::T1K}, registers::{a0, a1, a2}, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, test_amo, test_lrsc, }; diff --git a/src/riscv/lib/src/interpreter/rv64c.rs b/src/riscv/lib/src/interpreter/rv64c.rs index 35e2caf84827..df9cc699ff87 100644 --- a/src/riscv/lib/src/interpreter/rv64c.rs +++ b/src/riscv/lib/src/interpreter/rv64c.rs @@ -10,9 +10,8 @@ use crate::{ machine_state::{ bus::main_memory::MainMemoryLayout, - instruction_cache::InstructionCacheLayout, registers::{sp, x0, XRegister, XRegisters}, - MachineState, + MachineCoreState, }, state_backend as backend, traps::Exception, @@ -50,10 +49,9 @@ where } } -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `C.LD` CL-type compressed instruction diff --git a/src/riscv/lib/src/interpreter/rv64d.rs b/src/riscv/lib/src/interpreter/rv64d.rs index 0af850ef209c..c74058c8ea57 100644 --- a/src/riscv/lib/src/interpreter/rv64d.rs +++ b/src/riscv/lib/src/interpreter/rv64d.rs @@ -11,9 +11,8 @@ use crate::{ machine_state::{ bus::main_memory::MainMemoryLayout, hart_state::HartState, - instruction_cache::InstructionCacheLayout, registers::{FRegister, FValue, XRegister}, - MachineState, + MachineCoreState, }, parser::instruction::InstrRoundingMode, state_backend as backend, @@ -515,10 +514,9 @@ where } } -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `FLD` I-type instruction. @@ -559,9 +557,8 @@ mod tests { CSRegister, }, hart_state::{HartState, HartStateLayout}, - instruction_cache::TestInstructionCacheLayout, registers::{fa2, fa3, parse_fregister, parse_xregister, t0}, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, traps::Exception, }; @@ -598,8 +595,14 @@ mod tests { }); backend_test!(test_load_store, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let state_cell = std::cell::RefCell::new(state); proptest!(|( diff --git a/src/riscv/lib/src/interpreter/rv64dc.rs b/src/riscv/lib/src/interpreter/rv64dc.rs index 569f4711a3f4..7ba7a2d83f38 100644 --- a/src/riscv/lib/src/interpreter/rv64dc.rs +++ b/src/riscv/lib/src/interpreter/rv64dc.rs @@ -10,18 +10,16 @@ use crate::{ machine_state::{ bus::main_memory::MainMemoryLayout, - instruction_cache::InstructionCacheLayout, registers::{sp, FRegister, XRegister}, - MachineState, + MachineCoreState, }, state_backend as backend, traps::Exception, }; -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `C.FLD` CL-type compressed instruction @@ -85,9 +83,8 @@ mod test { xstatus::{ExtensionValue, MStatus}, CSRegister, }, - instruction_cache::TestInstructionCacheLayout, registers::{fa2, fa3, parse_xregister, sp}, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, traps::Exception, }; @@ -98,8 +95,14 @@ mod test { const OUT_OF_BOUNDS_OFFSET: i64 = 1024; backend_test!(test_cfsd_cfld, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let state_cell = std::cell::RefCell::new(state); proptest!(|( @@ -138,8 +141,14 @@ mod test { }); backend_test!(test_cfsdsp_cfldsp, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let state_cell = std::cell::RefCell::new(state); proptest!(|( diff --git a/src/riscv/lib/src/interpreter/rv64f.rs b/src/riscv/lib/src/interpreter/rv64f.rs index 5a0e747d6f6d..ac55d22301a4 100644 --- a/src/riscv/lib/src/interpreter/rv64f.rs +++ b/src/riscv/lib/src/interpreter/rv64f.rs @@ -11,9 +11,8 @@ use crate::{ machine_state::{ bus::main_memory::MainMemoryLayout, hart_state::HartState, - instruction_cache::InstructionCacheLayout, registers::{FRegister, FValue, XRegister}, - MachineState, + MachineCoreState, }, parser::instruction::InstrRoundingMode, state_backend as backend, @@ -501,10 +500,9 @@ where } } -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `FLW` I-type instruction. @@ -565,9 +563,8 @@ mod tests { CSRegister, }, hart_state::{HartState, HartStateLayout}, - instruction_cache::TestInstructionCacheLayout, registers::{fa1, fa4, parse_fregister, parse_xregister, t0}, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, traps::Exception, }; @@ -616,8 +613,14 @@ mod tests { }); backend_test!(test_load_store, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let state_cell = std::cell::RefCell::new(state); proptest!(|( diff --git a/src/riscv/lib/src/interpreter/rv64i.rs b/src/riscv/lib/src/interpreter/rv64i.rs index 95f30d1d47f4..0beb2c1e8f85 100644 --- a/src/riscv/lib/src/interpreter/rv64i.rs +++ b/src/riscv/lib/src/interpreter/rv64i.rs @@ -9,9 +9,8 @@ use crate::{ machine_state::{ bus::main_memory::MainMemoryLayout, - instruction_cache::InstructionCacheLayout, registers::{XRegister, XRegisters}, - MachineState, + MachineCoreState, }, state_backend as backend, traps::Exception, @@ -232,10 +231,9 @@ where } } -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `LD` I-type instruction @@ -357,9 +355,8 @@ mod tests { machine_state::{ bus::{devices::DEVICES_ADDRESS_SPACE_LENGTH, main_memory::tests::T1K}, hart_state::{HartState, HartStateLayout}, - instruction_cache::TestInstructionCacheLayout, registers::{a0, a1, a2, a3, a4, t0, t1, t2, t3, t4}, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, traps::Exception, }; @@ -758,8 +755,14 @@ mod tests { }); backend_test!(test_load_store, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineCoreStateLayout, F); + let state = create_state!( + MachineCoreState, + MachineCoreStateLayout, + F, + backend, + T1K + ); let state_cell = std::cell::RefCell::new(state); proptest!(|( diff --git a/src/riscv/lib/src/interpreter/rv64priv.rs b/src/riscv/lib/src/interpreter/rv64priv.rs index ef64f2b02b8d..d4af32035ae3 100644 --- a/src/riscv/lib/src/interpreter/rv64priv.rs +++ b/src/riscv/lib/src/interpreter/rv64priv.rs @@ -11,10 +11,9 @@ use crate::{ CSRegister, }, hart_state::HartState, - instruction_cache::InstructionCacheLayout, mode::Mode, registers::XRegister, - AccessType, MachineState, + AccessType, MachineCoreState, }, state_backend::{self as backend}, traps::Exception, @@ -102,10 +101,9 @@ where } } -impl MachineState +impl MachineCoreState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, M: backend::ManagerReadWrite, { /// `WFI` instruction @@ -143,20 +141,19 @@ mod tests { machine_state::{ bus::main_memory::tests::T1K, csregisters::{xstatus, CSRRepr, CSRegister}, - instruction_cache::TestInstructionCacheLayout, mode::Mode, registers::{a0, t0}, - MachineState, MachineStateLayout, + MachineCoreState, MachineCoreStateLayout, }, traps::Exception, }; backend_test!(test_sfence, F, { - type L = MachineStateLayout; + type L = MachineCoreStateLayout; let mut backend = create_backend!(L, F); - let mut state = create_state!(MachineState, L, F, backend, T1K, TestInstructionCacheLayout); + let mut state = create_state!(MachineCoreState, L, F, backend, T1K); - let run_test = |state: &mut MachineState<_, _, _>, + let run_test = |state: &mut MachineCoreState<_, _>, mode: Mode, bit: bool, result: Result<(), Exception>| { diff --git a/src/riscv/lib/src/interpreter/rv64zifencei.rs b/src/riscv/lib/src/interpreter/rv64zifencei.rs index 418ce0e0f2a0..02b57c3fd061 100644 --- a/src/riscv/lib/src/interpreter/rv64zifencei.rs +++ b/src/riscv/lib/src/interpreter/rv64zifencei.rs @@ -21,7 +21,9 @@ where /// Execute a `fence.i` instruction. #[inline(always)] pub fn run_fencei(&mut self) { - self.translation_cache.invalidate([AccessType::Instruction]); + self.core + .translation_cache + .invalidate([AccessType::Instruction]); self.instruction_cache.invalidate(); } } diff --git a/src/riscv/lib/src/machine_state.rs b/src/riscv/lib/src/machine_state.rs index 02fbf14ace6d..24ba48b4666d 100644 --- a/src/riscv/lib/src/machine_state.rs +++ b/src/riscv/lib/src/machine_state.rs @@ -44,23 +44,33 @@ use csregisters::{values::CSRValue, CSRRepr}; use mode::Mode; use std::ops::Bound; -/// Layout for the machine state -pub type MachineStateLayout = ( - HartStateLayout, - bus::BusLayout, - TranslationCacheLayout, - ICL, -); - -/// Machine state +/// Layout for the machine 'run state' - which contains everything required for the running of +/// instructions. +pub type MachineCoreStateLayout = (HartStateLayout, bus::BusLayout, TranslationCacheLayout); + +/// The part of the machine state required to run (almost all) instructions. +/// +/// Namely, things that are required to fetch instructions, but not run them, should be placed +/// elsewhere in [`MachineState`]. +/// +/// Certain instructions (e.g. `FENCE.I` may invalidate other parts of the state, but this are +/// small in number). +pub struct MachineCoreState { + pub hart: HartState, + pub bus: Bus, + pub translation_cache: TranslationCache, +} + +/// Layout for the machine state - everything required to fetch & run instructions. +pub type MachineStateLayout = (MachineCoreStateLayout, ICL); + +/// The machine state contains everything required to fetch & run instructions. pub struct MachineState< ML: main_memory::MainMemoryLayout, ICL: InstructionCacheLayout, M: backend::ManagerBase, > { - pub hart: HartState, - pub bus: Bus, - pub translation_cache: TranslationCache, + pub core: MachineCoreState, pub instruction_cache: InstructionCache, } @@ -255,28 +265,24 @@ macro_rules! run_cb_type_instr { }}; } -impl - MachineState -{ +impl MachineCoreState { /// Bind the machine state to the given allocated space. - pub fn bind(space: backend::AllocatedOf, M>) -> Self { + pub fn bind(space: backend::AllocatedOf, M>) -> Self { Self { hart: HartState::bind(space.0), bus: Bus::bind(space.1), translation_cache: TranslationCache::bind(space.2), - instruction_cache: InstructionCache::bind(space.3), } } /// Obtain a structure with references to the bound regions of this type. pub fn struct_ref( &self, - ) -> backend::AllocatedOf, backend::Ref<'_, M>> { + ) -> backend::AllocatedOf, backend::Ref<'_, M>> { ( self.hart.struct_ref(), self.bus.struct_ref(), self.translation_cache.struct_ref(), - self.instruction_cache.struct_ref(), ) } @@ -288,104 +294,6 @@ impl()); self.bus.reset(); self.translation_cache.reset(); - self.instruction_cache.reset(); - } - - /// Translate an instruction address. - #[inline] - fn translate_instr_address( - &mut self, - mode: Mode, - satp: CSRRepr, - virt_addr: Address, - ) -> Result - where - M: backend::ManagerReadWrite, - { - // Chapter: P:S-ISA-1.9 & P:M-ISA-1.16 - // If mtval is written with a nonzero value when a - // breakpoint, address-misaligned, access-fault, or page-fault exception - // occurs on an instruction fetch, load, or store, then mtval will contain the - // faulting virtual address. - - let phys_addr = if let Some(phys_addr) = - self.translation_cache - .try_translate(mode, satp, AccessType::Instruction, virt_addr) - { - phys_addr - } else { - let phys_addr = - self.translate_with_prefetch(mode, satp, virt_addr, AccessType::Instruction)?; - - self.translation_cache.cache_translation( - mode, - satp, - AccessType::Instruction, - virt_addr, - phys_addr, - ); - - phys_addr - }; - - Ok(phys_addr) - } - - /// Fetch the 16 bits of an instruction at the given physical address. - #[inline(always)] - fn fetch_instr_halfword(&self, phys_addr: Address) -> Result - where - M: backend::ManagerRead, - { - self.bus - .read(phys_addr) - .map_err(|_: OutOfBounds| Exception::InstructionAccessFault(phys_addr)) - } - - /// Fetch instruction from the address given by program counter - /// The spec stipulates translation is performed for each byte respectively. - /// However, we assume the `raw_pc` is 2-byte aligned. - #[inline] - fn fetch_instr( - &mut self, - mode: Mode, - satp: CSRRepr, - virt_addr: Address, - phys_addr: Address, - ) -> Result - where - M: backend::ManagerReadWrite, - { - let first_halfword = self.fetch_instr_halfword(phys_addr)?; - - // The reasons to provide the second half in the lambda is - // because those bytes may be inaccessible or may trigger an exception when read. - // Hence we can't read all 4 bytes eagerly. - let instr = if is_compressed(first_halfword) { - self.instruction_cache - .cache_compressed(phys_addr, first_halfword) - } else { - let upper = { - let next_addr = phys_addr + 2; - - // Optimization to skip an extra address translation lookup: - // If the last 2 bytes of the instruction are in the same page - // as the first 2 bytes, then we already know the translated address - let phys_addr = if next_addr % PAGE_SIZE == 0 { - self.translate_instr_address(mode, satp, virt_addr + 2)? - } else { - next_addr - }; - - self.fetch_instr_halfword(phys_addr)? - }; - - let combined = (upper as u32) << 16 | (first_halfword as u32); - self.instruction_cache - .cache_uncompressed(phys_addr, combined) - }; - - Ok(instr) } /// Advance [`MachineState`] by executing an [`InstrCacheable`]. @@ -663,6 +571,138 @@ impl Err(Exception::IllegalInstruction), } } +} + +impl + MachineState +{ + /// Bind the machine state to the given allocated space. + pub fn bind(space: backend::AllocatedOf, M>) -> Self { + Self { + core: MachineCoreState::bind(space.0), + instruction_cache: InstructionCache::bind(space.1), + } + } + + /// Obtain a structure with references to the bound regions of this type. + pub fn struct_ref( + &self, + ) -> backend::AllocatedOf, backend::Ref<'_, M>> { + (self.core.struct_ref(), self.instruction_cache.struct_ref()) + } + + /// Reset the machine state. + pub fn reset(&mut self) + where + M: backend::ManagerWrite, + { + self.core.reset(); + self.instruction_cache.reset(); + } + + /// Translate an instruction address. + #[inline] + fn translate_instr_address( + &mut self, + mode: Mode, + satp: CSRRepr, + virt_addr: Address, + ) -> Result + where + M: backend::ManagerReadWrite, + { + // Chapter: P:S-ISA-1.9 & P:M-ISA-1.16 + // If mtval is written with a nonzero value when a + // breakpoint, address-misaligned, access-fault, or page-fault exception + // occurs on an instruction fetch, load, or store, then mtval will contain the + // faulting virtual address. + + let phys_addr = if let Some(phys_addr) = self.core.translation_cache.try_translate( + mode, + satp, + AccessType::Instruction, + virt_addr, + ) { + phys_addr + } else { + let phys_addr = self.core.translate_with_prefetch( + mode, + satp, + virt_addr, + AccessType::Instruction, + )?; + + self.core.translation_cache.cache_translation( + mode, + satp, + AccessType::Instruction, + virt_addr, + phys_addr, + ); + + phys_addr + }; + + Ok(phys_addr) + } + + /// Fetch the 16 bits of an instruction at the given physical address. + #[inline(always)] + fn fetch_instr_halfword(&self, phys_addr: Address) -> Result + where + M: backend::ManagerRead, + { + self.core + .bus + .read(phys_addr) + .map_err(|_: OutOfBounds| Exception::InstructionAccessFault(phys_addr)) + } + + /// Fetch instruction from the address given by program counter + /// The spec stipulates translation is performed for each byte respectively. + /// However, we assume the `raw_pc` is 2-byte aligned. + #[inline] + fn fetch_instr( + &mut self, + mode: Mode, + satp: CSRRepr, + virt_addr: Address, + phys_addr: Address, + ) -> Result + where + M: backend::ManagerReadWrite, + { + let first_halfword = self.fetch_instr_halfword(phys_addr)?; + + // The reasons to provide the second half in the lambda is + // because those bytes may be inaccessible or may trigger an exception when read. + // Hence we can't read all 4 bytes eagerly. + let instr = if is_compressed(first_halfword) { + self.instruction_cache + .cache_compressed(phys_addr, first_halfword) + } else { + let upper = { + let next_addr = phys_addr + 2; + + // Optimization to skip an extra address translation lookup: + // If the last 2 bytes of the instruction are in the same page + // as the first 2 bytes, then we already know the translated address + let phys_addr = if next_addr % PAGE_SIZE == 0 { + self.translate_instr_address(mode, satp, virt_addr + 2)? + } else { + next_addr + }; + + self.fetch_instr_halfword(phys_addr)? + }; + + let combined = (upper as u32) << 16 | (first_halfword as u32); + self.instruction_cache + .cache_uncompressed(phys_addr, combined) + }; + + Ok(instr) + } /// Advance [`MachineState`] by executing an [`InstrUncacheable`]. fn run_instr_uncacheable( @@ -686,7 +726,7 @@ impl self.run_instr_cacheable(i), + Instr::Cacheable(i) => self.core.run_instr_cacheable(i), Instr::Uncacheable(i) => self.run_instr_uncacheable(i), } } @@ -703,7 +743,7 @@ impl self.run_instr_cacheable(instr), + Some(instr) => self.core.run_instr_cacheable(instr), None => self .fetch_instr(current_mode, satp, instr_pc, phys_addr) .and_then(|instr| self.run_instr(&instr)), @@ -719,18 +759,18 @@ impl self.hart.pc.write(address), - ProgramCounterUpdate::Add(width) => self.hart.pc.write(instr_pc + width), + ProgramCounterUpdate::Set(address) => self.core.hart.pc.write(address), + ProgramCounterUpdate::Add(width) => self.core.hart.pc.write(instr_pc + width), }; Ok(()) @@ -803,16 +843,16 @@ impl self.hart.pc.read(), + let instr_pc = match self.core.hart.get_pending_interrupt(current_mode) { + None => self.core.hart.pc.read(), Some(interrupt) => self.address_on_interrupt(interrupt)?, }; - let satp: CSRRepr = self.hart.csregisters.read(CSRegister::satp); + let satp: CSRRepr = self.core.hart.csregisters.read(CSRegister::satp); let instr_result = self .translate_instr_address(current_mode, satp, instr_pc) .and_then(|phys_addr| self.run_instr_at(current_mode, satp, instr_pc, phys_addr)); @@ -907,14 +947,14 @@ impl(initrd)?; - self.bus.write_all(dtb_addr, fdt.as_slice())?; + self.core.bus.write_all(dtb_addr, fdt.as_slice())?; // Point DTB boot argument (a1) at the written device tree - self.hart.xregisters.write(registers::a1, dtb_addr); + self.core.hart.xregisters.write(registers::a1, dtb_addr); // Start in supervisor mode - self.hart.mode.write(mode); + self.core.hart.mode.write(mode); // Make sure to forward all exceptions and interrupts to supervisor mode - self.hart + self.core + .hart .csregisters .write(csregisters::CSRegister::medeleg, CSRValue::from(!0u64)); - self.hart + self.core + .hart .csregisters .write(csregisters::CSRegister::mideleg, CSRValue::from(!0u64)); @@ -1026,13 +1068,13 @@ mod tests { // Instruction which performs a unit op (AUIPC with t0) const T2_ENC: u64 = 0b0_0111; // x7 - state.hart.pc.write(init_pc_addr); - state.hart.xregisters.write(a1, T2_ENC << 7 | 0b0010111); - state.hart.xregisters.write(a2, init_pc_addr); - state.run_sw(0, a2, a1).expect("Storing instruction should succeed"); + state.core.hart.pc.write(init_pc_addr); + state.core.hart.xregisters.write(a1, T2_ENC << 7 | 0b0010111); + state.core.hart.xregisters.write(a2, init_pc_addr); + state.core.run_sw(0, a2, a1).expect("Storing instruction should succeed"); state.step().expect("should not raise trap to EE"); - prop_assert_eq!(state.hart.xregisters.read(t2), init_pc_addr); - prop_assert_eq!(state.hart.pc.read(), init_pc_addr + 4); + prop_assert_eq!(state.core.hart.xregisters.read(t2), init_pc_addr); + prop_assert_eq!(state.core.hart.pc.read(), init_pc_addr + 4); // Instruction which updates pc by returning an address // t3 = jump_addr, (JALR imm=0, rs1=t3, rd=t0) @@ -1040,19 +1082,19 @@ mod tests { const OP_JALR: u64 = 0b110_0111; const F3_0: u64 = 0b000; - state.hart.pc.write(init_pc_addr); - state.hart.xregisters.write(a1, T2_ENC << 15 | F3_0 << 12 | T0_ENC << 7 | OP_JALR); - state.hart.xregisters.write(a2, init_pc_addr); - state.run_sw(0, a2, a1).expect("Storing instruction should succeed"); - state.hart.xregisters.write(t2, jump_addr); + state.core.hart.pc.write(init_pc_addr); + state.core.hart.xregisters.write(a1, T2_ENC << 15 | F3_0 << 12 | T0_ENC << 7 | OP_JALR); + state.core.hart.xregisters.write(a2, init_pc_addr); + state.core.run_sw(0, a2, a1).expect("Storing instruction should succeed"); + state.core.hart.xregisters.write(t2, jump_addr); // Since we've written a new instruction to the init_pc_addr - we need to // invalidate the instruction cache. state.run_fencei(); state.step().expect("should not raise trap to EE"); - prop_assert_eq!(state.hart.xregisters.read(t0), init_pc_addr + 4); - prop_assert_eq!(state.hart.pc.read(), jump_addr); + prop_assert_eq!(state.core.hart.xregisters.read(t0), init_pc_addr + 4); + prop_assert_eq!(state.core.hart.pc.read(), jump_addr); }); }); @@ -1076,20 +1118,20 @@ mod tests { const ECALL: u64 = 0b111_0011; // stvec is in DIRECT mode - state.hart.csregisters.write(CSRegister::stvec, stvec_addr); + state.core.hart.csregisters.write(CSRegister::stvec, stvec_addr); // mtvec is in VECTORED mode - state.hart.csregisters.write(CSRegister::mtvec, mtvec_addr | 1); + state.core.hart.csregisters.write(CSRegister::mtvec, mtvec_addr | 1); // TEST: Raise ECALL exception ==>> environment exception - state.hart.mode.write(Mode::Machine); - state.hart.pc.write(init_pc_addr); - state.hart.xregisters.write(a1, ECALL); - state.hart.xregisters.write(a2, init_pc_addr); - state.run_sw(0, a2, a1).expect("Storing instruction should succeed"); + state.core.hart.mode.write(Mode::Machine); + state.core.hart.pc.write(init_pc_addr); + state.core.hart.xregisters.write(a1, ECALL); + state.core.hart.xregisters.write(a2, init_pc_addr); + state.core.run_sw(0, a2, a1).expect("Storing instruction should succeed"); let e = state.step() .expect_err("should raise Environment Exception"); assert_eq!(e, EnvironException::EnvCallFromMMode); - prop_assert_eq!(state.hart.pc.read(), init_pc_addr); + prop_assert_eq!(state.core.hart.pc.read(), init_pc_addr); }); }); @@ -1110,7 +1152,7 @@ mod tests { const EBREAK: u64 = 1 << 20 | 0b111_0011; // mtvec is in VECTORED mode - state.hart.csregisters.write(CSRegister::mtvec, mtvec_addr | 1); + state.core.hart.csregisters.write(CSRegister::mtvec, mtvec_addr | 1); // TEST: Raise exception, (and no interrupt before) take trap from M-mode to M-mode // (test no delegation takes place, even if delegation is on, traps never lower privilege) @@ -1118,22 +1160,22 @@ mod tests { 1 << Exception::EnvCallFromSMode.exception_code() | 1 << Exception::EnvCallFromMMode.exception_code() | 1 << Exception::Breakpoint.exception_code(); - state.hart.mode.write(Mode::Machine); - state.hart.pc.write(init_pc_addr); - state.hart.csregisters.write(CSRegister::medeleg, medeleg_val); + state.core.hart.mode.write(Mode::Machine); + state.core.hart.pc.write(init_pc_addr); + state.core.hart.csregisters.write(CSRegister::medeleg, medeleg_val); - state.hart.xregisters.write(a1, EBREAK); - state.hart.xregisters.write(a2, init_pc_addr); - state.run_sw(0, a2, a1).expect("Storing instruction should succeed"); + state.core.hart.xregisters.write(a1, EBREAK); + state.core.hart.xregisters.write(a2, init_pc_addr); + state.core.run_sw(0, a2, a1).expect("Storing instruction should succeed"); state.step().expect("should not raise environment exception"); // pc should be mtvec_addr since exceptions aren't offset (by VECTORED mode) // even in VECTORED mode, only interrupts - let mstatus: MStatus = state.hart.csregisters.read(CSRegister::mstatus); - assert_eq!(state.hart.mode.read(), Mode::Machine); - assert_eq!(state.hart.pc.read(), mtvec_addr); + let mstatus: MStatus = state.core.hart.csregisters.read(CSRegister::mstatus); + assert_eq!(state.core.hart.mode.read(), Mode::Machine); + assert_eq!(state.core.hart.pc.read(), mtvec_addr); assert_eq!(mstatus.mpp(), xstatus::MPPValue::Machine); - assert_eq!(state.hart.csregisters.read::(CSRegister::mepc), init_pc_addr); - assert_eq!(state.hart.csregisters.read::(CSRegister::mcause), 3); + assert_eq!(state.core.hart.csregisters.read::(CSRegister::mepc), init_pc_addr); + assert_eq!(state.core.hart.csregisters.read::(CSRegister::mcause), 3); }); }); @@ -1154,26 +1196,26 @@ mod tests { let stvec_addr = init_pc_addr + 4 * stvec_offset; // stvec is in VECTORED mode - state.hart.csregisters.write(CSRegister::stvec, stvec_addr | 1); + state.core.hart.csregisters.write(CSRegister::stvec, stvec_addr | 1); let bad_address = bus::start_of_main_memory::() - (pc_addr_offset + 10) * 4; let medeleg_val = 1 << Exception::IllegalInstruction.exception_code() | 1 << Exception::EnvCallFromSMode.exception_code() | 1 << Exception::EnvCallFromMMode.exception_code() | 1 << Exception::InstructionAccessFault(bad_address).exception_code(); - state.hart.mode.write(Mode::User); - state.hart.pc.write(bad_address); - state.hart.csregisters.write(CSRegister::medeleg, medeleg_val); + state.core.hart.mode.write(Mode::User); + state.core.hart.pc.write(bad_address); + state.core.hart.csregisters.write(CSRegister::medeleg, medeleg_val); state.step().expect("should not raise environment exception"); // pc should be stvec_addr since exceptions aren't offsetted // even in VECTORED mode, only interrupts - let mstatus: MStatus = state.hart.csregisters.read(CSRegister::mstatus); - assert_eq!(state.hart.mode.read(), Mode::Supervisor); - assert_eq!(state.hart.pc.read(), stvec_addr); + let mstatus: MStatus = state.core.hart.csregisters.read(CSRegister::mstatus); + assert_eq!(state.core.hart.mode.read(), Mode::Supervisor); + assert_eq!(state.core.hart.pc.read(), stvec_addr); assert_eq!(mstatus.spp(), xstatus::SPPValue::User); - assert_eq!(state.hart.csregisters.read::(CSRegister::sepc), bad_address); - assert_eq!(state.hart.csregisters.read::(CSRegister::scause), 1); + assert_eq!(state.core.hart.csregisters.read::(CSRegister::sepc), bad_address); + assert_eq!(state.core.hart.csregisters.read::(CSRegister::scause), 1); }); }); @@ -1237,20 +1279,24 @@ mod tests { // Write the instructions to the beginning of the main memory and point the program // counter at the first instruction. - state.hart.pc.write(start_ram); + state.core.hart.pc.write(start_ram); let instrs: [u8; 8] = [I_WRITE_T1_TO_ADDRESS_T0, I_LOAD_5_INTO_T2] .into_iter() .flat_map(u32::to_le_bytes) .collect::>() .try_into() .unwrap(); - state.bus.write_all(start_ram, &instrs).unwrap(); + state.core.bus.write_all(start_ram, &instrs).unwrap(); // Configure the machine in such a way that the first instruction will override the // second instruction. The second instruction behaves differently. let address_to_write = start_ram + 4; - state.hart.xregisters.write(t0, address_to_write); - state.hart.xregisters.write(t1, I_LOAD_6_INTO_T2 as u64); + state.core.hart.xregisters.write(t0, address_to_write); + state + .core + .hart + .xregisters + .write(t1, I_LOAD_6_INTO_T2 as u64); } let mut alt_backend = backend.clone(); @@ -1260,7 +1306,7 @@ mod tests { let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1K, TestInstructionCacheLayout); state.step().unwrap(); state.step().unwrap(); - state.hart.xregisters.read(t2) + state.core.hart.xregisters.read(t2) }; // Perform 2 steps separately in another backend by re-binding the state between steps. @@ -1273,7 +1319,7 @@ mod tests { { let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1K, TestInstructionCacheLayout); state.step().unwrap(); - state.hart.xregisters.read(t2) + state.core.hart.xregisters.read(t2) } }; @@ -1448,29 +1494,34 @@ mod tests { state.reset(); state + .core .bus .write_all(root_page_table_addr, &init_page_table) .unwrap(); - state.bus.write_all(code0_addr, &instrs0).unwrap(); - state.bus.write_all(code1_addr, &instrs1).unwrap(); + state.core.bus.write_all(code0_addr, &instrs0).unwrap(); + state.core.bus.write_all(code1_addr, &instrs1).unwrap(); - state.hart.pc.write(code_virt_addr); + state.core.hart.pc.write(code_virt_addr); - state.hart.mode.write(Mode::User); - state.hart.csregisters.write(CSRegister::satp, satp); + state.core.hart.mode.write(Mode::User); + state.core.hart.csregisters.write(CSRegister::satp, satp); - state.hart.xregisters.write(t0, new_pte.to_bits()); - state.hart.xregisters.write(t1, root_page_table_virt_addr); + state.core.hart.xregisters.write(t0, new_pte.to_bits()); + state + .core + .hart + .xregisters + .write(t1, root_page_table_virt_addr); } let mut alt_backend = backend.clone(); - // Run 2 steps consecutively against one backend. + // 2 steps consecutively against one backend. let result = { let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1M, TestInstructionCacheLayout); state.step().unwrap(); state.step().unwrap(); - state.hart.xregisters.read(a0) + state.core.hart.xregisters.read(a0) }; // Perform 2 steps separately in another backend by re-binding the state between steps. @@ -1482,7 +1533,7 @@ mod tests { { let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1M, TestInstructionCacheLayout); state.step().unwrap(); - state.hart.xregisters.read(a0) + state.core.hart.xregisters.read(a0) } }; diff --git a/src/riscv/lib/src/machine_state/address_translation.rs b/src/riscv/lib/src/machine_state/address_translation.rs index e992589202a3..b724daca070d 100644 --- a/src/riscv/lib/src/machine_state/address_translation.rs +++ b/src/riscv/lib/src/machine_state/address_translation.rs @@ -8,9 +8,8 @@ use super::{ satp::{Satp, SvLength, TranslationAlgorithm}, CSRRepr, CSRegister, }, - instruction_cache, mode::Mode, - MachineState, + MachineCoreState, }; use crate::{ bits::Bits64, @@ -190,12 +189,7 @@ where p_addr.ok_or(access_type.exception(v_addr)) } -impl< - ML: main_memory::MainMemoryLayout, - ICL: instruction_cache::InstructionCacheLayout, - M: backend::ManagerBase, - > MachineState -{ +impl MachineCoreState { /// Get the effective hart mode when addressing memory. /// Section P:M-ISA-1.6.3 /// The MPRV (Modify PRiVilege) bit modifies the effective privilege mode, i.e., diff --git a/src/riscv/lib/src/pvm/common.rs b/src/riscv/lib/src/pvm/common.rs index cf5bede62a9b..f42dc7874d0f 100644 --- a/src/riscv/lib/src/pvm/common.rs +++ b/src/riscv/lib/src/pvm/common.rs @@ -285,18 +285,29 @@ mod tests { const BUFFER_LEN: usize = 1024; // Configure machine for 'sbi_tezos_inbox_next' - pvm.machine_state.hart.xregisters.write(a0, buffer_addr); pvm.machine_state + .core + .hart + .xregisters + .write(a0, buffer_addr); + pvm.machine_state + .core .hart .xregisters .write(a1, BUFFER_LEN as u64); - pvm.machine_state.hart.xregisters.write(a2, level_addr); - pvm.machine_state.hart.xregisters.write(a3, counter_addr); + pvm.machine_state.core.hart.xregisters.write(a2, level_addr); + pvm.machine_state + .core + .hart + .xregisters + .write(a3, counter_addr); pvm.machine_state + .core .hart .xregisters .write(a7, SBI_FIRMWARE_TEZOS); pvm.machine_state + .core .hart .xregisters .write(a6, SBI_TEZOS_INBOX_NEXT); @@ -324,16 +335,16 @@ mod tests { // Returned data is as expected assert_eq!( - pvm.machine_state.hart.xregisters.read(a0) as usize, + pvm.machine_state.core.hart.xregisters.read(a0) as usize, BUFFER_LEN ); - assert_eq!(pvm.machine_state.bus.read(level_addr), Ok(level)); - assert_eq!(pvm.machine_state.bus.read(counter_addr), Ok(counter)); + assert_eq!(pvm.machine_state.core.bus.read(level_addr), Ok(level)); + assert_eq!(pvm.machine_state.core.bus.read(counter_addr), Ok(counter)); // Payload in memory should be as expected for (offset, &byte) in payload[..BUFFER_LEN].iter().enumerate() { let addr = buffer_addr + offset as u64; - let byte_written: u8 = pvm.machine_state.bus.read(addr).unwrap(); + let byte_written: u8 = pvm.machine_state.core.bus.read(addr).unwrap(); assert_eq!( byte, byte_written, "Byte at {addr:x} (offset {offset}) is not the same" @@ -344,7 +355,7 @@ mod tests { assert!((BUFFER_LEN..4096) .map(|offset| { let addr = buffer_addr + offset as u64; - pvm.machine_state.bus.read(addr).unwrap() + pvm.machine_state.core.bus.read(addr).unwrap() }) .all(|b: u8| b == 0)); } @@ -365,6 +376,7 @@ mod tests { // Prepare subsequent ECALLs to use the SBI_CONSOLE_PUTCHAR extension pvm.machine_state + .core .hart .xregisters .write(a7, SBI_CONSOLE_PUTCHAR); @@ -373,7 +385,11 @@ mod tests { let mut written = Vec::new(); for _ in 0..10 { let char: u8 = rand::random(); - pvm.machine_state.hart.xregisters.write(a0, char as u64); + pvm.machine_state + .core + .hart + .xregisters + .write(a0, char as u64); written.push(char); let outcome = pvm.handle_exception(&mut hooks, EnvironException::EnvCallFromUMode); diff --git a/src/riscv/lib/src/pvm/sbi.rs b/src/riscv/lib/src/pvm/sbi.rs index 48d6e183b2d8..a0dc6a5b8618 100644 --- a/src/riscv/lib/src/pvm/sbi.rs +++ b/src/riscv/lib/src/pvm/sbi.rs @@ -31,7 +31,7 @@ fn sbi_return_error, code: SbiError, ) { - machine.hart.xregisters.write(a0, code as i64 as u64); + machine.core.hart.xregisters.write(a0, code as i64 as u64); } /// Write an arbitrary value as single return value. @@ -46,7 +46,7 @@ fn sbi_return1( ICL: InstructionCacheLayout, M: ManagerReadWrite, { - let char = machine.hart.xregisters.read(a0) as u8; + let char = machine.core.hart.xregisters.read(a0) as u8; (hooks.putchar_hook)(char); // This call always succeeds. @@ -359,7 +364,7 @@ fn handle_debug_console_write_byte( ICL: InstructionCacheLayout, M: ManagerReadWrite, { - let char = machine.hart.xregisters.read(a0) as u8; + let char = machine.core.hart.xregisters.read(a0) as u8; (hooks.putchar_hook)(char); // This call always succeeds. @@ -412,30 +417,30 @@ where // No matter the outcome, we need to bump the // program counter because ECALL's don't update it // to the following instructions. - let pc = machine.hart.pc.read() + InstrCacheable::Ecall.width(); - machine.hart.pc.write(pc); + let pc = machine.core.hart.pc.read() + InstrCacheable::Ecall.width(); + machine.core.hart.pc.write(pc); // SBI extension is contained in a7. - let sbi_extension = machine.hart.xregisters.read(a7); + let sbi_extension = machine.core.hart.xregisters.read(a7); match sbi_extension { SBI_CONSOLE_PUTCHAR => handle_legacy_console_putchar(machine, hooks), SBI_SHUTDOWN => handle_legacy_shutdown(machine), SBI_DBCN => { - let sbi_function = machine.hart.xregisters.read(a6); + let sbi_function = machine.core.hart.xregisters.read(a6); match sbi_function { SBI_DBCN_CONSOLE_WRITE_BYTE => handle_debug_console_write_byte(machine, hooks), _ => handle_not_supported(machine), } } SBI_SRST => { - let sbi_function = machine.hart.xregisters.read(a6); + let sbi_function = machine.core.hart.xregisters.read(a6); match sbi_function { SBI_SRST_SYSTEM_RESET => handle_system_reset(machine), _ => handle_not_supported(machine), } } SBI_FIRMWARE_TEZOS => { - let sbi_function = machine.hart.xregisters.read(a6); + let sbi_function = machine.core.hart.xregisters.read(a6); match sbi_function { SBI_TEZOS_INBOX_NEXT => handle_tezos_inbox_next(status), SBI_TEZOS_METADATA_REVEAL => handle_tezos_metadata_reveal(status), diff --git a/src/riscv/lib/src/stepper.rs b/src/riscv/lib/src/stepper.rs index 0622ca1ae94a..e8ca676a750d 100644 --- a/src/riscv/lib/src/stepper.rs +++ b/src/riscv/lib/src/stepper.rs @@ -4,7 +4,8 @@ use crate::{ machine_state::{ - bus::main_memory::MainMemoryLayout, instruction_cache::InstructionCacheLayout, MachineState, + bus::main_memory::MainMemoryLayout, instruction_cache::InstructionCacheLayout, + MachineCoreState, }, state_backend::{ManagerBase, ManagerRead}, }; @@ -83,9 +84,7 @@ pub trait Stepper { type Manager: ManagerBase + ManagerRead; /// Obtain a reference to the underlying machine state. - fn machine_state( - &self, - ) -> &MachineState; + fn machine_state(&self) -> &MachineCoreState; /// Result of one or more steps type StepResult: StepResult; diff --git a/src/riscv/lib/src/stepper/pvm.rs b/src/riscv/lib/src/stepper/pvm.rs index 1ca76a99d484..f5494145418f 100644 --- a/src/riscv/lib/src/stepper/pvm.rs +++ b/src/riscv/lib/src/stepper/pvm.rs @@ -9,7 +9,7 @@ use crate::{ bus::main_memory::{MainMemoryLayout, M1G}, instruction_cache::{DefaultInstructionCacheLayout, InstructionCacheLayout}, mode::Mode, - MachineError, MachineState, + MachineCoreState, MachineError, }, program::Program, pvm::{Pvm, PvmHooks, PvmLayout, PvmStatus}, @@ -133,10 +133,8 @@ impl<'hooks, ML: MainMemoryLayout, ICL: InstructionCacheLayout> Stepper type Manager = Owned; - fn machine_state( - &self, - ) -> &MachineState { - &self.pvm.machine_state + fn machine_state(&self) -> &MachineCoreState { + &self.pvm.machine_state.core } type StepResult = StepperStatus; diff --git a/src/riscv/lib/src/stepper/test.rs b/src/riscv/lib/src/stepper/test.rs index deb6725f8fbf..a02cbb27e5ab 100644 --- a/src/riscv/lib/src/stepper/test.rs +++ b/src/riscv/lib/src/stepper/test.rs @@ -11,7 +11,9 @@ use crate::{ bus::main_memory::{MainMemoryLayout, M1G}, instruction_cache::{InstructionCacheLayout, TestInstructionCacheLayout}, }, - machine_state::{mode, MachineError, MachineState, MachineStateLayout, StepManyResult}, + machine_state::{ + mode, MachineCoreState, MachineError, MachineState, MachineStateLayout, StepManyResult, + }, program::Program, state_backend::owned_backend::Owned, traps::EnvironException, @@ -161,10 +163,8 @@ impl Stepper for TestStepper &MachineState { - &self.machine_state + fn machine_state(&self) -> &MachineCoreState { + &self.machine_state.core } type StepResult = TestStepperResult; diff --git a/src/riscv/lib/src/stepper/test/posix.rs b/src/riscv/lib/src/stepper/test/posix.rs index 9cb82e7c3ef3..2ade83e7796f 100644 --- a/src/riscv/lib/src/stepper/test/posix.rs +++ b/src/riscv/lib/src/stepper/test/posix.rs @@ -84,9 +84,9 @@ impl PosixState { let exit_mode = self.exit_mode.read(); if source_mode != exit_mode { - let return_pc = machine.hart.pc.read(); - let new_pc = machine.hart.take_trap(source_exception, return_pc); - machine.hart.pc.write(new_pc); + let return_pc = machine.core.hart.pc.read(); + let new_pc = machine.core.hart.take_trap(source_exception, return_pc); + machine.core.hart.pc.write(new_pc); return Ok(true); } @@ -107,8 +107,8 @@ impl PosixState { // a7 = 93 & a0 = 1 | (TEST_FAILED << 1) // Failed virtual memory tests set // a7 = 0 (a7 never gets set) & a0 = 1 | (TEST_FAILED << 1) - let a7_val = machine.hart.xregisters.read(a7); - let a0_val = machine.hart.xregisters.read(a0); + let a7_val = machine.core.hart.xregisters.read(a7); + let a0_val = machine.core.hart.xregisters.read(a0); match (a7_val, a0_val) { // Exit (test pass, physical | virtual) (93, 0) | (0, 1) => handle_exit(0), diff --git a/src/riscv/sandbox/src/commands/debug/debugger_app.rs b/src/riscv/sandbox/src/commands/debug/debugger_app.rs index d57badcc8f19..fd7e75b07cfe 100644 --- a/src/riscv/sandbox/src/commands/debug/debugger_app.rs +++ b/src/riscv/sandbox/src/commands/debug/debugger_app.rs @@ -14,7 +14,7 @@ use octez_riscv::{ csregisters::satp::{Satp, SvLength, TranslationAlgorithm}, instruction_cache::InstructionCacheLayout, mode::Mode, - AccessType, MachineState, + AccessType, MachineCoreState, }, program::Program, pvm::PvmHooks, @@ -309,7 +309,7 @@ where .step_max(Bound::Included(1)) .to_stepper_status(); - let should_continue = |machine: &MachineState<_, _, _>| { + let should_continue = |machine: &MachineCoreState<_, _>| { let raw_pc = machine.hart.pc.read(); let pc = machine .translate_without_cache(raw_pc, AccessType::Instruction) @@ -337,7 +337,7 @@ where .step_max(Bound::Included(1)) .to_stepper_status(); - let should_continue = |machine: &MachineState<_, _, _>| { + let should_continue = |machine: &MachineCoreState<_, _>| { let raw_pc = machine.hart.pc.read(); let pc = machine .translate_without_cache(raw_pc, AccessType::Instruction) -- GitLab