From a7cf9b73cb5c99931b3a1c965223a4c593fd2bbe Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Tue, 1 Oct 2024 15:28:06 +0100 Subject: [PATCH 1/3] RISC-V: remove block cache --- .../lib/src/machine_state/block_cache.rs | 521 ------------------ 1 file changed, 521 deletions(-) delete mode 100644 src/riscv/lib/src/machine_state/block_cache.rs diff --git a/src/riscv/lib/src/machine_state/block_cache.rs b/src/riscv/lib/src/machine_state/block_cache.rs deleted file mode 100644 index 5750d003a192..000000000000 --- a/src/riscv/lib/src/machine_state/block_cache.rs +++ /dev/null @@ -1,521 +0,0 @@ -// SPDX-FileCopyrightText: 2024 TriliTech -// -// SPDX-License-Identifier: MIT - -use crate::state_backend::{self, CellWrite}; -use crate::{ - cache_utils::FenceCounter, - parser::instruction::InstrCacheable, - state_backend::{ - AllocatedOf, Atom, Cell, LazyCell, ManagerBase, ManagerRead, ManagerReadWrite, - ManagerWrite, Ref, - }, - traps::Exception, -}; - -use super::address_translation::PAGE_SIZE; -use super::instruction_cache::ValidatedCacheEntry; -use super::MachineCoreState; -use super::{ - bus::{main_memory, Address}, - ProgramCounterUpdate, -}; -use crate::cache_utils::{Sizes, Unparsed}; - -const CACHE_INSTR: usize = 20; - -pub type CachedLayout = ( - Atom
, - Atom, - Atom, - [Atom; CACHE_INSTR], -); - -pub struct Cached { - address: Cell, - fence_counter: Cell, - len_instr: Cell, - instr: [LazyCell; CACHE_INSTR], -} - -impl Cached { - fn bind(space: AllocatedOf) -> Self { - Self { - address: space.0, - fence_counter: space.1, - len_instr: space.2, - instr: space - .3 - .into_iter() - .map(|p| LazyCell::wrap(p)) - .collect::>() - .try_into() - .ok() - .unwrap(), - } - } - - fn invalidate(&mut self) - where - M: ManagerWrite, - { - self.address.write(0); - self.len_instr.write(0); - } - - fn reset(&mut self) - where - M: ManagerWrite, - { - self.address.write(0); - self.fence_counter.write(FenceCounter::INITIAL); - self.len_instr.write(0); - self.instr.iter_mut().for_each(|lc| lc.reset(Unparsed(0))); - } - - fn block(&mut self) -> Block - where - M: ManagerRead, - { - Block { - instr: &mut self.instr[..self.len_instr.read() as usize], - } - } - - fn struct_ref(&self) -> AllocatedOf> { - ( - self.address.struct_ref(), - self.fence_counter.struct_ref(), - self.len_instr.struct_ref(), - self.instr - .iter() - .map(LazyCell::struct_ref) - .collect::>() - .try_into() - .map_err(|_| "mismatching lengths for block instructions") - .unwrap(), - ) - } -} - -/// The default instruction cache index bits. -pub const DEFAULT_CACHE_BITS: usize = 16; - -/// The default instruction cache size. -pub const DEFAULT_CACHE_SIZE: usize = 1 << DEFAULT_CACHE_BITS; - -/// The default instruction cache index bits for tests. -pub const TEST_CACHE_BITS: usize = 12; - -/// The default instruction cache for tests. -pub const TEST_CACHE_SIZE: usize = 1 << TEST_CACHE_BITS; - -/// Trait for capturing the different possible layouts of the instruction cache (i.e. -/// controlling the number of cache entries present). -pub trait BlockCacheLayout: state_backend::Layout { - type Entries; - type Sizes; - - fn refl( - space: state_backend::AllocatedOf, - ) -> BlockCache - where - Self: Sized; - - fn entry(entries: &Self::Entries, phys_addr: Address) -> &Cached; - - fn entry_mut( - entries: &mut Self::Entries, - phys_addr: Address, - ) -> &mut Cached; - - fn entries_reset(entries: &mut Self::Entries); - - fn struct_ref(cache: &BlockCache) -> AllocatedOf> - where - Self: Sized; -} - -pub type Layout = - (Atom
, Atom, Sizes); - -impl BlockCacheLayout for Layout { - type Entries = Box<[Cached; SIZE]>; - type Sizes = Sizes; - - fn refl(space: AllocatedOf) -> BlockCache { - BlockCache { - phys_addr: space.0, - offset: space.1, - fence_counter: space.2 .0, - entries: space - .2 - .1 - .into_iter() - .map(Cached::bind) - .collect::>() - .into_boxed_slice() - .try_into() - .map_err(|_| "mismatching vector lengths for instruction cache") - .unwrap(), - } - } - - fn entry(entries: &Self::Entries, phys_addr: Address) -> &Cached { - &entries[Self::Sizes::cache_index(phys_addr)] - } - - fn entry_mut( - entries: &mut Self::Entries, - phys_addr: Address, - ) -> &mut Cached { - &mut entries[Self::Sizes::cache_index(phys_addr)] - } - - fn entries_reset(entries: &mut Self::Entries) { - entries.iter_mut().for_each(Cached::reset) - } - - fn struct_ref(cache: &BlockCache) -> AllocatedOf> { - ( - cache.phys_addr.struct_ref(), - cache.offset.struct_ref(), - ( - cache.fence_counter.struct_ref(), - cache.entries.iter().map(Cached::struct_ref).collect(), - ), - ) - } -} - -pub struct BlockCache { - phys_addr: Cell, - fence_counter: Cell, - offset: Cell, - entries: BCL::Entries, -} - -impl BlockCache { - pub fn bind(space: AllocatedOf) -> Self { - BCL::refl(space) - } - - pub fn invalidate(&mut self) - where - M: ManagerReadWrite, - { - let counter = self.fence_counter.read(); - self.fence_counter.write(counter.next()); - self.reset_to(0); - BCL::entry_mut(&mut self.entries, counter.0 as Address).invalidate(); - } - - pub fn reset(&mut self) - where - M: ManagerWrite, - { - self.fence_counter.write(FenceCounter::INITIAL); - self.reset_to(0); - BCL::entries_reset(&mut self.entries); - } - - pub fn struct_ref(&self) -> AllocatedOf> { - BCL::struct_ref(self) - } - - pub fn push_instr(&mut self, entry: ValidatedCacheEntry) - where - M: ManagerReadWrite, - { - let (phys_addr, instr, unparsed) = entry.unwrap(); - - let mut current_start = self.phys_addr.read(); - let mut offset = self.offset.read(); - - if phys_addr % PAGE_SIZE == 0 || phys_addr != current_start + offset as Address { - self.reset_to(phys_addr); - current_start = phys_addr; - offset = 0; - } - - let next = offset + WIDTH; - if self.cache_inner(current_start, phys_addr, instr, unparsed) { - self.reset_to(next as u64) - } else { - self.offset.write(offset + WIDTH); - } - } - - fn reset_to(&mut self, pa: Address) - where - M: ManagerWrite, - { - self.phys_addr.write(pa); - self.offset.write(0); - } - - fn cache_inner( - &mut self, - block_addr: Address, - phys_addr: Address, - instr: InstrCacheable, - bytes: Unparsed, - ) -> bool - where - M: ManagerReadWrite, - { - let entry = BCL::entry_mut(&mut self.entries, block_addr); - - let start = entry.address.read(); - if start != block_addr || entry.address.read() == phys_addr { - entry.address.write(block_addr); - entry.len_instr.write(0); - entry.fence_counter.write(self.fence_counter.read()); - } - - let len_instr = entry.len_instr.read(); - - entry.instr[len_instr as usize].write((instr, bytes)); - - let new_len = len_instr + 1; - entry.len_instr.write(new_len); - - new_len == CACHE_INSTR as u8 - } - - pub fn get_block(&mut self, phys_addr: Address) -> Option> - where - M: ManagerReadWrite, - { - let entry = BCL::entry_mut(&mut self.entries, phys_addr); - - if entry.address.read() == phys_addr - && self.fence_counter.read() == entry.fence_counter.read() - { - let block = entry.block(); - Some(block) - } else { - None - } - } -} - -pub struct Block<'a, M: ManagerBase> { - instr: &'a mut [LazyCell], -} - -impl<'a, M: ManagerRead> Block<'a, M> { - pub fn num_instr(&self) -> usize { - self.instr.len() - } - - pub(super) fn run_block( - &mut self, - core: &mut MachineCoreState, - instr_pc: &mut Address, - _phys_addr: Address, - steps: &mut usize, - ) -> Result - where - ML: main_memory::MainMemoryLayout, - M: ManagerReadWrite, - { - for i in self.instr.iter_mut().map(|i| &i.read_ref().0) { - match core.run_instr_cacheable(i) { - Err(e) => return Err(e), - Ok(r @ ProgramCounterUpdate::Set(_)) => { - return Ok(r); - } - Ok(ProgramCounterUpdate::Add(width)) => { - *instr_pc += width; - } - } - core.hart.pc.write(*instr_pc); - *steps += 1; - } - Ok(ProgramCounterUpdate::Set(*instr_pc)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - backend_test, create_backend, create_state, - machine_state::registers::{a0, t0, t1}, - parser::instruction::{CIBTypeArgs, SBTypeArgs}, - }; - - pub type TestLayout = Layout; - - // writing CACHE_INSTR to the block cache creates new block - backend_test!(test_writing_full_block_fetchable_uncompressed, F, { - let mut backend = create_backend!(TestLayout, F); - let mut state = create_state!(BlockCache, TestLayout, F, backend, TestLayout); - - let uncompressed_bytes = 0x00533423; - let uncompressed = InstrCacheable::Sd(SBTypeArgs { - rs1: t1, - rs2: t0, - imm: 8, - }); - - let phys_addr = 10; - - for offset in 0..(CACHE_INSTR as u64) { - let entry = ValidatedCacheEntry::from_unchecked( - phys_addr + (offset * 4), - uncompressed, - Unparsed(uncompressed_bytes), - ); - state.push_instr::<4>(entry); - } - - let block = state.get_block(phys_addr); - assert!(block.is_some()); - assert_eq!(CACHE_INSTR, block.unwrap().num_instr()); - }); - - backend_test!(test_writing_full_block_fetchable_compressed, F, { - let mut backend = create_backend!(TestLayout, F); - let mut state = create_state!(BlockCache, TestLayout, F, backend, TestLayout); - - let compressed_bytes = 0x4505; - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); - - let phys_addr = 10; - - for offset in 0..(CACHE_INSTR as u64) { - let entry = ValidatedCacheEntry::from_unchecked( - phys_addr + (offset * 2), - compressed, - Unparsed(compressed_bytes), - ); - state.push_instr::<2>(entry); - } - - let block = state.get_block(phys_addr); - assert!(block.is_some()); - assert_eq!(CACHE_INSTR, block.unwrap().num_instr()); - }); - - // writing instructions immediately creates block - backend_test!(test_writing_half_block_fetchable_compressed, F, { - let mut backend = create_backend!(TestLayout, F); - let mut state = create_state!(BlockCache, TestLayout, F, backend, TestLayout); - - let compressed_bytes = 0x4505; - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); - - let phys_addr = 10; - - for offset in 0..((CACHE_INSTR / 2) as u64) { - let entry = ValidatedCacheEntry::from_unchecked( - phys_addr + (offset * 2), - compressed, - Unparsed(compressed_bytes), - ); - state.push_instr::<2>(entry); - } - - let block = state.get_block(phys_addr); - assert!(block.is_some()); - assert_eq!(CACHE_INSTR / 2, block.unwrap().num_instr()); - }); - - backend_test!(test_writing_two_blocks_fetchable_compressed, F, { - let mut backend = create_backend!(TestLayout, F); - let mut state = create_state!(BlockCache, TestLayout, F, backend, TestLayout); - - let compressed_bytes = 0x4505; - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); - - let phys_addr = 10; - - for offset in 0..((CACHE_INSTR * 2) as u64) { - let entry = ValidatedCacheEntry::from_unchecked( - phys_addr + (offset * 2), - compressed, - Unparsed(compressed_bytes), - ); - state.push_instr::<2>(entry); - } - - let block = state.get_block(phys_addr); - assert!(block.is_some()); - assert_eq!(CACHE_INSTR, block.unwrap().num_instr()); - - let block = state.get_block(50); - assert!(block.is_some()); - assert_eq!(CACHE_INSTR, block.unwrap().num_instr()); - }); - - // writing across pages offset two blocks next to each other - backend_test!(test_crossing_page_exactly_creates_new_block, F, { - let mut backend = create_backend!(TestLayout, F); - let mut state = create_state!(BlockCache, TestLayout, F, backend, TestLayout); - - let compressed_bytes = 0x4505; - let compressed = InstrCacheable::CLi(CIBTypeArgs { rd_rs1: a0, imm: 1 }); - - let phys_addr = PAGE_SIZE - 10; - - for offset in 0..10 { - let entry = ValidatedCacheEntry::from_unchecked( - phys_addr + (offset * 2), - compressed, - Unparsed(compressed_bytes), - ); - state.push_instr::<2>(entry); - } - - let block = state.get_block(phys_addr); - assert!(block.is_some()); - assert_eq!(5, block.unwrap().num_instr()); - - let block = state.get_block(phys_addr + 10); - assert!(block.is_some()); - assert_eq!(5, block.unwrap().num_instr()); - }); - - // writing across pages offset creates two blocks with a gap - // TODO: needs to be done at the machine state level - backend_test!( - #[ignore] - test_crossing_page_offset_creates_new_block, - F, - { - let mut backend = create_backend!(TestLayout, F); - let mut state = create_state!(BlockCache, TestLayout, F, backend, TestLayout); - - let uncompressed_bytes = 0x00533423; - let uncompressed = InstrCacheable::Sd(SBTypeArgs { - rs1: t1, - rs2: t0, - imm: 8, - }); - - let phys_addr = PAGE_SIZE - 6; - - for offset in 0..3 { - let entry = ValidatedCacheEntry::from_unchecked( - phys_addr + (offset * 4), - uncompressed, - Unparsed(uncompressed_bytes), - ); - state.push_instr::<4>(entry); - } - - let block = state.get_block(phys_addr); - assert!(block.is_some()); - assert_eq!(1, block.unwrap().num_instr()); - - let block = state.get_block(phys_addr + 4); - assert!(block.is_none()); - - let block = state.get_block(phys_addr + 8); - assert!(block.is_some()); - assert_eq!(1, block.unwrap().num_instr()); - } - ); -} -- GitLab From 837ff557d0ff5eed0372c80bd16dce0f4e041168 Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Tue, 24 Sep 2024 11:44:37 +0100 Subject: [PATCH 2/3] RISC-V: move Unparsed to cache utils To be re-used by the block cache. --- src/riscv/lib/src/cache_utils.rs | 70 ++++++++++++++++++- .../src/machine_state/instruction_cache.rs | 67 +----------------- 2 files changed, 72 insertions(+), 65 deletions(-) diff --git a/src/riscv/lib/src/cache_utils.rs b/src/riscv/lib/src/cache_utils.rs index 4ad7331ffcc5..426890f0da3e 100644 --- a/src/riscv/lib/src/cache_utils.rs +++ b/src/riscv/lib/src/cache_utils.rs @@ -2,7 +2,15 @@ // // SPDX-License-Identifier: MIT -use crate::state_backend::Elem; +use std::convert::Infallible; + +use crate::{ + parser::{ + instruction::{Instr, InstrCacheable}, + parse, + }, + state_backend::Elem, +}; /// Integer to keep track of the fence counter #[derive( @@ -45,3 +53,63 @@ impl Elem for FenceCounter { Self(u32::from_stored(&source.0)) } } + +/// Unparsed instruction used for storing cached instructions in the state. +/// +/// Compressed instructions are represented as the lower-16 bits of the u32, with upper-16 bits +/// set to zero. +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[repr(transparent)] +pub struct Unparsed(pub u32); + +impl Elem for Unparsed { + #[inline(always)] + fn store(&mut self, source: &Self) { + self.0.store(&source.0) + } + + #[inline(always)] + fn to_stored_in_place(&mut self) { + self.0.to_stored_in_place() + } + + #[inline(always)] + fn from_stored_in_place(&mut self) { + self.0.from_stored_in_place() + } + + #[inline(always)] + fn from_stored(source: &Self) -> Self { + Self(u32::from_stored(&source.0)) + } +} + +impl From for (InstrCacheable, Unparsed) { + fn from(unparsed: Unparsed) -> Self { + let bytes = unparsed.0; + let upper = bytes as u16; + + let instr = parse(upper, || { + Result::::Ok((bytes >> 16) as u16) + }) + .unwrap(); + + match instr { + Instr::Cacheable(i) => (i, unparsed), + // As written, this code path is unreachable. + // We can convert it into a static requirement by allowing + // errors on bind, instead + // + // TODO RV-221: on bind, we should error if an instruction's + // bytes correspond to an Uncacheable instruction, rather + // than returning an 'Unknown' instruction. + Instr::Uncacheable(_) => (InstrCacheable::Unknown { instr: bytes }, unparsed), + } + } +} + +impl From<(InstrCacheable, Unparsed)> for Unparsed { + fn from((_, unparsed): (InstrCacheable, Unparsed)) -> Self { + unparsed + } +} diff --git a/src/riscv/lib/src/machine_state/instruction_cache.rs b/src/riscv/lib/src/machine_state/instruction_cache.rs index abde39fdc12b..4a40b0c0fc87 100644 --- a/src/riscv/lib/src/machine_state/instruction_cache.rs +++ b/src/riscv/lib/src/machine_state/instruction_cache.rs @@ -33,16 +33,15 @@ //! translation changes - as the upper address may no longer point //! to the same relative physical address. -use crate::cache_utils::FenceCounter; +use crate::cache_utils::{FenceCounter, Unparsed}; use crate::machine_state::address_translation::PAGE_SIZE; use crate::machine_state::bus::Address; use crate::parser::instruction::{Instr, InstrCacheable}; -use crate::parser::{parse, parse_compressed_instruction, parse_uncompressed_instruction}; +use crate::parser::{parse_compressed_instruction, parse_uncompressed_instruction}; use crate::state_backend::{ - self, AllocatedOf, Atom, Cell, CellWrite, Choreographer, Elem, Layout, LazyCell, ManagerAlloc, + self, AllocatedOf, Atom, Cell, CellWrite, Choreographer, Layout, LazyCell, ManagerAlloc, ManagerBase, ManagerRead, ManagerReadWrite, ManagerWrite, Many, Placed, Ref, }; -use std::convert::Infallible; /// The layout of an entry in the instruction cache. pub type CachedLayout = (Atom, Atom, Atom); @@ -94,66 +93,6 @@ impl Cached { } } -/// Unparsed instruction used for storing cached instructions in the state. -/// -/// Compressed instructions are represented as the lower-16 bits of the u32, with upper-16 bits -/// set to zero. -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[repr(transparent)] -pub struct Unparsed(u32); - -impl Elem for Unparsed { - #[inline(always)] - fn store(&mut self, source: &Self) { - self.0.store(&source.0) - } - - #[inline(always)] - fn to_stored_in_place(&mut self) { - self.0.to_stored_in_place() - } - - #[inline(always)] - fn from_stored_in_place(&mut self) { - self.0.from_stored_in_place() - } - - #[inline(always)] - fn from_stored(source: &Self) -> Self { - Self(u32::from_stored(&source.0)) - } -} - -impl From for (InstrCacheable, Unparsed) { - fn from(unparsed: Unparsed) -> Self { - let bytes = unparsed.0; - let upper = bytes as u16; - - let instr = parse(upper, || { - Result::::Ok((bytes >> 16) as u16) - }) - .unwrap(); - - match instr { - Instr::Cacheable(i) => (i, unparsed), - // As written, this code path is unreachable. - // We can convert it into a static requirement by allowing - // errors on bind, instead - // - // TODO RV-221: on bind, we should error if an instruction's - // bytes correspond to an Uncacheable instruction, rather - // than returning an 'Unknown' instruction. - Instr::Uncacheable(_) => (InstrCacheable::Unknown { instr: bytes }, unparsed), - } - } -} - -impl From<(InstrCacheable, Unparsed)> for Unparsed { - fn from((_, unparsed): (InstrCacheable, Unparsed)) -> Self { - unparsed - } -} - /// Configuration object for the size of the instruction cache. /// /// *NB* you should ensure `SIZE == 1 << BITS`, otherwise a compilation error will occur: -- GitLab From ddd85a4f826e92a537997710263999ed49e6b452 Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Tue, 24 Sep 2024 12:24:14 +0100 Subject: [PATCH 3/3] RISC-V: introduce higher-level cache layout configuration trait --- src/riscv/lib/src/cache_utils.rs | 69 ++++++++++++- src/riscv/lib/src/interpreter/rv64zifencei.rs | 9 +- src/riscv/lib/src/machine_state.rs | 70 ++++++------- .../lib/src/machine_state/cache_layouts.rs | 34 +++++++ .../src/machine_state/instruction_cache.rs | 99 +++++-------------- src/riscv/lib/src/pvm/common.rs | 32 +++--- src/riscv/lib/src/pvm/node_pvm.rs | 8 +- src/riscv/lib/src/pvm/sbi.rs | 88 ++++++++--------- src/riscv/lib/src/stepper.rs | 7 +- src/riscv/lib/src/stepper/pvm.rs | 21 ++-- src/riscv/lib/src/stepper/test.rs | 21 ++-- src/riscv/lib/src/stepper/test/posix.rs | 7 +- .../src/commands/debug/debugger_app.rs | 9 +- src/riscv/sandbox/src/commands/run.rs | 4 +- 14 files changed, 248 insertions(+), 230 deletions(-) create mode 100644 src/riscv/lib/src/machine_state/cache_layouts.rs diff --git a/src/riscv/lib/src/cache_utils.rs b/src/riscv/lib/src/cache_utils.rs index 426890f0da3e..ccf2d540fa18 100644 --- a/src/riscv/lib/src/cache_utils.rs +++ b/src/riscv/lib/src/cache_utils.rs @@ -2,15 +2,15 @@ // // SPDX-License-Identifier: MIT -use std::convert::Infallible; - use crate::{ + machine_state::bus::Address, parser::{ instruction::{Instr, InstrCacheable}, parse, }, - state_backend::Elem, + state_backend::{Choreographer, Elem, Layout, ManagerAlloc, ManagerBase, Many, Placed}, }; +use std::{convert::Infallible, marker::PhantomData}; /// Integer to keep track of the fence counter #[derive( @@ -113,3 +113,66 @@ impl From<(InstrCacheable, Unparsed)> for Unparsed { unparsed } } + +/// Configuration object for the size of a cache indexed by physical address. +/// +/// *NB* you should ensure `SIZE == 1 << BITS`, otherwise a compilation error will occur. +pub struct Sizes( + PhantomData, + Infallible, +); + +impl Sizes { + pub const CACHE_SIZE: usize = if 1 << BITS == SIZE { + SIZE + } else { + panic!("BITS parameter does not match SIZE parameter"); + }; + + const CACHE_MASK: usize = { + Self::fence_counter_wrapping_protection(); + Self::CACHE_SIZE - 1 + }; + + // We know that phys_addr here is always u16-aligned. + // Therefore, we can safely halve the number of buckets we + // look at. + #[inline(always)] + pub const fn cache_index(phys_addr: Address) -> usize { + (phys_addr >> 1) as usize & Self::CACHE_MASK + } + + /// Assert that the fence counter would not wrap before every cache entry has been invalidated + /// _at least_ once. + const fn fence_counter_wrapping_protection() { + let invalidation_count_until_wrapping = FenceCounter::MAX.0 as usize; + let cache_entries = Self::CACHE_SIZE; + + assert!( + invalidation_count_until_wrapping > cache_entries, + "The fence counter does a full cycle before all cache entries could be invalidated!" + ); + } +} + +type SizesLayout = Many; + +impl Layout + for Sizes +{ + type Placed = as Layout>::Placed; + + fn place_with(alloc: &mut Choreographer) -> Self::Placed { + SizesLayout::::place_with(alloc) + } + + fn placed() -> Placed { + SizesLayout::::placed() + } + + type Allocated = as Layout>::Allocated; + + fn allocate(backend: &mut M, placed: Self::Placed) -> Self::Allocated { + SizesLayout::::allocate(backend, placed) + } +} diff --git a/src/riscv/lib/src/interpreter/rv64zifencei.rs b/src/riscv/lib/src/interpreter/rv64zifencei.rs index 02b57c3fd061..f88b447747bc 100644 --- a/src/riscv/lib/src/interpreter/rv64zifencei.rs +++ b/src/riscv/lib/src/interpreter/rv64zifencei.rs @@ -5,17 +5,14 @@ //! Implementation of Zifencei extension for RISC-V use crate::{ - machine_state::{ - bus::main_memory::MainMemoryLayout, instruction_cache::InstructionCacheLayout, AccessType, - MachineState, - }, + machine_state::{bus::main_memory::MainMemoryLayout, AccessType, CacheLayouts, MachineState}, state_backend, }; -impl MachineState +impl MachineState where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: state_backend::ManagerReadWrite, { /// Execute a `fence.i` instruction. diff --git a/src/riscv/lib/src/machine_state.rs b/src/riscv/lib/src/machine_state.rs index 29d93b961906..0d863336123c 100644 --- a/src/riscv/lib/src/machine_state.rs +++ b/src/riscv/lib/src/machine_state.rs @@ -7,6 +7,7 @@ pub mod address_translation; pub mod bus; +mod cache_layouts; pub mod csregisters; pub mod hart_state; pub mod instruction_cache; @@ -17,7 +18,8 @@ pub mod reservation_set; #[cfg(test)] extern crate proptest; -use self::instruction_cache::{InstructionCache, InstructionCacheLayout}; +pub use self::cache_layouts::{CacheLayouts, DefaultCacheLayouts, TestCacheLayouts}; +use self::instruction_cache::InstructionCache; use crate::{ bits::u64, devicetree, @@ -32,7 +34,7 @@ use crate::{ }, program::Program, range_utils::{bound_saturating_sub, less_than_bound, unwrap_bound}, - state_backend::{self as backend}, + state_backend as backend, traps::{EnvironException, Exception, Interrupt, TrapContext}, }; pub use address_translation::AccessType; @@ -62,16 +64,19 @@ pub struct MachineCoreState = (MachineCoreStateLayout, ICL); +pub type MachineStateLayout = ( + MachineCoreStateLayout, + ::InstructionCacheLayout, +); /// The machine state contains everything required to fetch & run instructions. pub struct MachineState< ML: main_memory::MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: backend::ManagerBase, > { pub core: MachineCoreState, - pub instruction_cache: InstructionCache, + pub instruction_cache: InstructionCache, } /// How to modify the program counter @@ -551,11 +556,11 @@ impl MachineCoreStat } } -impl - MachineState +impl + MachineState { /// 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 { core: MachineCoreState::bind(space.0), instruction_cache: InstructionCache::bind(space.1), @@ -565,7 +570,7 @@ impl backend::AllocatedOf, backend::Ref<'_, M>> { + ) -> backend::AllocatedOf, backend::Ref<'_, M>> { (self.core.struct_ref(), self.instruction_cache.struct_ref()) } @@ -1033,9 +1038,9 @@ mod tests { xstatus::{self, MStatus}, CSRRepr, CSRegister, }, - instruction_cache::TestInstructionCacheLayout, mode::Mode, registers::{a0, a1, a2, t0, t1, t2, zero}, + TestCacheLayouts, }, parser::{ instruction::{CIBTypeArgs, ITypeArgs, Instr, InstrCacheable, SBTypeArgs}, @@ -1048,16 +1053,15 @@ mod tests { #[test] fn test_machine_state_reset() { - test_determinism::, _>(|space| { - let mut machine: MachineState = - MachineState::bind(space); + test_determinism::, _>(|space| { + let mut machine: MachineState = MachineState::bind(space); machine.reset(); }); } backend_test!(test_step, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineStateLayout, F); + let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestCacheLayouts); let state_cell = std::cell::RefCell::new(state); proptest!(|( @@ -1104,8 +1108,8 @@ mod tests { }); backend_test!(test_step_env_exc, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineStateLayout, F); + let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestCacheLayouts); let state_cell = std::cell::RefCell::new(state); proptest!(|( @@ -1141,8 +1145,8 @@ mod tests { }); backend_test!(test_step_exc_mm, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineStateLayout, F); + let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestCacheLayouts); let state_cell = std::cell::RefCell::new(state); proptest!(|( @@ -1185,8 +1189,8 @@ mod tests { }); backend_test!(test_step_exc_us, F, { - let mut backend = create_backend!(MachineStateLayout, F); - let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestInstructionCacheLayout); + let mut backend = create_backend!(MachineStateLayout, F); + let state = create_state!(MachineState, MachineStateLayout, F, backend, T1K, TestCacheLayouts); let state_cell = std::cell::RefCell::new(state); proptest!(|( @@ -1226,8 +1230,8 @@ mod tests { #[test] fn test_reset() { - test_determinism::, _>(|space| { - let mut machine_state: MachineState = + test_determinism::, _>(|space| { + let mut machine_state: MachineState = MachineState::bind(space); machine_state.reset(); }); @@ -1273,11 +1277,11 @@ mod tests { }))] ); - let mut backend = create_backend!(MachineStateLayout, F); + let mut backend = create_backend!(MachineStateLayout, F); // Configure the machine state. { - let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1K, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1K, TestCacheLayouts); state.reset(); let start_ram = start_of_main_memory::(); @@ -1308,7 +1312,7 @@ mod tests { // Perform 2 steps consecutively in one backend. let result = { - let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1K, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1K, TestCacheLayouts); state.step().unwrap(); state.step().unwrap(); state.core.hart.xregisters.read(t2) @@ -1317,12 +1321,12 @@ mod tests { // Perform 2 steps separately in another backend by re-binding the state between steps. let alt_result = { { - let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1K, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1K, TestCacheLayouts); state.step().unwrap(); } { - let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1K, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1K, TestCacheLayouts); state.step().unwrap(); state.core.hart.xregisters.read(t2) } @@ -1340,7 +1344,7 @@ mod tests { // TODO: RV-210: Generalise for all testable backends. type F = crate::state_backend::memory_backend::test_helpers::InMemoryBackendFactory; - let mut backend = create_backend!(MachineStateLayout, F); + let mut backend = create_backend!(MachineStateLayout, F); // Specify the physcal memory layout. let main_mem_addr = start_of_main_memory::(); @@ -1495,7 +1499,7 @@ mod tests { // Configure the state backend. { - let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1M, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1M, TestCacheLayouts); state.reset(); state @@ -1523,7 +1527,7 @@ mod tests { // 2 steps consecutively against one backend. let result = { - let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1M, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, backend, M1M, TestCacheLayouts); state.step().unwrap(); state.step().unwrap(); state.core.hart.xregisters.read(a0) @@ -1532,11 +1536,11 @@ mod tests { // Perform 2 steps separately in another backend by re-binding the state between steps. let alt_result = { { - let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1M, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1M, TestCacheLayouts); state.step().unwrap(); } { - let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1M, TestInstructionCacheLayout); + let mut state = create_state!(MachineState, MachineStateLayout, F, alt_backend, M1M, TestCacheLayouts); state.step().unwrap(); state.core.hart.xregisters.read(a0) } diff --git a/src/riscv/lib/src/machine_state/cache_layouts.rs b/src/riscv/lib/src/machine_state/cache_layouts.rs new file mode 100644 index 000000000000..3cce5a3470be --- /dev/null +++ b/src/riscv/lib/src/machine_state/cache_layouts.rs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2024 TriliTech +// +// SPDX-License-Identifier: MIT + +//! This module provides a wrapper for controlling the sizes of various caches. +//! +//! In future, this may be expanded to other compile-time-sized types that form +//! part of the machine state (e.g. main memory). + +use super::instruction_cache::{self, InstructionCacheLayout}; + +/// Configuration bucket for the size of caches. +pub enum Sizes {} + +/// Wrapping trait for a bucket containing layouts for various caches used by the machine state. +pub trait CacheLayouts { + /// Layout for the instruction cache - controlling the number of entries. + type InstructionCacheLayout: InstructionCacheLayout; +} + +impl CacheLayouts + for Sizes +{ + type InstructionCacheLayout = + instruction_cache::Layout; +} + +/// The default configuration of cache layouts. +pub type DefaultCacheLayouts = + Sizes<{ instruction_cache::DEFAULT_CACHE_BITS }, { instruction_cache::DEFAULT_CACHE_SIZE }>; + +/// The default configuration of cache layouts for tests. +pub type TestCacheLayouts = + Sizes<{ instruction_cache::TEST_CACHE_BITS }, { instruction_cache::TEST_CACHE_SIZE }>; diff --git a/src/riscv/lib/src/machine_state/instruction_cache.rs b/src/riscv/lib/src/machine_state/instruction_cache.rs index 4a40b0c0fc87..ac90c8a93917 100644 --- a/src/riscv/lib/src/machine_state/instruction_cache.rs +++ b/src/riscv/lib/src/machine_state/instruction_cache.rs @@ -33,14 +33,14 @@ //! translation changes - as the upper address may no longer point //! to the same relative physical address. -use crate::cache_utils::{FenceCounter, Unparsed}; +use crate::cache_utils::{FenceCounter, Sizes, Unparsed}; use crate::machine_state::address_translation::PAGE_SIZE; use crate::machine_state::bus::Address; use crate::parser::instruction::{Instr, InstrCacheable}; use crate::parser::{parse_compressed_instruction, parse_uncompressed_instruction}; use crate::state_backend::{ - self, AllocatedOf, Atom, Cell, CellWrite, Choreographer, Layout, LazyCell, ManagerAlloc, - ManagerBase, ManagerRead, ManagerReadWrite, ManagerWrite, Many, Placed, Ref, + self, AllocatedOf, Atom, Cell, CellWrite, LazyCell, ManagerBase, ManagerRead, ManagerReadWrite, + ManagerWrite, Ref, }; /// The layout of an entry in the instruction cache. @@ -93,63 +93,17 @@ impl Cached { } } -/// Configuration object for the size of the instruction cache. -/// -/// *NB* you should ensure `SIZE == 1 << BITS`, otherwise a compilation error will occur: -/// -/// The following fails to compile: -/// ```compile_fail -/// # use octez_riscv::machine_state::instruction_cache::Sizes; -/// pub type SizesX = Sizes<15, { 1 << 16 }>; -/// println!("{}", SizesX::CACHE_SIZE); -/// ``` -/// -/// But the following would succeed: -/// ```no_run -/// # use octez_riscv::machine_state::instruction_cache::Sizes; -/// pub type SizesY = Sizes<15, { 1 << 15 }>; -/// println!("{}", SizesY::CACHE_SIZE); -/// ``` -pub enum Sizes {} - -impl Sizes { - pub const CACHE_SIZE: usize = if 1 << BITS == SIZE { - SIZE - } else { - panic!("BITS parameter does not match SIZE parameter"); - }; +/// The default instruction cache index bits. +pub const DEFAULT_CACHE_BITS: usize = 16; - const CACHE_MASK: usize = { - Self::fence_counter_wrapping_protection(); - Self::CACHE_SIZE - 1 - }; - - // We know that phys_addr here is always u16-aligned. - // Therefore, we can safely halve the number of buckets we - // look at. - #[inline(always)] - const fn cache_index(phys_addr: Address) -> usize { - (phys_addr >> 1) as usize & Self::CACHE_MASK - } - - /// Assert that the fence counter would not wrap before every cache entry has been invalidated - /// _at least_ once. - const fn fence_counter_wrapping_protection() { - let invalidation_count_until_wrapping = FenceCounter::MAX.0 as usize; - let cache_entries = Self::CACHE_SIZE; - - assert!( - invalidation_count_until_wrapping > cache_entries, - "The fence counter does a full cycle before all cache entries could be invalidated!" - ); - } -} +/// The default instruction cache size. +pub const DEFAULT_CACHE_SIZE: usize = 1 << DEFAULT_CACHE_BITS; -/// The default instruction cache layout used in the sandbox/rollup node when running kernels. -pub type DefaultInstructionCacheLayout = Sizes<16, 65536>; +/// The default instruction cache index bits for tests. +pub const TEST_CACHE_BITS: usize = 12; -/// The instruction cache layout recommended for use in tests. -pub type TestInstructionCacheLayout = Sizes<12, 4096>; +/// The default instruction cache for tests. +pub const TEST_CACHE_SIZE: usize = 1 << TEST_CACHE_BITS; /// Trait for capturing the different possible layouts of the instruction cache (i.e. /// controlling the number of cache entries present). @@ -176,29 +130,14 @@ pub trait InstructionCacheLayout: state_backend::Layout { ) -> AllocatedOf> where Self: Sized; -} - -type SizesLayout = (Atom, Many); - -impl Layout for Sizes { - type Placed = as Layout>::Placed; - - fn place_with(alloc: &mut Choreographer) -> Self::Placed { - SizesLayout::::place_with(alloc) - } - - fn placed() -> Placed { - SizesLayout::::placed() - } - type Allocated = as Layout>::Allocated; - - fn allocate(backend: &mut M, placed: Self::Placed) -> Self::Allocated { - SizesLayout::::allocate(backend, placed) - } + fn cache_index(address: Address) -> usize; } -impl InstructionCacheLayout for Sizes { +pub type Layout = + (Atom, Sizes); + +impl InstructionCacheLayout for Layout { type Entries = Box<[Cached; SIZE]>; fn refl(space: AllocatedOf) -> InstructionCache { @@ -239,6 +178,10 @@ impl InstructionCacheLayout for Sizes usize { + Sizes::::cache_index(address) + } } /// Instruction Cache caches instructions by physical address, allowing them to be @@ -370,6 +313,8 @@ mod tests { parser::instruction::{CIBTypeArgs, InstrCacheable, SBTypeArgs}, }; + pub type TestInstructionCacheLayout = Layout; + // Ensure that the initialised values for the instruction cache (ie phys_addr = 0) // are not actually returned from the cache. This would result in an incorrect // `UnknownInstr` being executed, rather than an `OutOfBounds` error (for reading from diff --git a/src/riscv/lib/src/pvm/common.rs b/src/riscv/lib/src/pvm/common.rs index 2e2e90235454..4eb9ad001907 100644 --- a/src/riscv/lib/src/pvm/common.rs +++ b/src/riscv/lib/src/pvm/common.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use crate::{ - machine_state::{self, bus::main_memory, instruction_cache}, + machine_state::{self, bus::main_memory}, pvm::sbi, state_backend::{self, EnumCell, EnumCellLayout}, traps::EnvironException, @@ -42,9 +42,9 @@ impl<'a> Default for PvmHooks<'a> { } /// PVM state layout -pub type PvmLayout = ( +pub type PvmLayout = ( state_backend::Atom, - machine_state::MachineStateLayout, + machine_state::MachineStateLayout, EnumCellLayout, ); @@ -104,22 +104,22 @@ const INITIAL_VERSION: u64 = 0; /// Proof-generating virtual machine pub struct Pvm< ML: main_memory::MainMemoryLayout, - ICL: instruction_cache::InstructionCacheLayout, + CL: machine_state::CacheLayouts, M: state_backend::ManagerBase, > { version: state_backend::Cell, - pub(crate) machine_state: machine_state::MachineState, + pub(crate) machine_state: machine_state::MachineState, status: EnumCell, } impl< ML: main_memory::MainMemoryLayout, - ICL: instruction_cache::InstructionCacheLayout, + CL: machine_state::CacheLayouts, M: state_backend::ManagerBase, - > Pvm + > Pvm { /// Bind the PVM to the given allocated region. - pub fn bind(space: state_backend::AllocatedOf, M>) -> Self { + pub fn bind(space: state_backend::AllocatedOf, M>) -> Self { Self { version: space.0, machine_state: machine_state::MachineState::bind(space.1), @@ -130,7 +130,7 @@ impl< /// Obtain a structure with references to the bound regions of this type. pub fn struct_ref( &self, - ) -> state_backend::AllocatedOf, state_backend::Ref<'_, M>> { + ) -> state_backend::AllocatedOf, state_backend::Ref<'_, M>> { ( self.version.struct_ref(), self.machine_state.struct_ref(), @@ -251,12 +251,12 @@ impl< mod tests { use super::*; use crate::{ + machine_state::TestCacheLayouts, machine_state::{ bus::{ main_memory::{M1K, M1M}, start_of_main_memory, AddressableRead, }, - instruction_cache::TestInstructionCacheLayout, registers::{a0, a1, a2, a3, a6, a7}, }, state_backend::{memory_backend::InMemoryBackend, tests::test_determinism, Backend}, @@ -270,12 +270,12 @@ mod tests { #[test] fn test_read_input() { type ML = M1M; - type L = PvmLayout; + type L = PvmLayout; // Setup PVM let (mut backend, placed) = InMemoryBackend::::new(); let space = backend.allocate(placed); - let mut pvm = Pvm::::bind(space); + let mut pvm = Pvm::::bind(space); pvm.reset(); let level_addr = start_of_main_memory::(); @@ -363,7 +363,7 @@ mod tests { #[test] fn test_write_debug() { type ML = M1M; - type L = PvmLayout; + type L = PvmLayout; let mut buffer = Vec::new(); let mut hooks = PvmHooks::new(|c| buffer.push(c)); @@ -371,7 +371,7 @@ mod tests { // Setup PVM let (mut backend, placed) = InMemoryBackend::::new(); let space = backend.allocate(placed); - let mut pvm = Pvm::::bind(space); + let mut pvm = Pvm::::bind(space); pvm.reset(); // Prepare subsequent ECALLs to use the SBI_CONSOLE_PUTCHAR extension @@ -406,12 +406,12 @@ mod tests { #[test] fn test_reset() { - test_determinism::, _>(|mut space| { + test_determinism::, _>(|mut space| { // The [Pvm] type won't bind unless the version cell is set to its initial value. // TODO: RV-46 might change this constraint in the future. space.0.write(INITIAL_VERSION); - let mut machine_state: Pvm = Pvm::bind(space); + let mut machine_state: Pvm = Pvm::bind(space); machine_state.reset(); }); } diff --git a/src/riscv/lib/src/pvm/node_pvm.rs b/src/riscv/lib/src/pvm/node_pvm.rs index c782654f6ca9..852ea7cfb3a9 100644 --- a/src/riscv/lib/src/pvm/node_pvm.rs +++ b/src/riscv/lib/src/pvm/node_pvm.rs @@ -4,9 +4,7 @@ // SPDX-License-Identifier: MIT use crate::{ - machine_state::{ - bus::main_memory::M100M, instruction_cache::DefaultInstructionCacheLayout, mode::Mode, - }, + machine_state::{bus::main_memory::M100M, mode::Mode, DefaultCacheLayouts}, program::Program, pvm::common::{Pvm, PvmHooks, PvmLayout, PvmStatus}, state_backend::{ @@ -21,7 +19,7 @@ use std::{ops::Bound, path::Path}; use thiserror::Error; pub type StateLayout = ( - PvmLayout, + PvmLayout, state_backend::Atom, state_backend::Atom, state_backend::Atom, @@ -29,7 +27,7 @@ pub type StateLayout = ( ); pub struct State { - pvm: Pvm, + pvm: Pvm, level_is_set: state_backend::Cell, level: state_backend::Cell, message_counter: state_backend::Cell, diff --git a/src/riscv/lib/src/pvm/sbi.rs b/src/riscv/lib/src/pvm/sbi.rs index 6bf93b1809ff..1cab96675bb4 100644 --- a/src/riscv/lib/src/pvm/sbi.rs +++ b/src/riscv/lib/src/pvm/sbi.rs @@ -6,9 +6,8 @@ use super::{PvmHooks, PvmStatus}; use crate::{ machine_state::{ bus::{main_memory::MainMemoryLayout, AddressableRead, AddressableWrite}, - instruction_cache::InstructionCacheLayout, registers::{a0, a1, a2, a3, a6, a7, XValue}, - AccessType, MachineState, + AccessType, CacheLayouts, MachineState, }, parser::instruction::InstrUncacheable, state_backend::{CellRead, CellReadWrite, CellWrite, ManagerReadWrite}, @@ -27,8 +26,8 @@ use tezos_smart_rollup_constants::{ /// Write the SBI error code as the return value. #[inline(always)] -fn sbi_return_error( - machine: &mut MachineState, +fn sbi_return_error( + machine: &mut MachineState, code: SbiError, ) { machine.core.hart.xregisters.write(a0, code as i64 as u64); @@ -36,8 +35,8 @@ fn sbi_return_error( - machine: &mut MachineState, +fn sbi_return1( + machine: &mut MachineState, value: XValue, ) { // The SBI caller interprets the return value as a [i64]. We don't want the value to be @@ -51,8 +50,8 @@ fn sbi_return1( - machine: &mut MachineState, +fn sbi_return_sbiret( + machine: &mut MachineState, error: Option, value: XValue, ) { @@ -66,12 +65,12 @@ fn sbi_return_sbiret(machine: &mut MachineState, inner: F) +fn sbi_wrap(machine: &mut MachineState, inner: F) where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, - F: FnOnce(&mut MachineState) -> Result, + F: FnOnce(&mut MachineState) -> Result, { match inner(machine) { Ok(value) => sbi_return1(machine, value), @@ -81,13 +80,10 @@ where /// Respond to a request for input with no input. Returns `false` in case the /// machine wasn't expecting any input, otherwise returns `true`. -pub fn provide_no_input( - status: &mut S, - machine: &mut MachineState, -) -> bool +pub fn provide_no_input(status: &mut S, machine: &mut MachineState) -> bool where S: CellReadWrite, - ICL: InstructionCacheLayout, + CL: CacheLayouts, ML: MainMemoryLayout, M: ManagerReadWrite, { @@ -107,16 +103,16 @@ where /// Provide input information to the machine. Returns `false` in case the /// machine wasn't expecting any input, otherwise returns `true`. -pub fn provide_input( +pub fn provide_input( status: &mut S, - machine: &mut MachineState, + machine: &mut MachineState, level: u32, counter: u32, payload: &[u8], ) -> bool where S: CellReadWrite, - ICL: InstructionCacheLayout, + CL: CacheLayouts, ML: MainMemoryLayout, M: ManagerReadWrite, { @@ -169,15 +165,15 @@ where /// Provide metadata in response to a metadata request. Returns `false` /// if the machine is not expecting metadata. -pub fn provide_metadata( +pub fn provide_metadata( status: &mut S, - machine: &mut MachineState, + machine: &mut MachineState, rollup_address: &[u8; 20], origination_level: u32, ) -> bool where S: CellReadWrite, - ICL: InstructionCacheLayout, + CL: CacheLayouts, ML: MainMemoryLayout, M: ManagerReadWrite, { @@ -232,12 +228,12 @@ where /// Produce a Ed25519 signature. #[inline] -fn handle_tezos_ed25519_sign( - machine: &mut MachineState, +fn handle_tezos_ed25519_sign( + machine: &mut MachineState, ) -> Result where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { let arg_sk_addr = machine.core.hart.xregisters.read(a0); @@ -266,12 +262,12 @@ where /// Verify a Ed25519 signature. #[inline] -fn handle_tezos_ed25519_verify( - machine: &mut MachineState, +fn handle_tezos_ed25519_verify( + machine: &mut MachineState, ) -> Result where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { let arg_pk_addr = machine.core.hart.xregisters.read(a0); @@ -301,12 +297,12 @@ where /// Compute a BLAKE2B 256-bit digest. #[inline] -fn handle_tezos_blake2b_hash256( - machine: &mut MachineState, +fn handle_tezos_blake2b_hash256( + machine: &mut MachineState, ) -> Result where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { let arg_out_addr = machine.core.hart.xregisters.read(a0); @@ -327,10 +323,10 @@ where /// Handle a [SBI_SHUTDOWN] call. #[inline(always)] -fn handle_legacy_shutdown(machine: &mut MachineState) +fn handle_legacy_shutdown(machine: &mut MachineState) where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { // This call always fails. @@ -339,12 +335,12 @@ where /// Handle a [SBI_CONSOLE_PUTCHAR] call. #[inline(always)] -fn handle_legacy_console_putchar( - machine: &mut MachineState, +fn handle_legacy_console_putchar( + machine: &mut MachineState, hooks: &mut PvmHooks, ) where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { let char = machine.core.hart.xregisters.read(a0) as u8; @@ -356,12 +352,12 @@ fn handle_legacy_console_putchar( /// Handle a [SBI_DBCN_CONSOLE_WRITE_BYTE] call. #[inline(always)] -fn handle_debug_console_write_byte( - machine: &mut MachineState, +fn handle_debug_console_write_byte( + machine: &mut MachineState, hooks: &mut PvmHooks, ) where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { let char = machine.core.hart.xregisters.read(a0) as u8; @@ -373,10 +369,10 @@ fn handle_debug_console_write_byte( /// Handle a [SBI_SRST_SYSTEM_RESET] call. #[inline(always)] -fn handle_system_reset(machine: &mut MachineState) +fn handle_system_reset(machine: &mut MachineState) where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { sbi_return_sbiret(machine, Some(SbiError::NotSupported), 0); @@ -384,10 +380,10 @@ where /// Handle unsupported SBI calls. #[inline(always)] -fn handle_not_supported(machine: &mut MachineState) +fn handle_not_supported(machine: &mut MachineState) where ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { // SBI requires us to indicate that we don't support this function by returning @@ -397,16 +393,16 @@ where /// Handle a PVM SBI call. Returns `true` if it makes sense to continue evaluation. #[inline] -pub fn handle_call( +pub fn handle_call( status: &mut S, - machine: &mut MachineState, + machine: &mut MachineState, hooks: &mut PvmHooks, env_exception: EnvironException, ) -> bool where S: CellReadWrite, ML: MainMemoryLayout, - ICL: InstructionCacheLayout, + CL: CacheLayouts, M: ManagerReadWrite, { if let EnvironException::EnvCallFromMMode = env_exception { diff --git a/src/riscv/lib/src/stepper.rs b/src/riscv/lib/src/stepper.rs index e8ca676a750d..ce9bcf8fe52c 100644 --- a/src/riscv/lib/src/stepper.rs +++ b/src/riscv/lib/src/stepper.rs @@ -3,10 +3,7 @@ // SPDX-License-Identifier: MIT use crate::{ - machine_state::{ - bus::main_memory::MainMemoryLayout, instruction_cache::InstructionCacheLayout, - MachineCoreState, - }, + machine_state::{bus::main_memory::MainMemoryLayout, CacheLayouts, MachineCoreState}, state_backend::{ManagerBase, ManagerRead}, }; use std::ops::{AddAssign, Bound}; @@ -78,7 +75,7 @@ pub trait Stepper { type MainMemoryLayout: MainMemoryLayout; /// Layout of the instruction cache - type InstructionCacheLayout: InstructionCacheLayout; + type CacheLayouts: CacheLayouts; /// State backend with which the stepper was instantiated type Manager: ManagerBase + ManagerRead; diff --git a/src/riscv/lib/src/stepper/pvm.rs b/src/riscv/lib/src/stepper/pvm.rs index f5494145418f..adf5885beaed 100644 --- a/src/riscv/lib/src/stepper/pvm.rs +++ b/src/riscv/lib/src/stepper/pvm.rs @@ -7,9 +7,8 @@ use crate::{ kernel_loader, machine_state::{ bus::main_memory::{MainMemoryLayout, M1G}, - instruction_cache::{DefaultInstructionCacheLayout, InstructionCacheLayout}, mode::Mode, - MachineCoreState, MachineError, + CacheLayouts, DefaultCacheLayouts, MachineCoreState, MachineError, }, program::Program, pvm::{Pvm, PvmHooks, PvmLayout, PvmStatus}, @@ -30,19 +29,15 @@ pub enum PvmStepperError { } /// Wrapper over a PVM that lets you step through it -pub struct PvmStepper< - 'hooks, - ML: MainMemoryLayout = M1G, - ICL: InstructionCacheLayout = DefaultInstructionCacheLayout, -> { - pvm: Pvm, +pub struct PvmStepper<'hooks, ML: MainMemoryLayout = M1G, CL: CacheLayouts = DefaultCacheLayouts> { + pvm: Pvm, hooks: PvmHooks<'hooks>, inbox: Inbox, rollup_address: [u8; 20], origination_level: u32, } -impl<'hooks, ML: MainMemoryLayout, ICL: InstructionCacheLayout> PvmStepper<'hooks, ML, ICL> { +impl<'hooks, ML: MainMemoryLayout, CL: CacheLayouts> PvmStepper<'hooks, ML, CL> { /// Create a new PVM stepper. pub fn new( program: &[u8], @@ -52,7 +47,7 @@ impl<'hooks, ML: MainMemoryLayout, ICL: InstructionCacheLayout> PvmStepper<'hook rollup_address: [u8; 20], origination_level: u32, ) -> Result { - let space = Owned::allocate::>(); + let space = Owned::allocate::>(); let mut pvm = Pvm::bind(space); let program = Program::::from_elf(program)?; @@ -124,12 +119,10 @@ impl<'hooks, ML: MainMemoryLayout, ICL: InstructionCacheLayout> PvmStepper<'hook } } -impl<'hooks, ML: MainMemoryLayout, ICL: InstructionCacheLayout> Stepper - for PvmStepper<'hooks, ML, ICL> -{ +impl<'hooks, ML: MainMemoryLayout, CL: CacheLayouts> Stepper for PvmStepper<'hooks, ML, CL> { type MainMemoryLayout = ML; - type InstructionCacheLayout = ICL; + type CacheLayouts = CL; type Manager = Owned; diff --git a/src/riscv/lib/src/stepper/test.rs b/src/riscv/lib/src/stepper/test.rs index a02cbb27e5ab..13831ee8a00c 100644 --- a/src/riscv/lib/src/stepper/test.rs +++ b/src/riscv/lib/src/stepper/test.rs @@ -9,10 +9,8 @@ use crate::{ kernel_loader, machine_state::{ bus::main_memory::{MainMemoryLayout, M1G}, - instruction_cache::{InstructionCacheLayout, TestInstructionCacheLayout}, - }, - machine_state::{ - mode, MachineCoreState, MachineError, MachineState, MachineStateLayout, StepManyResult, + mode, CacheLayouts, MachineCoreState, MachineError, MachineState, MachineStateLayout, + StepManyResult, TestCacheLayouts, }, program::Program, state_backend::owned_backend::Owned, @@ -73,14 +71,11 @@ pub enum TestStepperError { MachineError(MachineError), } -pub type TestStepperLayout = - (PosixStateLayout, MachineStateLayout); +pub type TestStepperLayout = + (PosixStateLayout, MachineStateLayout); -pub struct TestStepper< - ML: MainMemoryLayout = M1G, - ICL: InstructionCacheLayout = TestInstructionCacheLayout, -> { - machine_state: MachineState, +pub struct TestStepper { + machine_state: MachineState, posix_state: PosixState, } @@ -155,10 +150,10 @@ impl TestStepper { } } -impl Stepper for TestStepper { +impl Stepper for TestStepper { type MainMemoryLayout = ML; - type InstructionCacheLayout = TestInstructionCacheLayout; + type CacheLayouts = TestCacheLayouts; type Manager = Owned; diff --git a/src/riscv/lib/src/stepper/test/posix.rs b/src/riscv/lib/src/stepper/test/posix.rs index 2ade83e7796f..352f3f1d92b9 100644 --- a/src/riscv/lib/src/stepper/test/posix.rs +++ b/src/riscv/lib/src/stepper/test/posix.rs @@ -5,10 +5,9 @@ use crate::{ machine_state::{ bus::main_memory::MainMemoryLayout, - instruction_cache::InstructionCacheLayout, mode::{Mode, ModeCell, ModeLayout}, registers::{a0, a7}, - MachineState, + CacheLayouts, MachineState, }, state_backend::{ AllocatedOf, Atom, Cell, ManagerBase, ManagerRead, ManagerReadWrite, ManagerWrite, @@ -62,9 +61,9 @@ impl PosixState { } /// Handle a POSIX system call. Returns `Ok(true)` if it makes sense to continue execution. - pub fn handle_call( + pub fn handle_call( &mut self, - machine: &mut MachineState, + machine: &mut MachineState, env_exception: EnvironException, ) -> Result where diff --git a/src/riscv/sandbox/src/commands/debug/debugger_app.rs b/src/riscv/sandbox/src/commands/debug/debugger_app.rs index fd7e75b07cfe..b6d2c083542d 100644 --- a/src/riscv/sandbox/src/commands/debug/debugger_app.rs +++ b/src/riscv/sandbox/src/commands/debug/debugger_app.rs @@ -12,9 +12,8 @@ use octez_riscv::{ machine_state::{ bus::{main_memory::MainMemoryLayout, Address}, csregisters::satp::{Satp, SvLength, TranslationAlgorithm}, - instruction_cache::InstructionCacheLayout, mode::Mode, - AccessType, MachineCoreState, + AccessType, CacheLayouts, MachineCoreState, }, program::Program, pvm::PvmHooks, @@ -175,9 +174,7 @@ impl<'a, ML: MainMemoryLayout> DebuggerApp<'a, TestStepper> { } } -impl<'hooks, ML: MainMemoryLayout, ICL: InstructionCacheLayout> - DebuggerApp<'_, PvmStepper<'hooks, ML, ICL>> -{ +impl<'hooks, ML: MainMemoryLayout, CL: CacheLayouts> DebuggerApp<'_, PvmStepper<'hooks, ML, CL>> { /// Launch the Debugger app for a PVM. pub fn launch( fname: &str, @@ -189,7 +186,7 @@ impl<'hooks, ML: MainMemoryLayout, ICL: InstructionCacheLayout> ) -> Result<()> { let hooks = PvmHooks::new(|_| {}); - let mut stepper = PvmStepper::<'_, ML, ICL>::new( + let mut stepper = PvmStepper::<'_, ML, CL>::new( program, initrd, inbox, diff --git a/src/riscv/sandbox/src/commands/run.rs b/src/riscv/sandbox/src/commands/run.rs index ae9fd70910f9..29953d7a4049 100644 --- a/src/riscv/sandbox/src/commands/run.rs +++ b/src/riscv/sandbox/src/commands/run.rs @@ -8,7 +8,7 @@ use crate::{ posix_exit_mode, }; use octez_riscv::{ - machine_state::{bus::main_memory::M1G, instruction_cache::DefaultInstructionCacheLayout}, + machine_state::{bus::main_memory::M1G, DefaultCacheLayouts}, pvm::PvmHooks, stepper::{pvm::PvmStepper, test::TestStepper, StepResult, Stepper, StepperStatus}, }; @@ -94,7 +94,7 @@ fn run_pvm( let _written = console.write(&[c]).unwrap(); }); - let stepper = PvmStepper::<'_, M1G, DefaultInstructionCacheLayout>::new( + let stepper = PvmStepper::<'_, M1G, DefaultCacheLayouts>::new( program, initrd, inbox.build(), -- GitLab