idk why these weren't alr committed

This commit is contained in:
2026-03-04 04:38:31 +00:00
parent fb2e734a2f
commit 29077adb38
10 changed files with 865 additions and 0 deletions
+42
View File
@@ -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,
}
+177
View File
@@ -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))
}
}
+1
View File
@@ -0,0 +1 @@
pub mod instructions;
+105
View File
@@ -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) }
}
}
+132
View File
@@ -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) }
}
}
+63
View File
@@ -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);
}
}
+49
View File
@@ -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]);
}
+47
View File
@@ -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);
}
}
+103
View File
@@ -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) }
}
}