WIP adding unit input/output values and insn tracking
This commit is contained in:
parent
d7818d889c
commit
2b7e7e4946
|
@ -2,17 +2,36 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{
|
||||
instruction::{PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM},
|
||||
unit::{UnitKind, UnitMOp},
|
||||
unit::{unit_base::UnitForwardingInfo, UnitCancelInput, UnitKind, UnitMOp, UnitOutputWrite},
|
||||
};
|
||||
use fayalite::prelude::*;
|
||||
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)]
|
||||
#[non_exhaustive]
|
||||
pub struct CpuConfig {
|
||||
pub unit_kinds: Vec<UnitKind>,
|
||||
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,
|
||||
}
|
||||
|
||||
impl CpuConfig {
|
||||
|
@ -23,15 +42,22 @@ impl CpuConfig {
|
|||
};
|
||||
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 {
|
||||
unit_kinds,
|
||||
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,
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@ pub trait MOpTrait: Type {
|
|||
type SrcRegWidth: Size;
|
||||
fn dest_reg_ty(self) -> 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>(
|
||||
self,
|
||||
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> {
|
||||
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>(
|
||||
self,
|
||||
new_dest_reg: NewDestReg,
|
||||
|
@ -396,6 +410,17 @@ macro_rules! mop_enum {
|
|||
}
|
||||
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>(
|
||||
self,
|
||||
new_dest_reg: NewDestReg,
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum,
|
||||
COMMON_MOP_SRC_LEN,
|
||||
},
|
||||
unit::{TrapData, UnitTrait},
|
||||
unit::{unit_base::UnitForwardingInfo, TrapData, UnitTrait},
|
||||
util::tree_reduce::tree_reduce_with_state,
|
||||
};
|
||||
use fayalite::{
|
||||
|
@ -17,6 +17,7 @@ use fayalite::{
|
|||
};
|
||||
use std::{
|
||||
collections::{BTreeMap, VecDeque},
|
||||
marker::PhantomData,
|
||||
num::NonZeroUsize,
|
||||
};
|
||||
|
||||
|
@ -79,8 +80,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
}
|
||||
|
||||
#[hdl]
|
||||
let available_units =
|
||||
wire(Array[Array[Bool][config.unit_kinds.len()]][config.fetch_width.get()]);
|
||||
let available_units = wire(Array[Array[Bool][config.units.len()]][config.fetch_width.get()]);
|
||||
#[hdl]
|
||||
let selected_unit_indexes =
|
||||
wire(Array[HdlOption[UInt[config.unit_num_width()]]][config.fetch_width.get()]);
|
||||
|
@ -95,7 +95,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
);
|
||||
connect(
|
||||
available_units[fetch_index],
|
||||
repeat(false, config.unit_kinds.len()),
|
||||
repeat(false, config.units.len()),
|
||||
);
|
||||
connect(
|
||||
renamed_mops[fetch_index],
|
||||
|
@ -116,7 +116,6 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
connect(wire.addr, MOpRegNum::const_zero());
|
||||
connect(wire.data, config.p_reg_num().const_zero());
|
||||
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();
|
||||
connect(read_port.clk, cd.clk);
|
||||
connect_any(read_port.addr, 0u8);
|
||||
|
@ -242,7 +241,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
connect(
|
||||
selected_unit_indexes[fetch_index],
|
||||
tree_reduce_with_state(
|
||||
0..config.unit_kinds.len(),
|
||||
0..config.units.len(),
|
||||
&mut 0usize,
|
||||
|_state, unit_index| {
|
||||
let selected_unit_index_leaf = wire_with_loc(
|
||||
|
@ -304,15 +303,15 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
config.fetch_width.get(),
|
||||
),
|
||||
);
|
||||
for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() {
|
||||
let dyn_unit = unit_kind.unit(config);
|
||||
for (unit_index, unit_config) in config.units.iter().enumerate() {
|
||||
let dyn_unit = unit_config.kind.unit(config, unit_index);
|
||||
let unit = instance_with_loc(
|
||||
&format!("unit_{unit_index}"),
|
||||
dyn_unit.make_module(),
|
||||
dyn_unit.module(),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
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
|
||||
let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap();
|
||||
// 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
|
||||
);
|
||||
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() {
|
||||
#[hdl]
|
||||
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);
|
||||
}
|
||||
#[hdl]
|
||||
if !unit_input.ready {
|
||||
if !unit_input_insn.ready {
|
||||
// must come after to override connects in loops above
|
||||
connect(available_units[fetch_index][unit_index], false);
|
||||
}
|
||||
|
@ -354,11 +356,11 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
if let HdlSome(renamed_mop) =
|
||||
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 {
|
||||
connect(
|
||||
unit_input.data,
|
||||
HdlSome(Expr::ty(unit_input).data.HdlSome.uninit()),
|
||||
unit_input_insn.data,
|
||||
HdlSome(Expr::ty(unit_input_insn).data.HdlSome.uninit()),
|
||||
);
|
||||
// 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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,3 +148,14 @@ pub struct PRegValue {
|
|||
pub int_fp: UInt<64>,
|
||||
pub flags: PRegFlags,
|
||||
}
|
||||
|
||||
impl PRegValue {
|
||||
#[hdl]
|
||||
pub fn zeroed() -> Expr<Self> {
|
||||
#[hdl]
|
||||
PRegValue {
|
||||
int_fp: 0u64,
|
||||
flags: PRegFlags::zeroed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, PRegNum, UnitOutRegNum,
|
||||
mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum,
|
||||
},
|
||||
register::PRegValue,
|
||||
unit::unit_base::UnitForwardingInfo,
|
||||
};
|
||||
use fayalite::{
|
||||
bundle::{Bundle, BundleType},
|
||||
|
@ -16,6 +17,7 @@ use fayalite::{
|
|||
};
|
||||
|
||||
pub mod alu_branch;
|
||||
pub mod unit_base;
|
||||
|
||||
macro_rules! all_units {
|
||||
(
|
||||
|
@ -42,9 +44,9 @@ macro_rules! all_units {
|
|||
}
|
||||
|
||||
impl $UnitKind {
|
||||
pub fn unit(self, config: &CpuConfig) -> DynUnit {
|
||||
pub fn unit(self, config: &CpuConfig, unit_index: usize) -> DynUnit {
|
||||
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]
|
||||
pub fn available_units_for_kind(&self, unit_kind: impl ToExpr<Type = $HdlUnitKind>) -> Expr<Array<Bool>> {
|
||||
#[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]
|
||||
match unit_kind {
|
||||
$($HdlUnitKind::$Unit => for (index, &unit_kind) in self.unit_kinds.iter().enumerate() {
|
||||
connect(available_units_for_kind[index], unit_kind == $UnitKind::$Unit);
|
||||
$($HdlUnitKind::$Unit => for (index, unit) in self.units.iter().enumerate() {
|
||||
connect(available_units_for_kind[index], unit.kind == $UnitKind::$Unit);
|
||||
})*
|
||||
}
|
||||
available_units_for_kind
|
||||
|
@ -129,13 +131,13 @@ all_units! {
|
|||
#[unit_kind = UnitKind]
|
||||
#[hdl]
|
||||
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]
|
||||
AluBranch(AluBranchMOp<DestReg, SrcRegWidth>),
|
||||
#[create_dyn_unit_fn = |config| todo!()]
|
||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||
#[extract = l2_register_file_mop]
|
||||
L2RegisterFile(L2RegisterFileMOp<DestReg, SrcRegWidth>),
|
||||
#[create_dyn_unit_fn = |config| todo!()]
|
||||
#[create_dyn_unit_fn = |config, unit_index| todo!()]
|
||||
#[extract = load_store_mop]
|
||||
LoadStore(LoadStoreMOp<DestReg, SrcRegWidth>),
|
||||
}
|
||||
|
@ -147,6 +149,12 @@ pub struct UnitResultCompleted<ExtraOut> {
|
|||
pub extra_out: ExtraOut,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct UnitOutputWrite<OutRegNumWidth: Size> {
|
||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
||||
pub value: PRegValue,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct TrapData {
|
||||
// TODO
|
||||
|
@ -159,14 +167,14 @@ pub enum UnitResult<ExtraOut> {
|
|||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct UnitOutput<UnitNumWidth: Size, OutRegNumWidth: Size, ExtraOut> {
|
||||
pub which: PRegNum<UnitNumWidth, OutRegNumWidth>,
|
||||
pub struct UnitOutput<OutRegNumWidth: Size, ExtraOut> {
|
||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
||||
pub result: UnitResult<ExtraOut>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct UnitCancelInput<UnitNumWidth: Size, OutRegNumWidth: Size> {
|
||||
pub which: PRegNum<UnitNumWidth, OutRegNumWidth>,
|
||||
pub struct UnitCancelInput<OutRegNumWidth: Size> {
|
||||
pub which: UnitOutRegNum<OutRegNumWidth>,
|
||||
}
|
||||
|
||||
pub trait UnitTrait:
|
||||
|
@ -187,18 +195,22 @@ pub trait UnitTrait:
|
|||
mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>,
|
||||
) -> 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,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>>;
|
||||
) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>>;
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
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 to_dyn(&self) -> DynUnit;
|
||||
|
@ -250,25 +262,29 @@ impl UnitTrait for DynUnit {
|
|||
self.unit.extract_mop(mop)
|
||||
}
|
||||
|
||||
fn make_module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.unit.make_module()
|
||||
fn module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.unit.module()
|
||||
}
|
||||
|
||||
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
self.unit.input(this)
|
||||
fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
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,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> {
|
||||
self.unit.cancel_input(this)
|
||||
) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
|
||||
self.unit.unit_forwarding_info(this)
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> {
|
||||
) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> {
|
||||
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)))
|
||||
}
|
||||
|
||||
fn make_module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.0.make_module().canonical().intern_sized()
|
||||
fn module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.0.module().canonical().intern_sized()
|
||||
}
|
||||
|
||||
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
Expr::from_bundle(Expr::as_bundle(self.0.input(Expr::from_bundle(this))))
|
||||
fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
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,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> {
|
||||
self.0.cancel_input(Expr::from_bundle(this))
|
||||
) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
|
||||
self.0.unit_forwarding_info(Expr::from_bundle(this))
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
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))))
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
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::{
|
||||
intern::{Intern, Interned},
|
||||
|
@ -13,14 +16,34 @@ use fayalite::{
|
|||
};
|
||||
|
||||
#[hdl_module]
|
||||
pub fn alu_branch(config: &CpuConfig) {
|
||||
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[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()]]);
|
||||
#[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
|
||||
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)]
|
||||
|
@ -30,10 +53,10 @@ pub struct AluBranch {
|
|||
}
|
||||
|
||||
impl AluBranch {
|
||||
pub fn new(config: &CpuConfig) -> Self {
|
||||
pub fn new(config: &CpuConfig, unit_index: usize) -> Self {
|
||||
Self {
|
||||
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 {
|
||||
self.module.io_ty().input.data.HdlSome
|
||||
self.module.io_ty().input_insn.data.HdlSome
|
||||
}
|
||||
|
||||
fn unit_kind(&self) -> UnitKind {
|
||||
|
@ -66,26 +89,30 @@ impl UnitTrait for AluBranch {
|
|||
UnitMOp::alu_branch_mop(mop)
|
||||
}
|
||||
|
||||
fn make_module(&self) -> Interned<Module<Self::Type>> {
|
||||
fn module(&self) -> Interned<Module<Self::Type>> {
|
||||
self.module
|
||||
}
|
||||
|
||||
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
this.input
|
||||
fn input_insn(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
|
||||
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,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> {
|
||||
todo!()
|
||||
) -> Expr<UnitForwardingInfo<DynSize, DynSize, DynSize>> {
|
||||
this.unit_forwarding_info
|
||||
}
|
||||
|
||||
fn output(
|
||||
&self,
|
||||
this: Expr<Self::Type>,
|
||||
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> {
|
||||
todo!()
|
||||
) -> Expr<ReadyValid<UnitOutput<DynSize, Self::ExtraOut>>> {
|
||||
this.output
|
||||
}
|
||||
|
||||
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||
|
|
130
crates/cpu/src/unit/unit_base.rs
Normal file
130
crates/cpu/src/unit/unit_base.rs
Normal 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
Loading…
Reference in a new issue