cpu/crates/cpu/src/unit.rs
Jacob Lifshay cb5855589f
All checks were successful
/ test (push) Successful in 46m24s
WIP adding register allocator
2024-10-14 21:20:42 -07:00

278 lines
7 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
config::CpuConfig,
instruction::{AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, PRegNum},
register::PRegValue,
};
use fayalite::{
bundle::{Bundle, BundleType},
intern::{Intern, Interned},
prelude::*,
util::ready_valid::ReadyValid,
};
macro_rules! all_units {
(
#[hdl_unit_kind = $HdlUnitKind:ident]
#[unit_kind = $UnitKind:ident]
#[hdl]
$(#[$enum_meta:meta])*
$vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> {
$(
$(#[$variant_meta:meta])*
$Unit:ident($Op:ty),
)*
}
) => {
$(#[$enum_meta])*
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
$vis enum $UnitKind {
$(
$(#[$variant_meta])*
$Unit,
)*
}
impl ToExpr for $UnitKind {
type Type = $HdlUnitKind;
fn to_expr(&self) -> Expr<Self::Type> {
match self {
$($UnitKind::$Unit => $HdlUnitKind.$Unit(),)*
}
}
}
#[hdl]
$(#[$enum_meta])*
$vis enum $HdlUnitKind {
$(
$(#[$variant_meta])*
$Unit,
)*
}
#[hdl]
$(#[$enum_meta])*
$vis enum $UnitMOpEnum<$RegWidth: Size> {
$(
$(#[$variant_meta])*
$Unit($Op),
)*
}
impl<$RegWidth: Size> $UnitMOpEnum<$RegWidth> {
#[hdl]
$vis fn kind(expr: impl ToExpr<Type = Self>) -> Expr<$HdlUnitKind> {
#[hdl]
let unit_kind = wire();
#[hdl]
match expr {
$($UnitMOpEnum::<$RegWidth>::$Unit(_) => connect(unit_kind, $HdlUnitKind.$Unit()),)*
}
unit_kind
}
}
impl CpuConfig {
#[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()]);
#[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);
})*
}
available_units_for_kind
}
}
};
}
all_units! {
#[hdl_unit_kind = HdlUnitKind]
#[unit_kind = UnitKind]
#[hdl]
pub enum UnitMOp<RegWidth: Size> {
AluBranch(AluBranchMOp<RegWidth>),
L2RegisterFile(L2RegisterFileMOp<RegWidth>),
LoadStore(LoadStoreMOp<RegWidth>),
}
}
#[hdl]
pub struct UnitResultCompleted<ExtraOut> {
pub value: PRegValue,
pub extra_out: ExtraOut,
}
#[hdl]
pub struct TrapData {
// TODO
}
#[hdl]
pub enum UnitResult<ExtraOut> {
Completed(UnitResultCompleted<ExtraOut>),
Trap(TrapData),
}
#[hdl]
pub struct UnitOutput<UnitNumWidth: Size, OutRegNumWidth: Size, ExtraOut> {
pub which: PRegNum<UnitNumWidth, OutRegNumWidth>,
pub result: UnitResult<ExtraOut>,
}
#[hdl]
pub struct UnitCancelInput<UnitNumWidth: Size, OutRegNumWidth: Size> {
pub which: PRegNum<UnitNumWidth, OutRegNumWidth>,
}
pub trait UnitTrait:
'static + Send + Sync + std::fmt::Debug + fayalite::intern::SupportsPtrEqWithTypeId
{
type Type: BundleType;
type ExtraOut: Type;
type MOp: Type;
fn ty(&self) -> Self::Type;
fn extra_out_ty(&self) -> Self::ExtraOut;
fn mop_ty(&self) -> Self::MOp;
fn unit_kind(&self) -> UnitKind;
fn make_module(&self) -> Interned<Module<Self::Type>>;
// TODO: add other inputs
fn cancel_input(
&self,
this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>>;
fn output(
&self,
this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>;
fn to_dyn(&self) -> DynUnit;
}
type DynUnitTrait = dyn UnitTrait<Type = Bundle, ExtraOut = CanonicalType, MOp = CanonicalType>;
impl fayalite::intern::InternedCompare for DynUnitTrait {
type InternedCompareKey = fayalite::intern::PtrEqWithTypeId;
fn interned_compare_key_ref(this: &Self) -> Self::InternedCompareKey {
Self::get_ptr_eq_with_type_id(this)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct DynUnit {
ty: Bundle,
extra_out_ty: CanonicalType,
mop_ty: CanonicalType,
unit_kind: UnitKind,
unit: Interned<DynUnitTrait>,
}
impl UnitTrait for DynUnit {
type Type = Bundle;
type ExtraOut = CanonicalType;
type MOp = CanonicalType;
fn ty(&self) -> Self::Type {
self.ty
}
fn extra_out_ty(&self) -> Self::ExtraOut {
self.extra_out_ty
}
fn mop_ty(&self) -> Self::MOp {
self.mop_ty
}
fn unit_kind(&self) -> UnitKind {
self.unit_kind
}
fn make_module(&self) -> Interned<Module<Self::Type>> {
self.unit.make_module()
}
fn cancel_input(
&self,
this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> {
self.unit.cancel_input(this)
}
fn output(
&self,
this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> {
self.unit.output(this)
}
fn to_dyn(&self) -> DynUnit {
*self
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct DynUnitWrapper<T>(pub T);
impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T> {
type Type = Bundle;
type ExtraOut = CanonicalType;
type MOp = CanonicalType;
fn ty(&self) -> Self::Type {
Bundle::from_canonical(self.0.ty().canonical())
}
fn extra_out_ty(&self) -> Self::ExtraOut {
self.0.extra_out_ty().canonical()
}
fn mop_ty(&self) -> Self::MOp {
self.0.mop_ty().canonical()
}
fn unit_kind(&self) -> UnitKind {
self.0.unit_kind()
}
fn make_module(&self) -> Interned<Module<Self::Type>> {
self.0.make_module().canonical().intern_sized()
}
fn cancel_input(
&self,
this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitCancelInput<DynSize, DynSize>>> {
self.0.cancel_input(Expr::from_bundle(this))
}
fn output(
&self,
this: Expr<Self::Type>,
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>> {
Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this))))
}
fn to_dyn(&self) -> DynUnit {
let unit = self.intern();
DynUnit {
ty: unit.ty(),
extra_out_ty: unit.extra_out_ty(),
mop_ty: unit.mop_ty(),
unit_kind: unit.unit_kind(),
unit: Interned::cast_unchecked(unit, |v: &Self| -> &DynUnitTrait { v }),
}
}
}