Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
618862c7d9
WIP adding rename_execute_retire 2026-04-10 19:08:22 -07:00
8 changed files with 420 additions and 156 deletions

View file

@ -33,3 +33,6 @@ hex-literal.workspace = true
regex = "1.12.2"
sha2.workspace = true
which.workspace = true
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(todo)'] }

View file

@ -1,12 +1,6 @@
// 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 crate::{instruction::CONST_ZERO_UNIT_NUM, unit::UnitKind};
use fayalite::prelude::*;
use serde::{Deserialize, Serialize};
use std::num::NonZeroUsize;
@ -101,55 +95,14 @@ impl CpuConfig {
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()]
}
pub fn fetch_width_in_bytes(&self) -> usize {
1usize
.checked_shl(self.log2_fetch_width_in_bytes.into())
@ -188,6 +141,18 @@ impl CpuConfig {
}
}
#[hdl(get(|c| c.out_reg_num_width))]
pub type CpuConfigOutRegNumWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.unit_num_width()))]
pub type CpuConfigUnitNumWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.p_reg_num_width()))]
pub type CpuConfigPRegNumWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.non_const_unit_nums().len()))]
pub type CpuConfigUnitCount<C: PhantomConstGet<CpuConfig>> = DynSize;
#[hdl(get(|c| c.fetch_width.get()))]
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
config::{CpuConfig, CpuConfigOutRegNumWidth, CpuConfigUnitNumWidth, PhantomConstCpuConfig},
register::{PRegFlags, PRegFlagsViewTrait, PRegValue, ViewUnused},
unit::UnitMOp,
util::{Rotate, range_u32_len},
@ -2595,19 +2596,21 @@ impl<DestReg: Type, SrcRegWidth: Size> MoveRegMOp<DestReg, SrcRegWidth> {
}
}
#[hdl(cmp_eq)]
#[hdl(cmp_eq, no_static)]
/// there may be more than one unit of a given kind, so UnitNum is not the same as UnitKind.
/// zero is used for built-in constants, such as the zero register
pub struct UnitNum<Width: Size> {
pub adj_value: UIntType<Width>,
pub struct UnitNum<C: PhantomConstGet<CpuConfig>> {
pub adj_value: UIntType<CpuConfigUnitNumWidth<C>>,
pub config: C,
}
impl<Width: Size> UnitNum<Width> {
impl<C: PhantomConstCpuConfig> UnitNum<C> {
#[hdl]
pub fn const_zero(self) -> Expr<Self> {
#[hdl]
UnitNum {
adj_value: CONST_ZERO_UNIT_NUM.cast_to(self.adj_value),
config: self.config,
}
}
#[hdl]
@ -2615,6 +2618,7 @@ impl<Width: Size> UnitNum<Width> {
#[hdl]
UnitNum {
adj_value: (index + 1).cast_to(self.adj_value),
config: self.config,
}
}
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
@ -2622,7 +2626,9 @@ impl<Width: Size> UnitNum<Width> {
expr.ty().from_index(index).adj_value.cmp_eq(expr.adj_value)
}
#[hdl]
pub fn as_index(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<UIntType<Width>>> {
pub fn as_index(
expr: impl ToExpr<Type = Self>,
) -> Expr<HdlOption<UIntType<CpuConfigUnitNumWidth<C>>>> {
let expr = expr.to_expr();
#[hdl]
let unit_index = wire(HdlOption[expr.ty().adj_value]);
@ -2640,19 +2646,20 @@ impl<Width: Size> UnitNum<Width> {
pub const CONST_ZERO_UNIT_NUM: usize = 0;
#[hdl(cmp_eq)]
pub struct UnitOutRegNum<Width: Size> {
pub value: UIntType<Width>,
#[hdl(cmp_eq, no_static)]
pub struct UnitOutRegNum<C: PhantomConstGet<CpuConfig>> {
pub value: UIntType<CpuConfigOutRegNumWidth<C>>,
pub config: C,
}
#[hdl(cmp_eq)]
#[hdl(cmp_eq, no_static)]
/// Physical Register Number -- registers in the CPU's backend
pub struct PRegNum<UnitNumWidth: Size, OutRegNumWidth: Size> {
pub unit_num: UnitNum<UnitNumWidth>,
pub unit_out_reg: UnitOutRegNum<OutRegNumWidth>,
pub struct PRegNum<C: PhantomConstGet<CpuConfig>> {
pub unit_num: UnitNum<C>,
pub unit_out_reg: UnitOutRegNum<C>,
}
impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWidth> {
impl<C: PhantomConstCpuConfig> PRegNum<C> {
#[hdl]
pub fn const_zero(self) -> Expr<Self> {
#[hdl]
@ -2661,6 +2668,7 @@ impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWi
unit_out_reg: #[hdl]
UnitOutRegNum {
value: 0u8.cast_to(self.unit_out_reg.value),
config: self.unit_out_reg.config,
},
}
}

View file

@ -7,7 +7,9 @@ pub mod instruction;
pub mod main_memory_and_io;
pub mod next_pc;
pub mod powerisa_instructions_xml;
#[cfg(todo)]
pub mod reg_alloc;
pub mod register;
pub mod rename_execute_retire;
pub mod unit;
pub mod util;

View file

@ -0,0 +1,295 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
config::{
CpuConfig, CpuConfigFetchWidth, CpuConfigPRegNumWidth, CpuConfigRobSize,
PhantomConstCpuConfig,
},
instruction::{MOp, MOpRegNum, PRegNum, RenamedMOp},
next_pc::{RetireToNextPcInterfaceInner, SimValueDefault},
util::array_vec::ArrayVec,
};
use fayalite::{
int::UIntInRangeInclusiveType, prelude::*, ty::OpaqueSimValue, util::ready_valid::ReadyValid,
};
use std::collections::VecDeque;
#[hdl]
/// A &micro;Op along with the state needed for this instance of the &micro;Op.
pub struct MOpInstance<MOp> {
pub fetch_block_id: UInt<8>,
pub id: UInt<12>,
pub pc: UInt<64>,
/// initialized to 0 by decoder, overwritten by `next_pc()`
pub predicted_next_pc: UInt<64>,
pub size_in_bytes: UInt<4>,
/// `true` if this &micro;Op is the first &micro;Op in the ISA-level instruction.
/// In general, a single &micro;Op can't be cancelled by itself,
/// it needs to be cancelled along with all other &micro;Ops that
/// come from the same ISA-level instruction.
pub is_first_mop_in_insn: Bool,
pub mop: MOp,
}
#[hdl(no_static)]
/// TODO: merge with [`crate::next_pc::PostDecodeOutputInterface`]
pub struct PostDecodeOutputInterface<C: PhantomConstGet<CpuConfig>> {
pub insns: ArrayVec<MOpInstance<MOp>, CpuConfigFetchWidth<C>>,
#[hdl(flip)]
pub ready: UIntInRangeInclusiveType<ConstUsize<0>, CpuConfigFetchWidth<C>>,
/// tells the rename/execute/retire circuit to cancel all non-retired instructions
pub cancel: ReadyValid<()>,
pub config: C,
}
#[hdl(no_static)]
/// handles updating speculative branch predictor state (e.g. branch histories)
/// when instructions retire, as well as updating state when a
/// branch instruction is mis-speculated.
pub struct RetireToNextPcInterface<C: PhantomConstGet<CpuConfig>> {
pub inner: ReadyValid<RetireToNextPcInterfaceInner<C>>,
/// only for debugging
pub next_insns: HdlOption<ArrayVec<MOpInstance<MOp>, CpuConfigRobSize<C>>>,
}
fn zeroed<T: Type>(ty: T) -> SimValue<T> {
SimValue::from_opaque(
ty,
OpaqueSimValue::from_bits(UInt::new(ty.canonical().bit_width()).zero()),
)
}
impl<C: PhantomConstCpuConfig> SimValueDefault for RenameExecuteRetireDebugState<C> {
fn sim_value_default(self) -> SimValue<Self> {
zeroed(self)
}
}
#[derive(Debug, Clone)]
struct RenameTable<C: PhantomConstCpuConfig> {
entries: Box<[SimValue<PRegNum<C>>; 1 << MOpRegNum::WIDTH]>,
config: C,
}
impl<C: PhantomConstCpuConfig> RenameTable<C> {
fn new(config: C) -> Self {
Self {
entries: vec![PRegNum[config].const_zero().into_sim_value(); 1 << MOpRegNum::WIDTH]
.try_into()
.expect("size is known to match"),
config,
}
}
fn to_debug_state(&self) -> SimValue<Array<PRegNum<C>, { 1 << MOpRegNum::WIDTH }>> {
self.entries
.to_sim_value_with_type(Array[PRegNum[self.config]][ConstUsize])
}
}
#[hdl(no_static)]
struct RobEntryDebugState<C: PhantomConstGet<CpuConfig>> {
mop: MOpInstance<RenamedMOp<PRegNum<C>, CpuConfigPRegNumWidth<C>>>,
config: C,
}
impl<C: PhantomConstCpuConfig> SimValueDefault for RobEntryDebugState<C> {
fn sim_value_default(self) -> SimValue<Self> {
zeroed(self)
}
}
#[derive(Debug)]
struct RobEntry<C: PhantomConstCpuConfig> {
mop: SimValue<MOpInstance<RenamedMOp<PRegNum<C>, CpuConfigPRegNumWidth<C>>>>,
config: C,
}
#[hdl]
struct OrigMOpQueueEntryDebugState {
mop: MOpInstance<MOp>,
/// number of renamed &micro;Ops that this non-renamed &micro;Op corresponds to
renamed_mop_count: UInt<8>,
}
#[derive(Debug)]
struct OrigMOpQueueEntry {
mop: SimValue<MOpInstance<MOp>>,
/// number of renamed &micro;Ops that this non-renamed &micro;Op corresponds to
renamed_mop_count: u8,
}
#[hdl(no_static)]
pub struct RenameExecuteRetireDebugState<C: PhantomConstGet<CpuConfig>> {
rename_table: Array<PRegNum<C>, { 1 << MOpRegNum::WIDTH }>,
retire_rename_table: Array<PRegNum<C>, { 1 << MOpRegNum::WIDTH }>,
rob: ArrayVec<RobEntryDebugState<C>, CpuConfigRobSize<C>>,
orig_mop_queue: ArrayVec<OrigMOpQueueEntryDebugState, CpuConfigRobSize<C>>,
cancelling: Bool,
}
#[derive(Debug)]
struct RenameExecuteRetireState<C: PhantomConstCpuConfig> {
rename_table: RenameTable<C>,
retire_rename_table: RenameTable<C>,
rob: VecDeque<RobEntry<C>>,
orig_mop_queue: VecDeque<OrigMOpQueueEntry>,
cancelling: bool,
config: C,
}
impl<C: PhantomConstCpuConfig> RenameExecuteRetireState<C> {
fn new(config: C) -> Self {
let rename_table = RenameTable::new(config);
Self {
rename_table: rename_table.clone(),
retire_rename_table: rename_table,
rob: VecDeque::with_capacity(CpuConfigRobSize[config]),
orig_mop_queue: VecDeque::with_capacity(CpuConfigRobSize[config]),
cancelling: false,
config,
}
}
#[hdl]
async fn write_for_debug(
&self,
sim: &mut ExternModuleSimulationState,
state_for_debug: Expr<RenameExecuteRetireDebugState<C>>,
) {
let Self {
ref rename_table,
ref retire_rename_table,
ref rob,
ref orig_mop_queue,
cancelling,
config,
} = *self;
sim.write(
state_for_debug,
#[hdl(sim)]
RenameExecuteRetireDebugState::<_> {
rename_table: rename_table.to_debug_state(),
retire_rename_table: retire_rename_table.to_debug_state(),
rob: state_for_debug
.ty()
.rob
.from_iter_sim(
zeroed(RobEntryDebugState[config]),
rob.iter().map(|entry| {
let RobEntry { mop, config: _ } = entry;
#[hdl(sim)]
RobEntryDebugState::<_> { mop, config }
}),
)
.expect("known to fit"),
orig_mop_queue: state_for_debug
.ty()
.orig_mop_queue
.from_iter_sim(
zeroed(OrigMOpQueueEntryDebugState),
orig_mop_queue.iter().map(|entry| {
let OrigMOpQueueEntry {
mop,
renamed_mop_count,
} = entry;
#[hdl(sim)]
OrigMOpQueueEntryDebugState {
mop,
renamed_mop_count,
}
}),
)
.expect("known to fit"),
cancelling,
},
)
.await;
}
#[hdl]
async fn write_to_next_pc_next_insns(
&self,
sim: &mut ExternModuleSimulationState,
next_insns: Expr<HdlOption<ArrayVec<MOpInstance<MOp>, CpuConfigRobSize<C>>>>,
) {
sim.write(
next_insns,
#[hdl(sim)]
(next_insns.ty()).HdlSome(
next_insns
.ty()
.HdlSome
.from_iter_sim(
zeroed(MOpInstance[MOp]),
self.orig_mop_queue.iter().map(|entry| &entry.mop),
)
.expect("known to fit"),
),
)
.await;
}
}
#[hdl]
async fn rename_execute_retire_run(
mut sim: ExternModuleSimulationState,
cd: Expr<ClockDomain>,
from_post_decode: Expr<PostDecodeOutputInterface<PhantomConst<CpuConfig>>>,
to_next_pc: Expr<RetireToNextPcInterface<PhantomConst<CpuConfig>>>,
state_for_debug: Expr<RenameExecuteRetireDebugState<PhantomConst<CpuConfig>>>,
config: PhantomConst<CpuConfig>,
) {
let mut state = RenameExecuteRetireState::new(config);
loop {
state
.write_to_next_pc_next_insns(&mut sim, to_next_pc.next_insns)
.await;
state.write_for_debug(&mut sim, state_for_debug).await;
sim.wait_for_clock_edge(cd.clk).await;
todo!("step state based on I/O");
}
}
#[hdl_module(extern)]
pub fn rename_execute_retire(config: PhantomConst<CpuConfig>) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let from_post_decode: PostDecodeOutputInterface<PhantomConst<CpuConfig>> =
m.input(PostDecodeOutputInterface[config]);
#[hdl]
let to_next_pc: RetireToNextPcInterface<PhantomConst<CpuConfig>> =
m.output(RetireToNextPcInterface[config]);
#[hdl]
let state_for_debug: RenameExecuteRetireDebugState<PhantomConst<CpuConfig>> =
m.output(RenameExecuteRetireDebugState[config]);
m.register_clock_for_past(cd.clk);
m.extern_module_simulation_fn(
(cd, from_post_decode, to_next_pc, state_for_debug, config),
|(cd, from_post_decode, to_next_pc, state_for_debug, config), mut sim| async move {
sim.write(state_for_debug, state_for_debug.ty().sim_value_default())
.await;
sim.resettable(
cd,
|mut sim: ExternModuleSimulationState| async move {
sim.write(from_post_decode.ready, 0usize).await;
sim.write(from_post_decode.cancel.ready, false).await;
sim.write(to_next_pc.inner.data, to_next_pc.ty().inner.data.HdlNone())
.await;
sim.write(to_next_pc.next_insns, to_next_pc.ty().next_insns.HdlNone())
.await;
},
|sim, ()| {
rename_execute_retire_run(
sim,
cd,
from_post_decode,
to_next_pc,
state_for_debug,
config,
)
},
)
.await;
},
);
}

View file

@ -2,7 +2,7 @@
// See Notices.txt for copyright information
use crate::{
config::CpuConfig,
config::{CpuConfig, PhantomConstCpuConfig},
instruction::{
AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait,
MOpVariantVisitOps, MOpVariantVisitor, MOpVisitVariants, RenamedMOp, UnitOutRegNum,
@ -48,7 +48,7 @@ macro_rules! all_units {
}
impl $UnitKind {
pub fn unit(self, config: &CpuConfig, unit_index: usize) -> DynUnit {
pub fn unit(self, config: PhantomConst<CpuConfig>, unit_index: usize) -> DynUnit {
match self {
$($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
}
@ -277,9 +277,9 @@ pub struct UnitResultCompleted<ExtraOut> {
pub extra_out: ExtraOut,
}
#[hdl(cmp_eq)]
pub struct UnitOutputWrite<OutRegNumWidth: Size> {
pub which: UnitOutRegNum<OutRegNumWidth>,
#[hdl(cmp_eq, no_static)]
pub struct UnitOutputWrite<C: PhantomConstGet<CpuConfig>> {
pub which: UnitOutRegNum<C>,
pub value: PRegValue,
}
@ -300,21 +300,21 @@ impl<ExtraOut: Type> UnitResult<ExtraOut> {
}
}
#[hdl]
pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> {
pub which: UnitOutRegNum<OutRegNumWidth>,
#[hdl(no_static)]
pub struct UnitOutput<C: PhantomConstGet<CpuConfig>, ExtraOut> {
pub which: UnitOutRegNum<C>,
pub result: UnitResult<ExtraOut>,
}
impl<OutRegNumWidth: Size, ExtraOut: Type> UnitOutput<OutRegNumWidth, ExtraOut> {
impl<C: PhantomConstCpuConfig, ExtraOut: Type> UnitOutput<C, ExtraOut> {
pub fn extra_out_ty(self) -> ExtraOut {
self.result.extra_out_ty()
}
}
#[hdl(cmp_eq)]
pub struct UnitCancelInput<OutRegNumWidth: Size> {
pub which: UnitOutRegNum<OutRegNumWidth>,
#[hdl(cmp_eq, no_static)]
pub struct UnitCancelInput<C: PhantomConstGet<CpuConfig>> {
pub which: UnitOutRegNum<C>,
}
pub trait UnitTrait:
@ -332,7 +332,7 @@ pub trait UnitTrait:
fn extract_mop(
&self,
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>>;
fn module(&self) -> Interned<Module<Self::Type>>;
@ -340,7 +340,7 @@ pub trait UnitTrait:
fn unit_to_reg_alloc(
&self,
this: Expr<Self::Type>,
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>>;
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>>;
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
@ -390,7 +390,7 @@ impl UnitTrait for DynUnit {
fn extract_mop(
&self,
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>> {
self.unit.extract_mop(mop)
}
@ -402,7 +402,7 @@ impl UnitTrait for DynUnit {
fn unit_to_reg_alloc(
&self,
this: Expr<Self::Type>,
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
self.unit.unit_to_reg_alloc(this)
}
@ -445,7 +445,7 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
fn extract_mop(
&self,
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>> {
Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop)))
}
@ -457,7 +457,7 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
fn unit_to_reg_alloc(
&self,
this: Expr<Self::Type>,
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
Expr::from_bundle(Expr::as_bundle(
self.0.unit_to_reg_alloc(Expr::from_bundle(this)),
))

View file

@ -19,16 +19,13 @@ use crate::{
},
};
use fayalite::{
intern::{Intern, Interned},
module::wire_with_loc,
prelude::*,
util::ready_valid::ReadyValid,
intern::Interned, module::wire_with_loc, prelude::*, util::ready_valid::ReadyValid,
};
use std::{collections::HashMap, ops::RangeTo};
#[hdl]
fn add_sub<SrcCount: KnownSize>(
mop: Expr<AddSubMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
mop: Expr<AddSubMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, SrcCount>>,
pc: Expr<UInt<64>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
@ -245,7 +242,7 @@ fn add_sub<SrcCount: KnownSize>(
#[hdl]
fn logical_flags(
mop: Expr<LogicalFlagsMOp<UnitOutRegNum<DynSize>, DynSize>>,
mop: Expr<LogicalFlagsMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
@ -259,7 +256,7 @@ fn logical_flags(
#[hdl]
fn logical(
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<2>>>,
mop: Expr<LogicalMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, ConstUsize<2>>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
@ -273,7 +270,7 @@ fn logical(
#[hdl]
fn logical_i(
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize, ConstUsize<1>>>,
mop: Expr<LogicalMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, ConstUsize<1>>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
@ -287,7 +284,7 @@ fn logical_i(
#[hdl]
fn shift_rotate(
mop: Expr<ShiftRotateMOp<UnitOutRegNum<DynSize>, DynSize>>,
mop: Expr<ShiftRotateMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
@ -301,7 +298,7 @@ fn shift_rotate(
#[hdl]
fn compare<SrcCount: KnownSize>(
mop: Expr<CompareMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
mop: Expr<CompareMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, SrcCount>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
@ -315,7 +312,7 @@ fn compare<SrcCount: KnownSize>(
#[hdl]
fn branch<SrcCount: KnownSize>(
mop: Expr<BranchMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
mop: Expr<BranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize, SrcCount>>,
pc: Expr<UInt<64>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
@ -330,7 +327,7 @@ fn branch<SrcCount: KnownSize>(
#[hdl]
fn read_special(
mop: Expr<ReadSpecialMOp<UnitOutRegNum<DynSize>, DynSize>>,
mop: Expr<ReadSpecialMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
pc: Expr<UInt<64>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
@ -344,20 +341,18 @@ fn read_special(
}
#[hdl_module]
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
pub fn alu_branch(config: PhantomConst<CpuConfig>, unit_index: usize) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let unit_to_reg_alloc: UnitToRegAlloc<
AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>,
PhantomConst<CpuConfig>,
AluBranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>,
(),
DynSize,
DynSize,
DynSize,
> = m.output(config.unit_to_reg_alloc(
AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()],
(),
));
> = m.output(
UnitToRegAlloc[config][AluBranchMOp[UnitOutRegNum[config]][config.get().p_reg_num_width()]]
[()],
);
#[hdl]
let global_state: GlobalState = m.input();
@ -375,10 +370,11 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
#[hdl]
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
#[hdl]
let ExecuteStart::<_> {
let ExecuteStart::<_, _> {
mop,
pc,
src_values,
config: _,
} = execute_start;
#[hdl]
match mop {
@ -580,14 +576,14 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct AluBranch {
config: Interned<CpuConfig>,
config: PhantomConst<CpuConfig>,
module: Interned<Module<alu_branch>>,
}
impl AluBranch {
pub fn new(config: &CpuConfig, unit_index: usize) -> Self {
pub fn new(config: PhantomConst<CpuConfig>, unit_index: usize) -> Self {
Self {
config: config.intern(),
config,
module: alu_branch(config, unit_index),
}
}
@ -596,7 +592,7 @@ impl AluBranch {
impl UnitTrait for AluBranch {
type Type = alu_branch;
type ExtraOut = ();
type MOp = AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>;
type MOp = AluBranchMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>;
fn ty(&self) -> Self::Type {
self.module.io_ty()
@ -616,7 +612,7 @@ impl UnitTrait for AluBranch {
fn extract_mop(
&self,
mop: Expr<RenamedMOp<UnitOutRegNum<DynSize>, DynSize>>,
mop: Expr<RenamedMOp<UnitOutRegNum<PhantomConst<CpuConfig>>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>> {
UnitMOp::alu_branch_mop(mop)
}
@ -628,7 +624,7 @@ impl UnitTrait for AluBranch {
fn unit_to_reg_alloc(
&self,
this: Expr<Self::Type>,
) -> Expr<UnitToRegAlloc<Self::MOp, Self::ExtraOut, DynSize, DynSize, DynSize>> {
) -> Expr<UnitToRegAlloc<PhantomConst<CpuConfig>, Self::MOp, Self::ExtraOut>> {
this.unit_to_reg_alloc
}

View file

@ -2,7 +2,7 @@
// See Notices.txt for copyright information
use crate::{
config::CpuConfig,
config::{CpuConfig, CpuConfigUnitCount, PhantomConstCpuConfig},
instruction::{COMMON_MOP_SRC_LEN, MOpTrait, PRegNum, UnitNum, UnitOutRegNum},
register::PRegValue,
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
@ -15,13 +15,11 @@ use fayalite::{
ty::StaticType,
util::ready_valid::ReadyValid,
};
use std::marker::PhantomData;
#[hdl]
pub struct UnitForwardingInfo<UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size> {
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<OutRegNumWidth>>, UnitCount>,
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<OutRegNumWidth>>, UnitCount>,
pub _phantom: PhantomData<UnitNumWidth>,
#[hdl(no_static)]
pub struct UnitForwardingInfo<C: PhantomConstGet<CpuConfig>> {
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<C>>, CpuConfigUnitCount<C>>,
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<C>>, CpuConfigUnitCount<C>>,
}
#[hdl]
@ -30,26 +28,18 @@ pub struct UnitInput<MOp: Type> {
pub pc: UInt<64>,
}
#[hdl]
pub struct UnitToRegAlloc<
MOp: Type,
ExtraOut: Type,
UnitNumWidth: Size,
OutRegNumWidth: Size,
UnitCount: Size,
> {
#[hdl(no_static)]
pub struct UnitToRegAlloc<C: PhantomConstGet<CpuConfig>, MOp: Type, ExtraOut: Type> {
#[hdl(flip)]
pub unit_forwarding_info: UnitForwardingInfo<UnitNumWidth, OutRegNumWidth, UnitCount>,
pub unit_forwarding_info: UnitForwardingInfo<C>,
#[hdl(flip)]
pub input: ReadyValid<UnitInput<MOp>>,
#[hdl(flip)]
pub cancel_input: HdlOption<UnitCancelInput<OutRegNumWidth>>,
pub output: HdlOption<UnitOutput<OutRegNumWidth, ExtraOut>>,
pub cancel_input: HdlOption<UnitCancelInput<C>>,
pub output: HdlOption<UnitOutput<C, ExtraOut>>,
}
impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCount: Size>
UnitToRegAlloc<MOp, ExtraOut, UnitNumWidth, OutRegNumWidth, UnitCount>
{
impl<C: PhantomConstCpuConfig, MOp: Type, ExtraOut: Type> UnitToRegAlloc<C, MOp, ExtraOut> {
pub fn mop_ty(self) -> MOp {
self.input.data.HdlSome.mop
}
@ -58,16 +48,20 @@ impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCo
}
}
#[hdl]
pub struct ExecuteStart<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> {
#[hdl(no_static)]
pub struct ExecuteStart<
C: PhantomConstGet<CpuConfig>,
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<C>>,
> {
pub mop: MOp,
pub pc: UInt<64>,
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
pub config: C,
}
#[hdl]
pub struct ExecuteEnd<OutRegNumWidth: Size, ExtraOut> {
pub unit_output: UnitOutput<OutRegNumWidth, ExtraOut>,
#[hdl(no_static)]
pub struct ExecuteEnd<C: PhantomConstGet<CpuConfig>, ExtraOut> {
pub unit_output: UnitOutput<C, ExtraOut>,
}
#[hdl]
@ -240,10 +234,10 @@ impl InFlightOpsSummary<DynSize> {
#[hdl_module]
pub fn unit_base<
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>, SrcRegWidth = DynSize>,
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<PhantomConst<CpuConfig>>, SrcRegWidth = DynSize>,
ExtraOut: Type,
>(
config: &CpuConfig,
config: PhantomConst<CpuConfig>,
unit_index: usize,
mop_ty: MOp,
extra_out_ty: ExtraOut,
@ -251,17 +245,18 @@ pub fn unit_base<
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let unit_to_reg_alloc: UnitToRegAlloc<MOp, ExtraOut, DynSize, DynSize, DynSize> =
m.output(config.unit_to_reg_alloc(mop_ty, extra_out_ty));
let unit_to_reg_alloc: UnitToRegAlloc<PhantomConst<CpuConfig>, MOp, ExtraOut> =
m.output(UnitToRegAlloc[config][mop_ty][extra_out_ty]);
#[hdl]
let execute_start: ReadyValid<ExecuteStart<MOp>> = m.output(ReadyValid[ExecuteStart[mop_ty]]);
let execute_start: ReadyValid<ExecuteStart<PhantomConst<CpuConfig>, MOp>> =
m.output(ReadyValid[ExecuteStart[config][mop_ty]]);
#[hdl]
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
let execute_end: HdlOption<ExecuteEnd<PhantomConst<CpuConfig>, ExtraOut>> =
m.input(HdlOption[ExecuteEnd[config][extra_out_ty]]);
connect(execute_start.data, execute_start.ty().data.HdlNone());
let max_in_flight = config.unit_max_in_flight(unit_index).get();
let max_in_flight = config.get().unit_max_in_flight(unit_index).get();
let in_flight_op_ty = InFlightOp[mop_ty];
#[hdl]
let in_flight_ops = reg_builder()
@ -279,16 +274,15 @@ pub fn unit_base<
);
#[hdl]
let UnitForwardingInfo::<_, _, _> {
let UnitForwardingInfo::<_> {
unit_output_writes,
unit_reg_frees,
_phantom: _,
} = unit_to_reg_alloc.unit_forwarding_info;
#[hdl]
let read_src_regs = wire(mop_ty.src_regs_ty());
connect(
read_src_regs,
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
);
#[hdl]
let read_src_values = wire();
@ -297,7 +291,7 @@ pub fn unit_base<
let input_src_regs = wire(mop_ty.src_regs_ty());
connect(
input_src_regs,
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
);
#[hdl]
let input_src_regs_valid = wire();
@ -309,7 +303,7 @@ pub fn unit_base<
Bool,
SourceLocation::caller(),
);
mem.depth(1 << config.out_reg_num_width);
mem.depth(1 << config.get().out_reg_num_width);
mem
})
.collect();
@ -319,11 +313,11 @@ pub fn unit_base<
PRegValue,
SourceLocation::caller(),
);
unit_output_regs.depth(1 << config.out_reg_num_width);
unit_output_regs.depth(1 << config.get().out_reg_num_width);
for src_index in 0..COMMON_MOP_SRC_LEN {
let read_port = unit_output_regs.new_read_port();
let p_reg_num = read_src_regs[src_index].cast_bits_to(config.p_reg_num());
let p_reg_num = read_src_regs[src_index].cast_bits_to(PRegNum[config]);
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
connect(read_port.en, false);
connect(read_port.clk, cd.clk);
@ -336,7 +330,7 @@ pub fn unit_base<
for src_index in 0..COMMON_MOP_SRC_LEN {
let read_port = unit_output_regs_valid[unit_index].new_read_port();
let p_reg_num = input_src_regs[src_index].cast_bits_to(config.p_reg_num());
let p_reg_num = input_src_regs[src_index].cast_bits_to(PRegNum[config]);
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
connect(read_port.en, false);
connect(read_port.clk, cd.clk);
@ -367,8 +361,8 @@ pub fn unit_base<
connect_any(ready_write_port.addr, unit_output_write.which.value);
connect(ready_write_port.en, true);
let p_reg_num = #[hdl]
PRegNum::<_, _> {
unit_num: config.unit_num().from_index(unit_index),
PRegNum::<_> {
unit_num: UnitNum[config].from_index(unit_index),
unit_out_reg: unit_output_write.which,
};
for src_index in 0..COMMON_MOP_SRC_LEN {
@ -399,10 +393,11 @@ pub fn unit_base<
execute_start.data,
HdlSome(
#[hdl]
ExecuteStart::<_> {
ExecuteStart::<_, _> {
mop: in_flight_op.mop,
pc: in_flight_op.pc,
src_values: read_src_values,
config,
},
),
);
@ -425,7 +420,7 @@ pub fn unit_base<
let input_mop_src_regs = wire(mop_ty.src_regs_ty());
connect(
input_mop_src_regs,
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
);
MOp::connect_src_regs(mop, input_mop_src_regs);
let src_ready_flags = wire_with_loc(
@ -497,7 +492,7 @@ pub fn unit_base<
);
connect(
src_regs,
repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize),
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
);
MOp::connect_src_regs(mop, src_regs);
@ -521,8 +516,8 @@ pub fn unit_base<
value: _,
} = unit_output_write;
let p_reg_num = #[hdl]
PRegNum::<_, _> {
unit_num: config.unit_num().from_index(unit_index),
PRegNum::<_> {
unit_num: UnitNum[config].from_index(unit_index),
unit_out_reg,
};
for src_index in 0..COMMON_MOP_SRC_LEN {