WIP adding unit input/output values and insn tracking
All checks were successful
/ deps (push) Successful in 16s
/ test (push) Successful in 25m56s

This commit is contained in:
Jacob Lifshay 2025-02-13 20:55:43 -08:00
parent d7818d889c
commit 2b7e7e4946
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
9 changed files with 11507 additions and 6399 deletions

View file

@ -2,17 +2,36 @@
// See Notices.txt for copyright information // See Notices.txt for copyright information
use crate::{ use crate::{
instruction::{PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM}, instruction::{PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM},
unit::{UnitKind, UnitMOp}, unit::{unit_base::UnitForwardingInfo, UnitCancelInput, UnitKind, UnitMOp, UnitOutputWrite},
}; };
use fayalite::prelude::*; use fayalite::prelude::*;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
#[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)] #[derive(Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive] #[non_exhaustive]
pub struct CpuConfig { pub struct CpuConfig {
pub unit_kinds: Vec<UnitKind>, pub units: Vec<UnitConfig>,
pub out_reg_num_width: usize, pub out_reg_num_width: usize,
pub fetch_width: NonZeroUsize, pub fetch_width: NonZeroUsize,
/// default value for [`UnitConfig::max_in_flight`]
pub default_unit_max_in_flight: NonZeroUsize,
} }
impl CpuConfig { impl CpuConfig {
@ -23,15 +42,22 @@ impl CpuConfig {
}; };
v v
}; };
pub fn new(unit_kinds: Vec<UnitKind>) -> Self { pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
let Some(v) = NonZeroUsize::new(8) else {
unreachable!();
};
v
};
pub fn new(units: Vec<UnitConfig>) -> Self {
Self { Self {
unit_kinds, units,
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH, out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
fetch_width: Self::DEFAULT_FETCH_WIDTH, fetch_width: Self::DEFAULT_FETCH_WIDTH,
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
} }
} }
pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> { pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> {
(CONST_ZERO_UNIT_NUM + 1)..(self.unit_kinds.len() + 1) (CONST_ZERO_UNIT_NUM + 1)..(self.units.len() + 1)
} }
pub fn unit_num_width(&self) -> usize { pub fn unit_num_width(&self) -> usize {
UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width() UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width()
@ -51,4 +77,22 @@ impl CpuConfig {
pub fn unit_mop_in_unit(&self) -> UnitMOp<UnitOutRegNum<DynSize>, DynSize> { pub fn unit_mop_in_unit(&self) -> UnitMOp<UnitOutRegNum<DynSize>, DynSize> {
UnitMOp[self.unit_out_reg_num()][self.p_reg_num_width()] UnitMOp[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)
}
} }

View file

@ -12,6 +12,10 @@ pub trait MOpTrait: Type {
type SrcRegWidth: Size; type SrcRegWidth: Size;
fn dest_reg_ty(self) -> Self::DestReg; fn dest_reg_ty(self) -> Self::DestReg;
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg>; fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg>;
fn for_each_src_reg(
input: impl ToExpr<Type = Self>,
f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize),
);
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self, self,
new_dest_reg: NewDestReg, new_dest_reg: NewDestReg,
@ -63,6 +67,16 @@ impl<T: CommonMOpTrait> MOpTrait for T {
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> { fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> {
T::common_mop(input).dest T::common_mop(input).dest
} }
fn for_each_src_reg(
input: impl ToExpr<Type = Self>,
f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize),
) {
let input = input.to_expr();
let common = T::common_mop(input);
for index in 0..T::SrcCount::VALUE {
f(common.src[index], index);
}
}
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self, self,
new_dest_reg: NewDestReg, new_dest_reg: NewDestReg,
@ -396,6 +410,17 @@ macro_rules! mop_enum {
} }
dest_reg dest_reg
} }
#[hdl]
fn for_each_src_reg(
input: impl ToExpr<Type = Self>,
f: &mut impl FnMut(Expr<UIntType<Self::SrcRegWidth>>, usize),
) {
#[hdl]
match input {
$MOp::<_, _>::$FirstVariant(v) => MOpTrait::for_each_src_reg(v, f),
$($MOp::<_, _>::$Variant(v) => MOpTrait::for_each_src_reg(v, f),)*
}
}
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>( fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self, self,
new_dest_reg: NewDestReg, new_dest_reg: NewDestReg,

View file

@ -6,7 +6,7 @@ use crate::{
MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum, MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum,
COMMON_MOP_SRC_LEN, COMMON_MOP_SRC_LEN,
}, },
unit::{TrapData, UnitTrait}, unit::{unit_base::UnitForwardingInfo, TrapData, UnitTrait},
util::tree_reduce::tree_reduce_with_state, util::tree_reduce::tree_reduce_with_state,
}; };
use fayalite::{ use fayalite::{
@ -17,6 +17,7 @@ use fayalite::{
}; };
use std::{ use std::{
collections::{BTreeMap, VecDeque}, collections::{BTreeMap, VecDeque},
marker::PhantomData,
num::NonZeroUsize, num::NonZeroUsize,
}; };
@ -79,8 +80,7 @@ pub fn reg_alloc(config: &CpuConfig) {
} }
#[hdl] #[hdl]
let available_units = let available_units = wire(Array[Array[Bool][config.units.len()]][config.fetch_width.get()]);
wire(Array[Array[Bool][config.unit_kinds.len()]][config.fetch_width.get()]);
#[hdl] #[hdl]
let selected_unit_indexes = let selected_unit_indexes =
wire(Array[HdlOption[UInt[config.unit_num_width()]]][config.fetch_width.get()]); wire(Array[HdlOption[UInt[config.unit_num_width()]]][config.fetch_width.get()]);
@ -95,7 +95,7 @@ pub fn reg_alloc(config: &CpuConfig) {
); );
connect( connect(
available_units[fetch_index], available_units[fetch_index],
repeat(false, config.unit_kinds.len()), repeat(false, config.units.len()),
); );
connect( connect(
renamed_mops[fetch_index], renamed_mops[fetch_index],
@ -116,7 +116,6 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(wire.addr, MOpRegNum::const_zero()); connect(wire.addr, MOpRegNum::const_zero());
connect(wire.data, config.p_reg_num().const_zero()); connect(wire.data, config.p_reg_num().const_zero());
for (&rename_table_name, mem) in &mut rename_table_mems { for (&rename_table_name, mem) in &mut rename_table_mems {
let table_name = rename_table_name.as_str();
let read_port = mem.new_read_port(); let read_port = mem.new_read_port();
connect(read_port.clk, cd.clk); connect(read_port.clk, cd.clk);
connect_any(read_port.addr, 0u8); connect_any(read_port.addr, 0u8);
@ -242,7 +241,7 @@ pub fn reg_alloc(config: &CpuConfig) {
connect( connect(
selected_unit_indexes[fetch_index], selected_unit_indexes[fetch_index],
tree_reduce_with_state( tree_reduce_with_state(
0..config.unit_kinds.len(), 0..config.units.len(),
&mut 0usize, &mut 0usize,
|_state, unit_index| { |_state, unit_index| {
let selected_unit_index_leaf = wire_with_loc( let selected_unit_index_leaf = wire_with_loc(
@ -304,15 +303,15 @@ pub fn reg_alloc(config: &CpuConfig) {
config.fetch_width.get(), config.fetch_width.get(),
), ),
); );
for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() { for (unit_index, unit_config) in config.units.iter().enumerate() {
let dyn_unit = unit_kind.unit(config); let dyn_unit = unit_config.kind.unit(config, unit_index);
let unit = instance_with_loc( let unit = instance_with_loc(
&format!("unit_{unit_index}"), &format!("unit_{unit_index}"),
dyn_unit.make_module(), dyn_unit.module(),
SourceLocation::caller(), SourceLocation::caller(),
); );
connect(dyn_unit.cd(unit), cd); connect(dyn_unit.cd(unit), cd);
let unit_input = dyn_unit.input(unit); let unit_input_insn = dyn_unit.input_insn(unit);
// TODO: handle assigning multiple instructions to a unit at a time // TODO: handle assigning multiple instructions to a unit at a time
let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap(); let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap();
// TODO: handle retiring multiple instructions from a unit at a time // TODO: handle retiring multiple instructions from a unit at a time
@ -333,7 +332,10 @@ pub fn reg_alloc(config: &CpuConfig) {
HdlOption[UInt[config.out_reg_num_width]].uninit(), // FIXME: just for debugging HdlOption[UInt[config.out_reg_num_width]].uninit(), // FIXME: just for debugging
); );
connect(unit_free_regs_tracker.alloc_out[0].ready, false); connect(unit_free_regs_tracker.alloc_out[0].ready, false);
connect(unit_input.data, Expr::ty(unit_input).data.HdlNone()); connect(
unit_input_insn.data,
Expr::ty(unit_input_insn).data.HdlNone(),
);
for fetch_index in 0..config.fetch_width.get() { for fetch_index in 0..config.fetch_width.get() {
#[hdl] #[hdl]
if let HdlNone = unit_free_regs_tracker.alloc_out[0].data { if let HdlNone = unit_free_regs_tracker.alloc_out[0].data {
@ -341,7 +343,7 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(available_units[fetch_index][unit_index], false); connect(available_units[fetch_index][unit_index], false);
} }
#[hdl] #[hdl]
if !unit_input.ready { if !unit_input_insn.ready {
// must come after to override connects in loops above // must come after to override connects in loops above
connect(available_units[fetch_index][unit_index], false); connect(available_units[fetch_index][unit_index], false);
} }
@ -354,11 +356,11 @@ pub fn reg_alloc(config: &CpuConfig) {
if let HdlSome(renamed_mop) = if let HdlSome(renamed_mop) =
HdlOption::and_then(renamed_mops[fetch_index], |v| dyn_unit.extract_mop(v)) HdlOption::and_then(renamed_mops[fetch_index], |v| dyn_unit.extract_mop(v))
{ {
connect(unit_input.data, HdlSome(renamed_mop)); connect(unit_input_insn.data, HdlSome(renamed_mop));
} else { } else {
connect( connect(
unit_input.data, unit_input_insn.data,
HdlSome(Expr::ty(unit_input).data.HdlSome.uninit()), HdlSome(Expr::ty(unit_input_insn).data.HdlSome.uninit()),
); );
// FIXME: add hdl_assert(cd.clk, false.to_expr(), ""); // FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
} }
@ -383,5 +385,23 @@ pub fn reg_alloc(config: &CpuConfig) {
} }
} }
} }
// TODO: connect outputs to other units
connect(
dyn_unit.unit_forwarding_info(unit),
#[hdl]
UnitForwardingInfo::<_, _, _> {
unit_output_writes: repeat(
HdlOption[config.unit_output_write()].HdlNone(),
config.units.len(),
),
_phantom: PhantomData,
},
);
connect(dyn_unit.output(unit).ready, false);
// TODO: handle cancellation
connect(
dyn_unit.cancel_input(unit).data,
HdlOption[config.unit_cancel_input()].HdlNone(),
);
} }
} }

View file

@ -148,3 +148,14 @@ pub struct PRegValue {
pub int_fp: UInt<64>, pub int_fp: UInt<64>,
pub flags: PRegFlags, pub flags: PRegFlags,
} }
impl PRegValue {
#[hdl]
pub fn zeroed() -> Expr<Self> {
#[hdl]
PRegValue {
int_fp: 0u64,
flags: PRegFlags::zeroed(),
}
}
}

View file

@ -4,9 +4,10 @@
use crate::{ use crate::{
config::CpuConfig, config::CpuConfig,
instruction::{ instruction::{
mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, PRegNum, UnitOutRegNum, mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum,
}, },
register::PRegValue, register::PRegValue,
unit::unit_base::UnitForwardingInfo,
}; };
use fayalite::{ use fayalite::{
bundle::{Bundle, BundleType}, bundle::{Bundle, BundleType},
@ -16,6 +17,7 @@ use fayalite::{
}; };
pub mod alu_branch; pub mod alu_branch;
pub mod unit_base;
macro_rules! all_units { macro_rules! all_units {
( (
@ -42,9 +44,9 @@ macro_rules! all_units {
} }
impl $UnitKind { impl $UnitKind {
pub fn unit(self, config: &CpuConfig) -> DynUnit { pub fn unit(self, config: &CpuConfig, unit_index: usize) -> DynUnit {
match self { match self {
$($UnitKind::$Unit => $create_dyn_unit_fn(config),)* $($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)*
} }
} }
} }
@ -111,11 +113,11 @@ macro_rules! all_units {
#[hdl] #[hdl]
pub fn available_units_for_kind(&self, unit_kind: impl ToExpr<Type = $HdlUnitKind>) -> Expr<Array<Bool>> { pub fn available_units_for_kind(&self, unit_kind: impl ToExpr<Type = $HdlUnitKind>) -> Expr<Array<Bool>> {
#[hdl] #[hdl]
let available_units_for_kind = wire(Array[Bool][self.unit_kinds.len()]); let available_units_for_kind = wire(Array[Bool][self.units.len()]);
#[hdl] #[hdl]
match unit_kind { match unit_kind {
$($HdlUnitKind::$Unit => for (index, &unit_kind) in self.unit_kinds.iter().enumerate() { $($HdlUnitKind::$Unit => for (index, unit) in self.units.iter().enumerate() {
connect(available_units_for_kind[index], unit_kind == $UnitKind::$Unit); connect(available_units_for_kind[index], unit.kind == $UnitKind::$Unit);
})* })*
} }
available_units_for_kind available_units_for_kind
@ -129,13 +131,13 @@ all_units! {
#[unit_kind = UnitKind] #[unit_kind = UnitKind]
#[hdl] #[hdl]
pub enum UnitMOp<DestReg: Type, SrcRegWidth: Size> { pub enum UnitMOp<DestReg: Type, SrcRegWidth: Size> {
#[create_dyn_unit_fn = |config| alu_branch::AluBranch::new(config).to_dyn()] #[create_dyn_unit_fn = |config, unit_index| alu_branch::AluBranch::new(config, unit_index).to_dyn()]
#[extract = alu_branch_mop] #[extract = alu_branch_mop]
AluBranch(AluBranchMOp<DestReg, SrcRegWidth>), AluBranch(AluBranchMOp<DestReg, SrcRegWidth>),
#[create_dyn_unit_fn = |config| todo!()] #[create_dyn_unit_fn = |config, unit_index| todo!()]
#[extract = l2_register_file_mop] #[extract = l2_register_file_mop]
L2RegisterFile(L2RegisterFileMOp<DestReg, SrcRegWidth>), L2RegisterFile(L2RegisterFileMOp<DestReg, SrcRegWidth>),
#[create_dyn_unit_fn = |config| todo!()] #[create_dyn_unit_fn = |config, unit_index| todo!()]
#[extract = load_store_mop] #[extract = load_store_mop]
LoadStore(LoadStoreMOp<DestReg, SrcRegWidth>), LoadStore(LoadStoreMOp<DestReg, SrcRegWidth>),
} }
@ -147,6 +149,12 @@ pub struct UnitResultCompleted<ExtraOut> {
pub extra_out: ExtraOut, pub extra_out: ExtraOut,
} }
#[hdl]
pub struct UnitOutputWrite<OutRegNumWidth: Size> {
pub which: UnitOutRegNum<OutRegNumWidth>,
pub value: PRegValue,
}
#[hdl] #[hdl]
pub struct TrapData { pub struct TrapData {
// TODO // TODO
@ -159,14 +167,14 @@ pub enum UnitResult<ExtraOut> {
} }
#[hdl] #[hdl]
pub struct UnitOutput<UnitNumWidth: Size, OutRegNumWidth: Size, ExtraOut> { pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> {
pub which: PRegNum<UnitNumWidth, OutRegNumWidth>, pub which: UnitOutRegNum<OutRegNumWidth>,
pub result: UnitResult<ExtraOut>, pub result: UnitResult<ExtraOut>,
} }
#[hdl] #[hdl]
pub struct UnitCancelInput<UnitNumWidth: Size, OutRegNumWidth: Size> { pub struct UnitCancelInput<OutRegNumWidth: Size> {
pub which: PRegNum<UnitNumWidth, OutRegNumWidth>, pub which: UnitOutRegNum<OutRegNumWidth>,
} }
pub trait UnitTrait: pub trait UnitTrait:
@ -187,18 +195,22 @@ pub trait UnitTrait:
mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>, mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>>; ) -> Expr<HdlOption<Self::MOp>>;
fn make_module(&self) -> Interned<Module<Self::Type>>; fn module(&self) -> Interned<Module<Self::Type>>;
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>>; fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>>;
fn cancel_input( fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>>;
fn unit_forwarding_info(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>>; ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>>;
fn output( fn output(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>; ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>>;
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>; fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
fn to_dyn(&self) -> DynUnit; fn to_dyn(&self) -> DynUnit;
@ -250,25 +262,29 @@ impl UnitTrait for DynUnit {
self.unit.extract_mop(mop) self.unit.extract_mop(mop)
} }
fn make_module(&self) -> Interned<Module<Self::Type>> { fn module(&self) -> Interned<Module<Self::Type>> {
self.unit.make_module() self.unit.module()
} }
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
self.unit.input(this) self.unit.input_insn(this)
} }
fn cancel_input( fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> {
self.unit.cancel_input(this)
}
fn unit_forwarding_info(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> { ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
self.unit.cancel_input(this) self.unit.unit_forwarding_info(this)
} }
fn output( fn output(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> { ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> {
self.unit.output(this) self.unit.output(this)
} }
@ -312,25 +328,29 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop))) Expr::from_enum(Expr::as_enum(self.0.extract_mop(mop)))
} }
fn make_module(&self) -> Interned<Module<Self::Type>> { fn module(&self) -> Interned<Module<Self::Type>> {
self.0.make_module().canonical().intern_sized() self.0.module().canonical().intern_sized()
} }
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
Expr::from_bundle(Expr::as_bundle(self.0.input(Expr::from_bundle(this)))) Expr::from_bundle(Expr::as_bundle(self.0.input_insn(Expr::from_bundle(this))))
} }
fn cancel_input( fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> {
self.0.cancel_input(Expr::from_bundle(this))
}
fn unit_forwarding_info(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> { ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
self.0.cancel_input(Expr::from_bundle(this)) self.0.unit_forwarding_info(Expr::from_bundle(this))
} }
fn output( fn output(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> { ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> {
Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this)))) Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this))))
} }

View file

@ -4,7 +4,10 @@
use crate::{ use crate::{
config::CpuConfig, config::CpuConfig,
instruction::{AluBranchMOp, UnitOutRegNum}, instruction::{AluBranchMOp, UnitOutRegNum},
unit::{DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitMOp, UnitOutput, UnitTrait}, unit::{
unit_base::{unit_base, UnitForwardingInfo},
DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitMOp, UnitOutput, UnitTrait,
},
}; };
use fayalite::{ use fayalite::{
intern::{Intern, Interned}, intern::{Intern, Interned},
@ -13,14 +16,34 @@ use fayalite::{
}; };
#[hdl_module] #[hdl_module]
pub fn alu_branch(config: &CpuConfig) { pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
#[hdl] #[hdl]
let cd: ClockDomain = m.input(); let cd: ClockDomain = m.input();
#[hdl] #[hdl]
let input: ReadyValid<AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>> = let input_insn: ReadyValid<AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>> =
m.input(ReadyValid[AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()]]); m.input(ReadyValid[AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()]]);
#[hdl]
let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> =
m.input(config.unit_forwarding_info());
#[hdl]
let cancel_input: ReadyValid<UnitCancelInput<DynSize>> =
m.input(ReadyValid[config.unit_cancel_input()]);
#[hdl]
let output: ReadyValid<UnitOutput<DynSize, ()>> =
m.output(ReadyValid[UnitOutput[config.out_reg_num_width][()]]);
#[hdl]
let unit_base = instance(unit_base(
config,
unit_index,
Expr::ty(input_insn).data.HdlSome,
));
connect(unit_base.input_insn, input_insn);
connect(unit_base.cd, cd);
connect(unit_base.unit_forwarding_info, unit_forwarding_info);
connect(unit_base.cancel_input, cancel_input);
// TODO: finish // TODO: finish
connect(input.ready, true); connect(unit_base.ready_mop.ready, true);
connect(output.data, Expr::ty(output.data).HdlNone());
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -30,10 +53,10 @@ pub struct AluBranch {
} }
impl AluBranch { impl AluBranch {
pub fn new(config: &CpuConfig) -> Self { pub fn new(config: &CpuConfig, unit_index: usize) -> Self {
Self { Self {
config: config.intern(), config: config.intern(),
module: alu_branch(config), module: alu_branch(config, unit_index),
} }
} }
} }
@ -52,7 +75,7 @@ impl UnitTrait for AluBranch {
} }
fn mop_ty(&self) -> Self::MOp { fn mop_ty(&self) -> Self::MOp {
self.module.io_ty().input.data.HdlSome self.module.io_ty().input_insn.data.HdlSome
} }
fn unit_kind(&self) -> UnitKind { fn unit_kind(&self) -> UnitKind {
@ -66,26 +89,30 @@ impl UnitTrait for AluBranch {
UnitMOp::alu_branch_mop(mop) UnitMOp::alu_branch_mop(mop)
} }
fn make_module(&self) -> Interned<Module<Self::Type>> { fn module(&self) -> Interned<Module<Self::Type>> {
self.module self.module
} }
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> { fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
this.input this.input_insn
} }
fn cancel_input( fn cancel_input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<UnitCancelInput<DynSize>>> {
this.cancel_input
}
fn unit_forwarding_info(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> { ) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
todo!() this.unit_forwarding_info
} }
fn output( fn output(
&self, &self,
this: Expr<Self::Type>, this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> { ) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> {
todo!() this.output
} }
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> { fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {

View file

@ -0,0 +1,130 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
config::CpuConfig,
instruction::{MOpTrait, UnitOutRegNum, COMMON_MOP_SRC_LEN},
register::PRegValue,
unit::{UnitCancelInput, UnitOutputWrite},
util::tree_reduce::tree_reduce,
};
use fayalite::{module::wire_with_loc, prelude::*, 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 _phantom: PhantomData<UnitNumWidth>,
}
#[hdl]
pub struct ReadyMOp<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> {
pub mop: MOp,
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
}
#[hdl]
struct InFlightOp<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> {
pub mop: MOp,
pub src_values: Array<HdlOption<PRegValue>, { COMMON_MOP_SRC_LEN }>,
}
#[hdl_module]
pub fn unit_base<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>>(
config: &CpuConfig,
unit_index: usize,
mop_ty: MOp,
) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> =
m.input(config.unit_forwarding_info());
#[hdl]
let input_insn: ReadyValid<MOp> = m.input(ReadyValid[mop_ty]);
connect(input_insn.ready, false);
#[hdl]
let cancel_input: ReadyValid<UnitCancelInput<DynSize>> =
m.input(ReadyValid[config.unit_cancel_input()]);
connect(cancel_input.ready, true);
#[hdl]
let ready_mop: ReadyValid<ReadyMOp<MOp>> = m.output(ReadyValid[ReadyMOp[mop_ty]]);
connect(ready_mop.data, Expr::ty(ready_mop.data).HdlNone());
let max_in_flight = config.unit_max_in_flight(unit_index).get();
#[hdl]
let in_flight_ops = reg_builder().clock_domain(cd).reset(repeat(
HdlOption[InFlightOp[mop_ty]].HdlNone(),
max_in_flight,
));
let in_flight_op_index_ty = UInt::range(0..max_in_flight);
#[hdl]
let input_index = wire(HdlOption[in_flight_op_index_ty]);
connect(
input_index,
tree_reduce(
(0..max_in_flight).map(|i| -> Expr<HdlOption<UInt>> {
HdlOption::map(in_flight_ops[i], |_| i.cast_to(in_flight_op_index_ty))
}),
HdlOption::or,
)
.expect("max_in_flight is known to be non-zero"),
);
#[hdl]
let input_in_flight_op = wire(HdlOption[InFlightOp[mop_ty]]);
connect(input_in_flight_op, Expr::ty(input_in_flight_op).HdlNone());
#[hdl]
if let HdlSome(mop) = ReadyValid::firing_data(input_insn) {
let src_values = wire_with_loc(
"input_in_flight_op_src_values",
SourceLocation::caller(),
StaticType::TYPE,
);
connect(
src_values,
[HdlSome(PRegValue::zeroed()); COMMON_MOP_SRC_LEN],
);
MOp::for_each_src_reg(mop, &mut |src_reg, src_index| {
#[hdl]
if config
.p_reg_num()
.const_zero()
.cast_to_bits()
.cmp_ne(src_reg)
{
connect(src_values[src_index], HdlNone());
}
});
connect(
input_in_flight_op,
HdlSome(
#[hdl]
InFlightOp::<_> { mop, src_values },
),
);
}
for in_flight_op_index in 0..max_in_flight {
#[hdl]
if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] {
#[hdl]
if let HdlSome(cancel_input) = ReadyValid::firing_data(cancel_input) {
#[hdl]
let UnitCancelInput::<_> { which } = cancel_input;
#[hdl]
if which.value.cmp_eq(MOp::dest_reg(in_flight_op.mop).value) {
// TODO: if it needs extra time to cancel (e.g. still in pipeline), handle that here
connect(
in_flight_ops[in_flight_op_index],
HdlOption[InFlightOp[mop_ty]].HdlNone(),
);
}
}
// TODO: finish
} else if let HdlSome(input_index) = input_index {
connect(input_insn.ready, true);
#[hdl]
if input_index.cmp_eq(in_flight_op_index) {
connect(in_flight_ops[in_flight_op_index], input_in_flight_op);
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff