idk why these weren't alr committed
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
|
||||
use crate::{MemoryMap, RandomAccessMemory};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct DsaArgs {
|
||||
/// Memory map to use on boot.
|
||||
/// Overrides default value.
|
||||
#[arg(long = "mmap")]
|
||||
memory_map: Option<PathBuf>,
|
||||
|
||||
#[arg(value_enum, long = "mem", default_value = "bulk-alloc")]
|
||||
pub memory_bank: MemoryBank,
|
||||
}
|
||||
|
||||
impl DsaArgs {
|
||||
pub fn get_memory_map(&self) -> Option<MemoryMap> {
|
||||
self.memory_map.as_ref().and_then(|m| {
|
||||
fs::read_to_string(m)
|
||||
.ok()
|
||||
.and_then(|map| ron::from_str(&map).ok())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, ValueEnum, Default)]
|
||||
pub enum MemoryBank {
|
||||
#[cfg(feature = "mainstore-bulkalloc")]
|
||||
#[default]
|
||||
BulkAlloc,
|
||||
#[cfg(feature = "mainstore-arraymap")]
|
||||
ArrayMap,
|
||||
#[cfg(feature = "mainstore-hashmap")]
|
||||
HashMap,
|
||||
#[cfg(feature = "mainstore-prealloc")]
|
||||
PreAlloc,
|
||||
#[cfg(feature = "mainstore-stackarray")]
|
||||
StackArray,
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct InstructionWord(pub u32);
|
||||
|
||||
impl InstructionWord {
|
||||
#[inline]
|
||||
pub fn opcode(self) -> u8 {
|
||||
((self.0 >> 26) & 0x3F) as u8
|
||||
}
|
||||
|
||||
// Src shared between R type and I type
|
||||
#[inline]
|
||||
pub fn src1(self) -> Reg {
|
||||
Reg::from_u8_unchecked(((self.0 >> 21) & 0x1F) as u8)
|
||||
}
|
||||
|
||||
// Dest shared between R type and I type
|
||||
#[inline]
|
||||
pub fn dest(self) -> Reg {
|
||||
Reg::from_u8_unchecked(((self.0 >> 16) & 0x1F) as u8)
|
||||
}
|
||||
|
||||
// Secondary Src for R type only
|
||||
#[inline]
|
||||
pub fn src2(self) -> Reg {
|
||||
Reg::from_u8_unchecked(((self.0 >> 11) & 0x1F) as u8)
|
||||
}
|
||||
|
||||
// Misc/Conditional reg for R type only
|
||||
#[inline]
|
||||
pub fn misc(self) -> Reg {
|
||||
Reg::from_u8_unchecked(((self.0 >> 6) & 0x1F) as u8)
|
||||
}
|
||||
|
||||
// Shift amount / misc data for R type only
|
||||
#[inline]
|
||||
pub fn shamt(self) -> u8 {
|
||||
(self.0 & 0x3F) as u8
|
||||
}
|
||||
|
||||
// 16 Bit immediate for I type only
|
||||
#[inline]
|
||||
pub fn imm16(self) -> u16 {
|
||||
self.0 as u16
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Opcode {
|
||||
Nop = 0,
|
||||
|
||||
// move
|
||||
Mov = 1,
|
||||
CMov = 2,
|
||||
|
||||
// load
|
||||
Ldb = 3,
|
||||
Ldbs = 4,
|
||||
Ldh = 5,
|
||||
Ldhs = 6,
|
||||
Ldw = 7,
|
||||
|
||||
// store
|
||||
Stb = 8,
|
||||
Sth = 9,
|
||||
Stw = 10,
|
||||
|
||||
// load immediate
|
||||
Lli = 11,
|
||||
Lui = 12,
|
||||
|
||||
// comparison
|
||||
Ieq = 13,
|
||||
Ine = 14,
|
||||
Ilt = 15,
|
||||
Ile = 16,
|
||||
Igt = 17,
|
||||
Ige = 18,
|
||||
|
||||
// jump
|
||||
Jmp = 19,
|
||||
Jez = 20,
|
||||
Jnz = 21,
|
||||
Jic = 22,
|
||||
Jnc = 23,
|
||||
|
||||
// bitwise
|
||||
And = 24,
|
||||
Nand = 25,
|
||||
Or = 26,
|
||||
Nor = 27,
|
||||
Xor = 28,
|
||||
Xnor = 29,
|
||||
Not = 30,
|
||||
|
||||
// arithmetic
|
||||
Add = 31,
|
||||
Sub = 32,
|
||||
Shl = 33,
|
||||
Shr = 34,
|
||||
Addi = 35,
|
||||
Subi = 36,
|
||||
|
||||
// system
|
||||
Int = 37,
|
||||
Hlt = 38,
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
#[inline]
|
||||
pub fn from_u8(val: u8) -> Option<Self> {
|
||||
if val <= Self::Hlt as u8 {
|
||||
Some(unsafe { std::mem::transmute(val) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
|
||||
#[repr(u8)]
|
||||
#[non_exhaustive]
|
||||
pub enum Reg {
|
||||
// general purpose
|
||||
Rg0 = 0,
|
||||
Rg1 = 1,
|
||||
Rg2 = 2,
|
||||
Rg3 = 3,
|
||||
Rg4 = 4,
|
||||
Rg5 = 5,
|
||||
Rg6 = 6,
|
||||
Rg7 = 7,
|
||||
Rg8 = 8,
|
||||
Rg9 = 9,
|
||||
Rga = 10,
|
||||
Rgb = 11,
|
||||
Rgc = 12,
|
||||
Rgd = 13,
|
||||
Rge = 14,
|
||||
Rgf = 15,
|
||||
|
||||
// special purpose
|
||||
Zero = 16,
|
||||
Acc = 17,
|
||||
Spr = 18,
|
||||
Bpr = 19,
|
||||
Ret = 20,
|
||||
Idr = 21,
|
||||
Mmr = 22,
|
||||
|
||||
// system - read only
|
||||
Mar = 23,
|
||||
Mdr = 24,
|
||||
Sts = 25,
|
||||
Cir = 26,
|
||||
Pcx = 27,
|
||||
|
||||
#[default]
|
||||
Null = 28,
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn from_u8_unchecked(idx: u8) -> Self {
|
||||
debug_assert!(idx <= 28);
|
||||
unsafe { std::mem::transmute(idx) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_u8(idx: u8) -> Result<Self, ()> {
|
||||
if idx > 28 {
|
||||
return Err(());
|
||||
}
|
||||
Ok(Self::from_u8_unchecked(idx))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod instructions;
|
||||
@@ -0,0 +1,105 @@
|
||||
use std::{
|
||||
alloc::{Layout, alloc_zeroed},
|
||||
hint::{likely, unlikely},
|
||||
};
|
||||
|
||||
use crate::memory::{
|
||||
PhysAddr, RandomAccessMemory,
|
||||
ram::{NUM_PAGES, Page, idx},
|
||||
};
|
||||
|
||||
pub struct ArrayStore {
|
||||
pages: Box<[*mut Page; NUM_PAGES]>,
|
||||
}
|
||||
|
||||
unsafe impl Send for ArrayStore {}
|
||||
impl ArrayStore {
|
||||
pub fn new() -> Self {
|
||||
let pages = vec![0 as *mut Page; 2 << 20]
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
Self { pages }
|
||||
}
|
||||
|
||||
fn alloc(&mut self) -> *mut Page {
|
||||
let layout = Layout::from_size_align(4096, 4096).unwrap();
|
||||
unsafe { alloc_zeroed(layout) as *mut Page }
|
||||
}
|
||||
}
|
||||
|
||||
impl RandomAccessMemory for ArrayStore {
|
||||
#[inline(always)]
|
||||
fn read_word(&self, addr: PhysAddr) -> u32 {
|
||||
debug_assert_eq!(addr % 4, 0);
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { (self.pages[idx] as *const u32).byte_add(offset).read() };
|
||||
}
|
||||
|
||||
// Slow path: MMIO, fault, etc — never inlined
|
||||
// Since we're only reading, we can safely return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_byte(&self, addr: PhysAddr) -> u8 {
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { (self.pages[idx] as *const u8).byte_add(offset).read() };
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_page(&self, addr: PhysAddr) -> &[u8; 4096] {
|
||||
debug_assert_eq!(addr % 4096, 0);
|
||||
let (idx, _) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { &*(self.pages[idx] as *const [u8; 4096]) };
|
||||
}
|
||||
|
||||
return &[0; 4096];
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_byte(&mut self, addr: PhysAddr, value: u8) {
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(self.pages[idx] as *mut u8).byte_add(offset).write(value);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_word(&mut self, addr: PhysAddr, value: u32) {
|
||||
debug_assert_eq!(addr % 4, 0);
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe { (self.pages[idx] as *mut u32).byte_add(offset).write(value) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]) {
|
||||
debug_assert_eq!(addr % 4096, 0);
|
||||
let (idx, _) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe { (self.pages[idx] as *mut [u8; 4096]).write(*value) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
use std::{
|
||||
alloc::{Layout, alloc_zeroed},
|
||||
hint::{likely, unlikely},
|
||||
};
|
||||
|
||||
use crate::memory::{
|
||||
PhysAddr, RandomAccessMemory,
|
||||
ram::{NUM_PAGES, Page, idx},
|
||||
};
|
||||
|
||||
pub struct BulkAllocStore {
|
||||
pages: Box<[*mut Page; NUM_PAGES]>,
|
||||
pre_allocated: [*mut Page; Self::PREALLOC],
|
||||
idx: u8,
|
||||
}
|
||||
|
||||
unsafe impl Send for BulkAllocStore {}
|
||||
impl BulkAllocStore {
|
||||
const PREALLOC: usize = u8::MAX as usize;
|
||||
|
||||
pub fn new() -> Self {
|
||||
let pages = vec![0 as *mut Page; 2 << 20]
|
||||
.into_boxed_slice()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
pages,
|
||||
pre_allocated: Self::alloc_set(),
|
||||
idx: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_set() -> [*mut Page; Self::PREALLOC] {
|
||||
let layout = Layout::from_size_align(4096 * Self::PREALLOC, 4096).unwrap();
|
||||
let mut region = unsafe { alloc_zeroed(layout) as *mut Page };
|
||||
let mut set = [0 as *mut Page; Self::PREALLOC];
|
||||
for i in 0..Self::PREALLOC {
|
||||
set[i] = region;
|
||||
region = unsafe { region.byte_add(4096) };
|
||||
}
|
||||
set
|
||||
}
|
||||
|
||||
fn alloc(&mut self) -> *mut Page {
|
||||
if self.idx < Self::PREALLOC as u8 {
|
||||
let page = self.pre_allocated[self.idx as usize];
|
||||
self.idx += 1;
|
||||
page
|
||||
} else {
|
||||
self.idx = 0;
|
||||
self.pre_allocated = Self::alloc_set();
|
||||
self.pre_allocated[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RandomAccessMemory for BulkAllocStore {
|
||||
#[inline(always)]
|
||||
fn read_word(&self, addr: PhysAddr) -> u32 {
|
||||
debug_assert_eq!(addr % 4, 0);
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { (self.pages[idx] as *const u32).byte_add(offset).read() };
|
||||
}
|
||||
|
||||
// Slow path: MMIO, fault, etc — never inlined
|
||||
// Since we're only reading, we can safely return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_byte(&self, addr: PhysAddr) -> u8 {
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { (self.pages[idx] as *const u8).byte_add(offset).read() };
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_page(&self, addr: PhysAddr) -> &[u8; 4096] {
|
||||
debug_assert_eq!(addr % 4096, 0);
|
||||
let (idx, _) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { &*(self.pages[idx] as *const [u8; 4096]) };
|
||||
}
|
||||
|
||||
return &[0; 4096];
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_byte(&mut self, addr: PhysAddr, value: u8) {
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(self.pages[idx] as *mut u8).byte_add(offset).write(value);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_word(&mut self, addr: PhysAddr, value: u32) {
|
||||
debug_assert_eq!(addr % 4, 0);
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe { (self.pages[idx] as *mut u32).byte_add(offset).write(value) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]) {
|
||||
debug_assert_eq!(addr % 4096, 0);
|
||||
let (idx, _) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe { (self.pages[idx] as *mut [u8; 4096]).write(*value) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use fxhash::FxHashMap;
|
||||
|
||||
use crate::memory::{PhysAddr, RandomAccessMemory, ram::Page};
|
||||
|
||||
pub struct HashStore {
|
||||
pages: FxHashMap<PhysAddr, Page>,
|
||||
}
|
||||
|
||||
impl HashStore {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pages: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn segment_addr(addr: PhysAddr) -> (PhysAddr, usize) {
|
||||
(addr & !(0xFFF), (addr & 0xFFF) as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl RandomAccessMemory for HashStore {
|
||||
#[inline(always)]
|
||||
fn read_byte(&self, addr: PhysAddr) -> u8 {
|
||||
let (page, offset) = Self::segment_addr(addr);
|
||||
self.pages.get(&page).map(|p| p[offset]).unwrap_or(0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_word(&self, addr: PhysAddr) -> u32 {
|
||||
let (page, offset) = Self::segment_addr(addr);
|
||||
debug_assert_eq!(offset % 4, 0);
|
||||
let page = self.pages.get(&page).unwrap_or(&[0; 4096]);
|
||||
u32::from_be_bytes(page[offset..=offset + 3].try_into().unwrap())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_page(&self, addr: PhysAddr) -> &[u8; 4096] {
|
||||
debug_assert_eq!(addr % 0x1000, 0);
|
||||
self.pages.get(&addr).unwrap_or(&[0; 4096])
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_byte(&mut self, addr: PhysAddr, value: u8) {
|
||||
let (page, offset) = Self::segment_addr(addr);
|
||||
self.pages.entry(page).or_insert_with(|| [0; 4096])[offset] = value;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_word(&mut self, addr: PhysAddr, value: u32) {
|
||||
let (page, offset) = Self::segment_addr(addr);
|
||||
debug_assert_eq!(offset % 4, 0);
|
||||
let page = self.pages.entry(page).or_insert_with(|| [0; 4096]);
|
||||
page[offset..=offset + 3].copy_from_slice(&value.to_be_bytes());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]) {
|
||||
debug_assert_eq!(addr % 0x1000, 0);
|
||||
let page = self.pages.entry(addr).or_insert_with(|| [0; 4096]);
|
||||
page.copy_from_slice(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
use crate::memory::PhysAddr;
|
||||
|
||||
#[cfg(feature = "mainstore-arraymap")]
|
||||
pub mod arraymap;
|
||||
#[cfg(feature = "mainstore-arraymap")]
|
||||
pub use arraymap::ArrayStore;
|
||||
|
||||
#[cfg(feature = "mainstore-hashmap")]
|
||||
pub mod hashmap;
|
||||
#[cfg(feature = "mainstore-hashmap")]
|
||||
pub use hashmap::HashStore;
|
||||
|
||||
#[cfg(feature = "mainstore-stackarray")]
|
||||
pub mod stackarray;
|
||||
#[cfg(feature = "mainstore-stackarray")]
|
||||
pub use stackarray::StackArrayStore;
|
||||
|
||||
#[cfg(feature = "mainstore-bulkalloc")]
|
||||
pub mod bulkalloc;
|
||||
#[cfg(feature = "mainstore-bulkalloc")]
|
||||
pub use bulkalloc::BulkAllocStore;
|
||||
|
||||
#[cfg(feature = "mainstore-prealloc")]
|
||||
pub mod prealloc;
|
||||
#[cfg(feature = "mainstore-prealloc")]
|
||||
pub use prealloc::PreAllocStore;
|
||||
|
||||
const NUM_PAGES: usize = 2 << 20;
|
||||
|
||||
type Page = [u8; 4096];
|
||||
|
||||
#[inline(always)]
|
||||
const fn idx(addr: PhysAddr) -> (usize, usize) {
|
||||
((addr >> 12) as usize, (addr & 0xFFF) as usize)
|
||||
}
|
||||
|
||||
pub trait RandomAccessMemory {
|
||||
fn read_byte(&self, addr: PhysAddr) -> u8;
|
||||
|
||||
fn write_byte(&mut self, addr: PhysAddr, value: u8);
|
||||
|
||||
fn read_word(&self, addr: PhysAddr) -> u32;
|
||||
|
||||
fn write_word(&mut self, addr: PhysAddr, value: u32);
|
||||
|
||||
fn read_page(&self, addr: PhysAddr) -> &[u8; 4096];
|
||||
|
||||
fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use crate::memory::{PhysAddr, RandomAccessMemory, ram::NUM_PAGES};
|
||||
|
||||
pub struct PreAllocStore {
|
||||
heap: Box<[u8; NUM_PAGES * 4096]>,
|
||||
}
|
||||
|
||||
unsafe impl Send for PreAllocStore {}
|
||||
impl PreAllocStore {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
heap: unsafe { Box::new_zeroed().assume_init() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RandomAccessMemory for PreAllocStore {
|
||||
#[inline(always)]
|
||||
fn read_word(&self, addr: PhysAddr) -> u32 {
|
||||
unsafe { (self.heap.as_ptr().add(addr as usize) as *const u32).read() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_byte(&self, addr: PhysAddr) -> u8 {
|
||||
self.heap[addr as usize]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_page(&self, addr: PhysAddr) -> &[u8; 4096] {
|
||||
debug_assert_eq!(addr % 4096, 0);
|
||||
unsafe { (self.heap.as_ptr().add(addr as usize) as *const [u8; 4096]).as_ref_unchecked() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_byte(&mut self, addr: PhysAddr, value: u8) {
|
||||
self.heap[addr as usize] = value;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_word(&mut self, addr: PhysAddr, value: u32) {
|
||||
unsafe { (self.heap.as_ptr().add(addr as usize) as *mut u32).write(value) };
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]) {
|
||||
self.heap[addr as usize..addr as usize + 4096].copy_from_slice(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
use std::{
|
||||
alloc::{Layout, alloc_zeroed},
|
||||
hint::{likely, unlikely},
|
||||
};
|
||||
|
||||
use crate::memory::{
|
||||
PhysAddr, RandomAccessMemory,
|
||||
ram::{NUM_PAGES, Page, idx},
|
||||
};
|
||||
|
||||
pub struct StackArrayStore {
|
||||
pages: [*mut Page; NUM_PAGES],
|
||||
}
|
||||
|
||||
unsafe impl Send for StackArrayStore {}
|
||||
impl StackArrayStore {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pages: [0 as *mut Page; 2 << 20],
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc(&mut self) -> *mut Page {
|
||||
let layout = Layout::from_size_align(4096, 4096).unwrap();
|
||||
unsafe { alloc_zeroed(layout) as *mut Page }
|
||||
}
|
||||
}
|
||||
|
||||
impl RandomAccessMemory for StackArrayStore {
|
||||
#[inline(always)]
|
||||
fn read_word(&self, addr: PhysAddr) -> u32 {
|
||||
debug_assert_eq!(addr % 4, 0);
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { (self.pages[idx] as *const u32).byte_add(offset).read() };
|
||||
}
|
||||
|
||||
// Slow path: MMIO, fault, etc — never inlined
|
||||
// Since we're only reading, we can safely return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_byte(&self, addr: PhysAddr) -> u8 {
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { (self.pages[idx] as *const u8).byte_add(offset).read() };
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn read_page(&self, addr: PhysAddr) -> &[u8; 4096] {
|
||||
debug_assert_eq!(addr % 4096, 0);
|
||||
let (idx, _) = idx(addr);
|
||||
|
||||
if likely(!self.pages[idx].is_null()) {
|
||||
return unsafe { &*(self.pages[idx] as *const [u8; 4096]) };
|
||||
}
|
||||
|
||||
return &[0; 4096];
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_byte(&mut self, addr: PhysAddr, value: u8) {
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(self.pages[idx] as *mut u8).byte_add(offset).write(value);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_word(&mut self, addr: PhysAddr, value: u32) {
|
||||
debug_assert_eq!(addr % 4, 0);
|
||||
let (idx, offset) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe { (self.pages[idx] as *mut u32).byte_add(offset).write(value) }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn write_page(&mut self, addr: PhysAddr, value: &[u8; 4096]) {
|
||||
debug_assert_eq!(addr % 4096, 0);
|
||||
let (idx, _) = idx(addr);
|
||||
|
||||
if unlikely(self.pages[idx].is_null()) {
|
||||
self.pages[idx] = self.alloc();
|
||||
}
|
||||
|
||||
unsafe { (self.pages[idx] as *mut [u8; 4096]).write(*value) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user