forked from libre-chip/cpu
120 lines
4.1 KiB
Rust
120 lines
4.1 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
use crate::{
|
|
instruction::{CONST_ZERO_UNIT_NUM, MOpTrait, PRegNum, RenamedMOp, UnitNum, UnitOutRegNum},
|
|
unit::{
|
|
UnitCancelInput, UnitKind, UnitOutputWrite,
|
|
unit_base::{UnitForwardingInfo, UnitToRegAlloc},
|
|
},
|
|
};
|
|
use fayalite::prelude::*;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::num::NonZeroUsize;
|
|
|
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct UnitConfig {
|
|
pub kind: UnitKind,
|
|
/// max number of instructions that can be in-flight through this unit at any point in time.
|
|
pub max_in_flight: Option<NonZeroUsize>,
|
|
}
|
|
|
|
impl UnitConfig {
|
|
pub fn new(kind: UnitKind) -> Self {
|
|
Self {
|
|
kind,
|
|
max_in_flight: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
|
#[non_exhaustive]
|
|
pub struct CpuConfig {
|
|
pub units: Vec<UnitConfig>,
|
|
pub out_reg_num_width: usize,
|
|
pub fetch_width: NonZeroUsize,
|
|
/// default value for [`UnitConfig::max_in_flight`]
|
|
pub default_unit_max_in_flight: NonZeroUsize,
|
|
pub rob_size: NonZeroUsize,
|
|
}
|
|
|
|
impl CpuConfig {
|
|
pub const DEFAULT_OUT_REG_NUM_WIDTH: usize = 4;
|
|
pub const DEFAULT_FETCH_WIDTH: NonZeroUsize = {
|
|
let Some(v) = NonZeroUsize::new(1) else {
|
|
unreachable!();
|
|
};
|
|
v
|
|
};
|
|
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
|
let Some(v) = NonZeroUsize::new(8) else {
|
|
unreachable!();
|
|
};
|
|
v
|
|
};
|
|
pub fn new(units: Vec<UnitConfig>, rob_size: NonZeroUsize) -> Self {
|
|
Self {
|
|
units,
|
|
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
|
fetch_width: Self::DEFAULT_FETCH_WIDTH,
|
|
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
|
rob_size,
|
|
}
|
|
}
|
|
pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> {
|
|
(CONST_ZERO_UNIT_NUM + 1)..(self.units.len() + 1)
|
|
}
|
|
pub fn unit_num_width(&self) -> usize {
|
|
UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width()
|
|
}
|
|
pub fn unit_num(&self) -> UnitNum<DynSize> {
|
|
UnitNum[self.unit_num_width()]
|
|
}
|
|
pub fn unit_out_reg_num(&self) -> UnitOutRegNum<DynSize> {
|
|
UnitOutRegNum[self.out_reg_num_width]
|
|
}
|
|
pub fn p_reg_num(&self) -> PRegNum<DynSize, DynSize> {
|
|
PRegNum[self.unit_num_width()][self.out_reg_num_width]
|
|
}
|
|
pub fn p_reg_num_width(&self) -> usize {
|
|
self.unit_num_width() + self.out_reg_num_width
|
|
}
|
|
pub fn renamed_mop_in_unit(&self) -> RenamedMOp<UnitOutRegNum<DynSize>, DynSize> {
|
|
RenamedMOp[self.unit_out_reg_num()][self.p_reg_num_width()]
|
|
}
|
|
pub fn unit_output_write(&self) -> UnitOutputWrite<DynSize> {
|
|
UnitOutputWrite[self.out_reg_num_width]
|
|
}
|
|
pub fn unit_output_writes(&self) -> Array<HdlOption<UnitOutputWrite<DynSize>>> {
|
|
Array[HdlOption[self.unit_output_write()]][self.non_const_unit_nums().len()]
|
|
}
|
|
pub fn unit_cancel_input(&self) -> UnitCancelInput<DynSize> {
|
|
UnitCancelInput[self.out_reg_num_width]
|
|
}
|
|
pub fn unit_forwarding_info(&self) -> UnitForwardingInfo<DynSize, DynSize, DynSize> {
|
|
UnitForwardingInfo[self.unit_num_width()][self.out_reg_num_width]
|
|
[self.non_const_unit_nums().len()]
|
|
}
|
|
pub fn unit_max_in_flight(&self, unit_index: usize) -> NonZeroUsize {
|
|
self.units[unit_index]
|
|
.max_in_flight
|
|
.unwrap_or(self.default_unit_max_in_flight)
|
|
}
|
|
pub fn unit_to_reg_alloc<
|
|
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>,
|
|
ExtraOut: Type,
|
|
>(
|
|
&self,
|
|
mop_ty: MOp,
|
|
extra_out_ty: ExtraOut,
|
|
) -> UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> {
|
|
assert_eq!(
|
|
mop_ty.dest_reg_ty(),
|
|
self.unit_out_reg_num(),
|
|
"inconsistent types",
|
|
);
|
|
UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width]
|
|
[self.non_const_unit_nums().len()]
|
|
}
|
|
}
|