WIP: adding load/store unit

This commit is contained in:
Jacob Lifshay 2026-07-10 19:16:13 -07:00
parent 09038d40ab
commit 0897b46f23
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
9 changed files with 16747 additions and 3 deletions

4
.cargo/config.toml Normal file
View file

@ -0,0 +1,4 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
# See Notices.txt for copyright information
[build]
rustflags = ["-Csymbol-mangling-version=v0", "-Cforce-frame-pointers=yes"]

View file

@ -19,6 +19,7 @@ use std::{
borrow::Cow, borrow::Cow,
fmt, fmt,
marker::PhantomData, marker::PhantomData,
num::NonZeroU64,
ops::{ControlFlow, Range}, ops::{ControlFlow, Range},
}; };
@ -2983,6 +2984,19 @@ pub enum LoadStoreWidth {
Width64Bit, Width64Bit,
} }
impl LoadStoreWidth {
#[hdl]
pub fn access_byte_size_sim(this: &<Self as Type>::SimValue) -> NonZeroU64 {
#[hdl(sim)]
match this {
Self::Width8Bit => const { NonZeroU64::new(1).unwrap() },
Self::Width16Bit => const { NonZeroU64::new(2).unwrap() },
Self::Width32Bit => const { NonZeroU64::new(4).unwrap() },
Self::Width64Bit => const { NonZeroU64::new(8).unwrap() },
}
}
}
#[hdl(cmp_eq)] #[hdl(cmp_eq)]
pub enum LoadStoreConversion { pub enum LoadStoreConversion {
ZeroExt, ZeroExt,

View file

@ -127,8 +127,47 @@ impl AddressRange {
}, },
} }
} }
pub const fn is_overlapping(self, other: Self) -> bool {
self.contains(other.start().0) || other.contains(self.start().0)
}
} }
const _: () = {
const N: u64 = 4;
const fn is_overlapping_reference(range1: AddressRange, range2: AddressRange) -> bool {
// we just need to check values < N since all starts/ends are < N
let mut v = 0;
while v < N {
if range1.contains(v) && range2.contains(v) {
return true;
}
v += 1;
}
false
}
let mut start1 = 0;
while start1 < N {
let mut end1 = 0;
while end1 < N {
let mut start2 = 0;
while start2 < N {
let mut end2 = 0;
while end2 < N {
let range1 = AddressRange::from_wrapping_range_inclusive(start1..=end1);
let range2 = AddressRange::from_wrapping_range_inclusive(start2..=end2);
assert!(
range1.is_overlapping(range2) == is_overlapping_reference(range1, range2)
);
end2 += 1;
}
start2 += 1;
}
end1 += 1;
}
start1 += 1;
}
};
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, serde::Serialize, serde::Deserialize)]
#[non_exhaustive] #[non_exhaustive]
pub struct MemoryInterfaceConfig { pub struct MemoryInterfaceConfig {

View file

@ -8,6 +8,7 @@ use crate::{
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, mop_enum, MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, mop_enum,
}, },
rename_execute_retire::ExecuteToUnitInterface, rename_execute_retire::ExecuteToUnitInterface,
unit::load_store::LoadStoreToDCacheInterface,
}; };
use fayalite::{ use fayalite::{
bundle::{Bundle, BundleType}, bundle::{Bundle, BundleType},
@ -18,6 +19,7 @@ use serde::{Deserialize, Serialize};
use std::ops::ControlFlow; use std::ops::ControlFlow;
pub mod alu_branch; pub mod alu_branch;
pub mod load_store;
macro_rules! all_units { macro_rules! all_units {
( (
@ -333,7 +335,7 @@ all_units! {
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()] #[create_dyn_unit_fn = |config, unit_index, filter| todo!()]
#[extract(transformed_move_mop, transformed_move_mop_sim, transformed_move_mop_sim_ref, transformed_move_mop_sim_mut)] #[extract(transformed_move_mop, transformed_move_mop_sim, transformed_move_mop_sim_ref, transformed_move_mop_sim_mut)]
TransformedMove(TransformedMoveOp), TransformedMove(TransformedMoveOp),
#[create_dyn_unit_fn = |config, unit_index, filter| todo!()] #[create_dyn_unit_fn = |config, unit_index, filter| load_store::LoadStore::new(config, unit_index, filter).to_dyn()]
#[extract(load_store_mop, load_store_mop_sim, load_store_mop_sim_ref, load_store_mop_sim_mut)] #[extract(load_store_mop, load_store_mop_sim, load_store_mop_sim_ref, load_store_mop_sim_mut)]
LoadStore(LoadStoreMOp<DestReg, SrcReg>), LoadStore(LoadStoreMOp<DestReg, SrcReg>),
} }
@ -391,6 +393,7 @@ impl RenamedMOpFilter for () {
pub struct UnitIO { pub struct UnitIO {
pub cd: Option<Expr<ClockDomain>>, pub cd: Option<Expr<ClockDomain>>,
pub from_execute: Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>>, pub from_execute: Expr<ExecuteToUnitInterface<PhantomConst<CpuConfig>>>,
pub to_d_cache: Option<Expr<LoadStoreToDCacheInterface<PhantomConst<CpuConfig>>>>,
} }
pub trait UnitTrait: pub trait UnitTrait:

View file

@ -1617,6 +1617,7 @@ impl UnitTrait for AluBranch {
UnitIO { UnitIO {
cd: None, cd: None,
from_execute: this.from_execute, from_execute: this.from_execute,
to_d_cache: None,
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -94,13 +94,17 @@ fn formal_harness(
let UnitIO { let UnitIO {
cd: unit_cd, cd: unit_cd,
from_execute: unit_from_execute, from_execute: unit_from_execute,
to_d_cache,
} = dyn_unit.io(unit); } = dyn_unit.io(unit);
if let Some(unit_cd) = unit_cd {
connect(unit_cd, cd);
}
connect( connect(
unit_from_execute, unit_from_execute,
ExecuteToUnitInterfaces::unit_fields(decode_and_run.to_units)[unit_index], ExecuteToUnitInterfaces::unit_fields(decode_and_run.to_units)[unit_index],
); );
if let Some(unit_cd) = unit_cd { if let Some(to_d_cache) = to_d_cache {
connect(unit_cd, cd); unimplemented!("to_d_cache for {unit:?}: {to_d_cache:?}");
} }
} }
hdl_assert(cd.clk, !decode_and_run.error, ""); hdl_assert(cd.clk, !decode_and_run.error, "");