WIP adding fetch::l1_i_cache

This commit is contained in:
Jacob Lifshay 2026-02-04 17:55:14 -08:00
parent c62d33048c
commit de81b9d8a4
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
3 changed files with 116 additions and 0 deletions

View file

@ -37,6 +37,8 @@ pub struct CpuConfig {
pub max_branches_per_fetch: NonZeroUsize,
pub max_fetches_in_flight: NonZeroUsize,
pub log2_fetch_width_in_bytes: u8,
pub log2_cache_line_size_in_bytes: u8,
pub l1_i_cache_line_count: NonZeroUsize,
/// default value for [`UnitConfig::max_in_flight`]
pub default_unit_max_in_flight: NonZeroUsize,
pub rob_size: NonZeroUsize,
@ -63,6 +65,13 @@ impl CpuConfig {
v
};
pub const DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES: u8 = 3;
pub const DEFAULT_LOG2_CACHE_LINE_SIZE_IN_BYTES: u8 = 6;
pub const DEFAULT_L1_I_CACHE_LINE_COUNT: NonZeroUsize = {
let Some(v) = NonZeroUsize::new(256) else {
unreachable!();
};
v
};
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
let Some(v) = NonZeroUsize::new(8) else {
unreachable!();
@ -77,6 +86,8 @@ impl CpuConfig {
max_branches_per_fetch: Self::DEFAULT_MAX_BRANCHES_PER_FETCH,
max_fetches_in_flight: Self::DEFAULT_MAX_FETCHES_IN_FLIGHT,
log2_fetch_width_in_bytes: Self::DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES,
log2_cache_line_size_in_bytes: Self::DEFAULT_LOG2_CACHE_LINE_SIZE_IN_BYTES,
l1_i_cache_line_count: Self::DEFAULT_L1_I_CACHE_LINE_COUNT,
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
rob_size,
}
@ -141,6 +152,17 @@ impl CpuConfig {
.checked_shl(self.log2_fetch_width_in_bytes.into())
.expect("log2_fetch_width_in_bytes is too big")
}
pub fn cache_line_size_in_bytes(&self) -> usize {
1usize
.checked_shl(self.log2_cache_line_size_in_bytes.into())
.expect("log2_cache_line_size_in_bytes is too big")
}
pub fn l1_i_cache_size_in_bytes(&self) -> usize {
self.l1_i_cache_line_count
.get()
.checked_mul(self.cache_line_size_in_bytes())
.expect("L1 I-Cache is too big")
}
}
#[hdl(get(|c| c.fetch_width.get()))]
@ -161,6 +183,18 @@ pub type CpuConfigLog2FetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize
#[hdl(get(|c| c.fetch_width_in_bytes()))]
pub type CpuConfigFetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.log2_cache_line_size_in_bytes.into()))]
pub type CpuConfigLog2CacheLineSizeInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.cache_line_size_in_bytes()))]
pub type CpuConfigCacheLineSizeInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.l1_i_cache_line_count.get()))]
pub type CpuConfigL1ICacheLineCount<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.l1_i_cache_size_in_bytes()))]
pub type CpuConfigL1ICacheSizeInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.rob_size.get()))]
pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize;

81
crates/cpu/src/fetch.rs Normal file
View file

@ -0,0 +1,81 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::config::{
CpuConfig, CpuConfigCacheLineSizeInBytes, CpuConfigFetchWidthInBytes,
CpuConfigL1ICacheLineCount, CpuConfigMaxFetchesInFlight, PhantomConstCpuConfig,
};
use fayalite::{
int::UIntInRangeInclusiveType, memory::ReadWriteStruct, prelude::*,
util::ready_valid::ReadyValid,
};
#[hdl]
pub enum MemoryOperationKind {
Read,
Write,
}
#[hdl(no_static)]
pub struct MemoryOperationStart<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
pub kind: MemoryOperationKind,
pub addr: UInt<64>,
pub write_data: ArrayType<UInt<8>, CpuConfigFetchWidthInBytes<C>>,
pub config: C,
}
#[hdl]
pub enum MemoryOperationErrorKind {
Generic,
}
#[hdl]
pub enum MemoryOperationFinishKind {
Success(MemoryOperationKind),
Error(MemoryOperationErrorKind),
}
#[hdl(no_static)]
pub struct MemoryOperationFinish<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
pub kind: MemoryOperationFinishKind,
pub read_data: ArrayType<UInt<8>, CpuConfigFetchWidthInBytes<C>>,
pub config: C,
}
#[hdl(no_static)]
pub struct MemoryInterface<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> {
pub start: ReadyValid<MemoryOperationStart<C>>,
/// when both start and cancel are triggered in the same clock cycle, that means to cancel and then start a new memory operation
pub cancel: ReadyValid<UIntInRangeInclusiveType<ConstUsize<1>, CpuConfigMaxFetchesInFlight<C>>>,
#[hdl(flip)]
pub finish: ReadyValid<MemoryOperationFinish<C>>,
pub config: C,
}
#[hdl]
type CacheLine<C: PhantomConstGet<CpuConfig> + PhantomConstCpuConfig> =
ArrayType<UInt<8>, CpuConfigCacheLineSizeInBytes<C>>;
#[hdl_module]
pub fn l1_i_cache(config: PhantomConst<CpuConfig>) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let memory_interface: MemoryInterface<PhantomConst<CpuConfig>> =
m.output(MemoryInterface[config]);
#[hdl]
let mut i_cache =
memory_array(ArrayType[CacheLine[config]][CpuConfigL1ICacheLineCount[config]]);
#[hdl]
let ReadWriteStruct::<_, _> {
addr: port_addr,
en: port_en,
clk: port_clk,
rdata: port_rdata,
wmode: port_wmode,
wdata: port_wdata,
wmask: port_wmask,
} = i_cache.new_rw_port();
connect(port_clk, cd.clk);
todo!()
}

View file

@ -2,6 +2,7 @@
// See Notices.txt for copyright information
pub mod config;
pub mod decoder;
pub mod fetch;
pub mod instruction;
pub mod next_pc;
pub mod powerisa_instructions_xml;