WIP implementing reg_alloc
All checks were successful
/ deps (push) Successful in 18s
/ test (push) Successful in 25m30s

This commit is contained in:
Jacob Lifshay 2024-11-05 17:34:31 -08:00
parent 1a72425156
commit b51109f4f6
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
4 changed files with 146 additions and 5 deletions

View file

@ -5,12 +5,14 @@ use crate::{
unit::UnitKind,
};
use fayalite::prelude::*;
use std::num::NonZeroUsize;
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub struct CpuConfig {
pub unit_kinds: Vec<UnitKind>,
pub out_reg_num_width: usize,
pub fetch_width: NonZeroUsize,
}
impl CpuConfig {

View file

@ -183,4 +183,5 @@ impl MOpRegNum {
pub const CONST_ZERO_REG_NUM: u32 = 0;
}
#[hdl]
pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>;

View file

@ -1,11 +1,128 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::config::CpuConfig;
use fayalite::prelude::*;
use crate::{
config::CpuConfig,
instruction::{MOp, UnitNum},
unit::{TrapData, UnitTrait},
util::tree_reduce::{tree_reduce, tree_reduce_with_state},
};
use fayalite::{module::instance_with_loc, prelude::*, util::ready_valid::ReadyValid};
use std::num::NonZeroUsize;
pub mod unit_free_regs_tracker;
#[hdl_module]
pub fn reg_alloc(config: CpuConfig) {
todo!()
#[hdl]
pub struct FetchedDecodedMOp {
pub uop: MOp,
/// true if pc doesn't have to be related to the previous instruction.
/// (enable to stop detecting when the current instruction isn't
/// supposed to be run next, e.g. on branch mis-prediction)
pub is_unrelated_pc: Bool,
pub pc: UInt<64>,
}
#[hdl]
pub enum FetchDecodeSpecialOp {
Trap(TrapData),
ICacheFlush,
}
#[hdl]
pub struct FetchDecodeInterface<FetchWidth: Size> {
pub decoded_insns: ArrayType<ReadyValid<FetchedDecodedMOp>, FetchWidth>,
#[hdl(flip)]
pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>,
}
#[hdl_module]
/// combination register allocator, register renaming, unit selection, and retire handling
pub fn reg_alloc(config: &CpuConfig) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let fetch_decode_interface: FetchDecodeInterface<DynSize> =
m.input(FetchDecodeInterface[config.fetch_width.get()]);
// TODO: propagate traps, branch mis-predictions, and special ops
connect(
fetch_decode_interface.fetch_decode_special_op.data,
HdlNone(),
);
// TODO: finish
#[hdl]
let available_units =
wire(Array[Array[Bool][config.unit_kinds.len()]][config.fetch_width.get()]);
#[hdl]
let selected_unit_nums = wire(Array[HdlOption[config.unit_num()]][config.fetch_width.get()]);
for fetch_index in 0..config.fetch_width.get() {
connect(
fetch_decode_interface.decoded_insns[fetch_index].ready,
true,
);
connect(
available_units[fetch_index],
repeat(false, config.unit_kinds.len()),
);
#[hdl]
if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data {
connect(
available_units[fetch_index],
config.available_units_for_kind(MOp::kind(decoded_insn.uop)),
);
}
connect(
selected_unit_nums[fetch_index],
tree_reduce_with_state(
0..config.unit_kinds.len(),
&mut (),
|_state, unit_index| {
#[hdl]
let selected_unit_leaf = wire(HdlOption[config.unit_num()]);
connect(selected_unit_leaf, HdlOption[config.unit_num()].HdlNone());
#[hdl]
let unit_num = wire(config.unit_num());
connect_any(unit_num.value, unit_index);
#[hdl]
if available_units[fetch_index][unit_index] {
connect(selected_unit_leaf, HdlSome(unit_num))
}
selected_unit_leaf
},
|_state, l, r| {
#[hdl]
let selected_unit_node = wire(Expr::ty(l));
connect(selected_unit_node, l);
#[hdl]
if let HdlNone = l {
connect(selected_unit_node, r);
}
selected_unit_node
},
)
.expect("expected at least one unit"),
);
}
for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() {
let dyn_unit = unit_kind.unit(config);
let unit = instance_with_loc(
&format!("unit_{unit_index}"),
dyn_unit.make_module(),
SourceLocation::caller(),
);
connect(dyn_unit.cd(unit), cd);
// 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
let retire_from_unit_at_once = NonZeroUsize::new(1).unwrap();
let unit_free_regs_tracker = instance_with_loc(
&format!("unit_{unit_index}_free_regs_tracker"),
unit_free_regs_tracker::unit_free_regs_tracker(
retire_from_unit_at_once,
assign_to_unit_at_once,
config.out_reg_num_width,
),
SourceLocation::caller(),
);
connect(unit_free_regs_tracker.cd, cd);
// TODO: finish
}
}

View file

@ -21,6 +21,7 @@ macro_rules! all_units {
$(#[$enum_meta:meta])*
$vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> {
$(
#[create_dyn_unit_fn = $create_dyn_unit_fn:expr]
$(#[$variant_meta:meta])*
$Unit:ident($Op:ty),
)*
@ -35,6 +36,14 @@ macro_rules! all_units {
)*
}
impl $UnitKind {
pub fn unit(self, config: &CpuConfig) -> DynUnit {
match self {
$($UnitKind::$Unit => $create_dyn_unit_fn(config),)*
}
}
}
impl ToExpr for $UnitKind {
type Type = $HdlUnitKind;
@ -98,8 +107,11 @@ all_units! {
#[unit_kind = UnitKind]
#[hdl]
pub enum UnitMOp<RegWidth: Size> {
#[create_dyn_unit_fn = |config| todo!()]
AluBranch(AluBranchMOp<RegWidth>),
#[create_dyn_unit_fn = |config| todo!()]
L2RegisterFile(L2RegisterFileMOp<RegWidth>),
#[create_dyn_unit_fn = |config| todo!()]
LoadStore(LoadStoreMOp<RegWidth>),
}
}
@ -156,6 +168,7 @@ pub trait UnitTrait:
&self,
this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>;
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
fn to_dyn(&self) -> DynUnit;
}
@ -217,6 +230,10 @@ impl UnitTrait for DynUnit {
self.unit.output(this)
}
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
self.unit.cd(this)
}
fn to_dyn(&self) -> DynUnit {
*self
}
@ -264,6 +281,10 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this))))
}
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
self.0.cd(Expr::from_bundle(this))
}
fn to_dyn(&self) -> DynUnit {
let unit = self.intern();
DynUnit {