mod bpred;
mod cache;
mod coherence;
pub mod ddr5;
mod defaults;
mod general;
mod memory;
mod pipeline;
mod prefetch;
mod system;
pub use bpred::{
BranchPredictorKind, GehlConfig, IttageConfig, LocalGehlConfig, LoopConfig, MAX_GEHL_TABLES,
MAX_LOCAL_HISTORIES, MAX_TAGE_BANKS, MAX_TAGE_HISTORY, PerceptronConfig, ScConfig,
ScConfigError, TageAllocation, TageBanking, TageConfig, TageHashing, TageHistoryMode,
TageUpdate, TournamentConfig,
};
pub use cache::{
CacheConfig, CacheHierarchyConfig, InclusionPolicy, PrefetcherKind, ReplacementPolicyKind,
};
pub use coherence::{
CoherenceConfig, CoherenceProtocolConfig, HomeAgentConfig, InterconnectConfig,
};
pub use general::{Console, GeneralConfig};
pub use memory::{AddressMappingKind, MemoryConfig, MemoryControllerKind};
pub use pipeline::{
BackendKind, FuConfig, MAX_VECTOR_MEM_WIDTH, MemDepPredictorKind, PipelineConfig,
StoreSetConfig, VecStoreForwarding,
};
pub use prefetch::{LoadPrefetcherConfig, PageBoundary, StorePrefetcherConfig};
pub use system::SystemConfig;
use crate::isa::encoding::zicboz::CBOZ_BLOCK_SIZE;
use serde::Deserialize;
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
pub general: GeneralConfig,
pub system: SystemConfig,
pub memory: MemoryConfig,
pub cache: CacheHierarchyConfig,
#[serde(default)]
pub coherence: CoherenceConfig,
pub pipeline: PipelineConfig,
#[serde(default)]
pub isa: crate::isa::config::IsaConfig,
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum ConfigError {
#[error(
"inclusion_policy Exclusive is not supported with hart_count > 1: the L2 must be inclusive of its L1s to answer snoops"
)]
ExclusiveWithCoherence,
#[error("hart_count {0} exceeds the 64 cores a coherence sharer set can hold")]
TooManyHarts(usize),
#[error("simple_bandwidth_gib_s must be a positive number")]
SimpleBandwidth,
#[error("misa_override sets V, but vlen {vlen} / elen {elen} is not the full V extension")]
VWithoutFullVector {
vlen: usize,
elen: usize,
},
#[error(
"cache {level} has {line_bytes}-byte lines, smaller than the {CBOZ_BLOCK_SIZE}-byte cache-block-operation block"
)]
LineSmallerThanCacheBlock {
level: &'static str,
line_bytes: usize,
},
#[error("vector_mem_width {0} must be a power of two from 8 to {MAX_VECTOR_MEM_WIDTH} bytes")]
VectorMemWidth(usize),
#[error("tage num_banks {0} exceeds {MAX_TAGE_BANKS}")]
TageBanks(usize),
#[error(
"tage banking needs one enabled flag per bank, a first_long_bank among them and non-zero factors"
)]
TageBanking,
#[error("tage bimodal_entries {entries} must be a power of two of at least 2^{share_log}")]
TageBimodal {
entries: usize,
share_log: u32,
},
#[error("tage path_history_bits {0} must be in 1..=31")]
TagePathBits(u32),
#[error("tage history length {0} exceeds {MAX_TAGE_HISTORY}")]
TageHistoryLength(usize),
#[error(
"tage useful_bits {useful_bits} must be in 1..=8 and max_allocations {max_allocations} at least 1"
)]
TageAllocation {
useful_bits: u32,
max_allocations: usize,
},
#[error("tage use_alt_counters {counters} must be at least 1 and use_alt_bits {bits} in 2..=8")]
TageUseAlt {
counters: usize,
bits: u32,
},
#[error("sc: {0}")]
StatCorrector(#[from] ScConfigError),
#[error("btb_size {size} / btb_ways {ways} gives {sets} sets, which is not a power of two")]
BtbSets {
size: usize,
ways: usize,
sets: usize,
},
}
impl Config {
#[must_use]
pub fn misa(&self) -> crate::isa::misa::Misa {
self.pipeline
.misa_override
.unwrap_or_else(|| crate::isa::misa::Misa::rv64imafdc(self.implements_full_v()))
}
const fn implements_full_v(&self) -> bool {
self.isa.vector.elen == 64
}
pub fn validate(&self) -> Result<(), ConfigError> {
let harts = self.system.hart_count.max(1);
if harts > 64 {
return Err(ConfigError::TooManyHarts(harts));
}
if harts > 1 && self.cache.inclusion_policy == InclusionPolicy::Exclusive {
return Err(ConfigError::ExclusiveWithCoherence);
}
let ways = self.pipeline.btb_ways.max(1);
let sets = (self.pipeline.btb_size / ways).max(1);
if !sets.is_power_of_two() {
return Err(ConfigError::BtbSets { size: self.pipeline.btb_size, ways, sets });
}
if self.misa().has_v() && !self.implements_full_v() {
return Err(ConfigError::VWithoutFullVector {
vlen: self.pipeline.vlen.bits(),
elen: self.isa.vector.elen,
});
}
if self.memory.simple_bandwidth_bytes_per_second().is_none() {
return Err(ConfigError::SimpleBandwidth);
}
let levels = [
("l1_d", &self.cache.l1_d),
("l1_i", &self.cache.l1_i),
("l2", &self.cache.l2),
("l3", &self.cache.l3),
];
for (level, cache) in levels {
let line_bytes = cache.line_bytes;
if cache.enabled && line_bytes != 0 && (line_bytes as u64) < CBOZ_BLOCK_SIZE {
return Err(ConfigError::LineSmallerThanCacheBlock { level, line_bytes });
}
}
let tage = &self.pipeline.tage;
if tage.use_alt_counters == 0 || !(2..=8).contains(&tage.use_alt_bits) {
return Err(ConfigError::TageUseAlt {
counters: tage.use_alt_counters,
bits: tage.use_alt_bits,
});
}
if tage.num_banks > MAX_TAGE_BANKS {
return Err(ConfigError::TageBanks(tage.num_banks));
}
if let Some(banking) = &tage.banking {
let fits = banking.enabled.len() == tage.num_banks
&& banking.first_long_bank < tage.num_banks
&& banking.short_factor > 0
&& banking.long_factor > 0;
if !fits {
return Err(ConfigError::TageBanking);
}
}
let bimodal = tage.bimodal_entries();
if !bimodal.is_power_of_two() || (bimodal >> tage.bimodal_hysteresis_share_log) == 0 {
return Err(ConfigError::TageBimodal {
entries: bimodal,
share_log: tage.bimodal_hysteresis_share_log,
});
}
if !(1..=31).contains(&tage.path_history_bits) {
return Err(ConfigError::TagePathBits(tage.path_history_bits));
}
if let Some(&length) =
tage.history_lengths.iter().find(|&&length| length > MAX_TAGE_HISTORY)
{
return Err(ConfigError::TageHistoryLength(length));
}
if !(1..=8).contains(&tage.useful_bits) || tage.max_allocations == 0 {
return Err(ConfigError::TageAllocation {
useful_bits: tage.useful_bits,
max_allocations: tage.max_allocations,
});
}
self.pipeline.sc.validate()?;
let vector_mem_width = self.pipeline.vector_mem_width_bytes();
if !vector_mem_width.is_power_of_two()
|| !(8..=MAX_VECTOR_MEM_WIDTH).contains(&vector_mem_width)
{
return Err(ConfigError::VectorMemWidth(vector_mem_width));
}
Ok(())
}
}