diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index cf2fd08..e2145d0 100644 --- a/crates/cpu/src/config.rs +++ b/crates/cpu/src/config.rs @@ -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> = DynSize #[hdl(get(|c| c.fetch_width_in_bytes()))] pub type CpuConfigFetchWidthInBytes> = DynSize; +#[hdl(get(|c| c.log2_cache_line_size_in_bytes.into()))] +pub type CpuConfigLog2CacheLineSizeInBytes> = DynSize; + +#[hdl(get(|c| c.cache_line_size_in_bytes()))] +pub type CpuConfigCacheLineSizeInBytes> = DynSize; + +#[hdl(get(|c| c.l1_i_cache_line_count.get()))] +pub type CpuConfigL1ICacheLineCount> = DynSize; + +#[hdl(get(|c| c.l1_i_cache_size_in_bytes()))] +pub type CpuConfigL1ICacheSizeInBytes> = DynSize; + #[hdl(get(|c| c.rob_size.get()))] pub type CpuConfigRobSize> = DynSize; diff --git a/crates/cpu/src/fetch.rs b/crates/cpu/src/fetch.rs new file mode 100644 index 0000000..fbae344 --- /dev/null +++ b/crates/cpu/src/fetch.rs @@ -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 + PhantomConstCpuConfig> { + pub kind: MemoryOperationKind, + pub addr: UInt<64>, + pub write_data: ArrayType, CpuConfigFetchWidthInBytes>, + pub config: C, +} + +#[hdl] +pub enum MemoryOperationErrorKind { + Generic, +} + +#[hdl] +pub enum MemoryOperationFinishKind { + Success(MemoryOperationKind), + Error(MemoryOperationErrorKind), +} + +#[hdl(no_static)] +pub struct MemoryOperationFinish + PhantomConstCpuConfig> { + pub kind: MemoryOperationFinishKind, + pub read_data: ArrayType, CpuConfigFetchWidthInBytes>, + pub config: C, +} + +#[hdl(no_static)] +pub struct MemoryInterface + PhantomConstCpuConfig> { + pub start: ReadyValid>, + /// 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, CpuConfigMaxFetchesInFlight>>, + #[hdl(flip)] + pub finish: ReadyValid>, + pub config: C, +} + +#[hdl] +type CacheLine + PhantomConstCpuConfig> = + ArrayType, CpuConfigCacheLineSizeInBytes>; + +#[hdl_module] +pub fn l1_i_cache(config: PhantomConst) { + #[hdl] + let cd: ClockDomain = m.input(); + #[hdl] + let memory_interface: MemoryInterface> = + 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!() +} diff --git a/crates/cpu/src/lib.rs b/crates/cpu/src/lib.rs index 7992ec5..62936de 100644 --- a/crates/cpu/src/lib.rs +++ b/crates/cpu/src/lib.rs @@ -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;