working on reg_alloc
All checks were successful
/ deps (push) Successful in 19s
/ test (push) Successful in 26m12s

This commit is contained in:
Jacob Lifshay 2025-02-06 21:28:30 -08:00
parent 88eff5952b
commit 7efcd872b5
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
10 changed files with 112441 additions and 7174 deletions

View file

@ -15,3 +15,6 @@ rust-version = "1.82.0"
[workspace.dependencies]
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
[profile.dev]
opt-level = 1

View file

@ -1,8 +1,8 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
instruction::{PRegNum, UnitNum, CONST_ZERO_UNIT_NUM},
unit::UnitKind,
instruction::{PRegNum, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM},
unit::{UnitKind, UnitMOp},
};
use fayalite::prelude::*;
use std::num::NonZeroUsize;
@ -34,12 +34,21 @@ impl CpuConfig {
(CONST_ZERO_UNIT_NUM + 1)..(self.unit_kinds.len() + 1)
}
pub fn unit_num_width(&self) -> usize {
UInt::range(self.non_const_unit_nums()).width()
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 unit_mop_in_unit(&self) -> UnitMOp<UnitOutRegNum<DynSize>, DynSize> {
UnitMOp[self.unit_out_reg_num()][self.p_reg_num_width()]
}
}

View file

@ -1,11 +1,108 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::unit::UnitMOp;
use crate::{unit::UnitMOp, util::range_u32_len};
use fayalite::{expr::ops::ArrayLiteral, intern::Interned, prelude::*};
use std::marker::PhantomData;
use std::{marker::PhantomData, ops::Range};
pub mod power_isa;
pub trait MOpTrait: Type {
type Mapped<NewDestReg: Type, NewSrcRegWidth: Size>: MOpTrait;
type DestReg: Type;
type SrcRegWidth: Size;
fn dest_reg_ty(self) -> Self::DestReg;
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg>;
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_dest_reg: NewDestReg,
new_src_reg_width: NewSrcRegWidth::SizeType,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth>;
fn map_regs<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_dest: impl ToExpr<Type = NewDestReg>,
new_src_reg_width: NewSrcRegWidth::SizeType,
map_src: &mut impl FnMut(
Expr<UIntType<Self::SrcRegWidth>>,
usize,
) -> Expr<UIntType<NewSrcRegWidth>>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
}
pub trait CommonMOpTrait: MOpTrait {
type PrefixPad: KnownSize;
type SrcCount: KnownSize;
type CommonMOpTraitMapped<NewDestReg: Type, NewSrcRegWidth: Size>: CommonMOpTrait;
type CommonMOpTraitDestReg: Type;
type CommonMOpTraitSrcRegWidth: Size;
fn common_mop_ty(
self,
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>;
fn common_mop(
input: impl ToExpr<Type = Self>,
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>>;
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth>;
fn with_common_mop<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_common_mop: impl ToExpr<
Type = CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>>;
}
impl<T: CommonMOpTrait> MOpTrait for T {
type Mapped<NewDestReg: Type, NewSrcRegWidth: Size> =
T::CommonMOpTraitMapped<NewDestReg, NewSrcRegWidth>;
type DestReg = T::CommonMOpTraitDestReg;
type SrcRegWidth = T::CommonMOpTraitSrcRegWidth;
fn dest_reg_ty(self) -> Self::DestReg {
self.common_mop_ty().dest
}
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> {
T::common_mop(input).dest
}
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_dest_reg: NewDestReg,
new_src_reg_width: NewSrcRegWidth::SizeType,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth> {
self.with_common_mop_ty(
CommonMOp[T::PrefixPad::SIZE][new_dest_reg][new_src_reg_width][T::SrcCount::SIZE],
)
}
fn map_regs<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_dest: impl ToExpr<Type = NewDestReg>,
new_src_reg_width: NewSrcRegWidth::SizeType,
map_src: &mut impl FnMut(
Expr<UIntType<Self::SrcRegWidth>>,
usize,
) -> Expr<UIntType<NewSrcRegWidth>>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let input = input.to_expr();
let common = T::common_mop(input);
let new_dest = new_dest.to_expr();
T::with_common_mop(
input,
CommonMOp::new(
common.prefix_pad,
new_dest,
ArrayLiteral::new(
UIntType[new_src_reg_width],
Interned::from_iter(
(0..T::SrcCount::VALUE)
.map(|index| Expr::canonical(map_src(common.src[index], index))),
),
)
.to_expr(),
CommonMOp::imm(common),
),
)
}
}
#[hdl]
pub enum OutputIntegerMode {
Full64,
@ -25,15 +122,51 @@ pub const COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM: usize = 2;
pub const COMMON_MOP_IMM_LOW_WIDTH: usize = CommonMOpWithMaxSrcCount::IMM_WIDTH - 1;
#[hdl]
pub struct CommonMOp<PrefixPad: KnownSize, RegWidth: Size, SrcCount: KnownSize> {
pub struct CommonMOp<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
pub prefix_pad: UIntType<PrefixPad>,
pub dest: UIntType<RegWidth>,
pub src: Array<UIntType<RegWidth>, { COMMON_MOP_SRC_LEN }>,
pub dest: DestReg,
pub src: Array<UIntType<SrcRegWidth>, { COMMON_MOP_SRC_LEN }>,
pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>,
pub imm_sign: SInt<1>,
pub _phantom: PhantomData<SrcCount>,
}
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> CommonMOpTrait
for CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount>
{
type PrefixPad = PrefixPad;
type SrcCount = SrcCount;
type CommonMOpTraitMapped<NewDestReg: Type, NewSrcRegWidth: Size> =
CommonMOp<PrefixPad, NewDestReg, NewSrcRegWidth, SrcCount>;
type CommonMOpTraitDestReg = DestReg;
type CommonMOpTraitSrcRegWidth = SrcRegWidth;
fn common_mop_ty(
self,
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount> {
self
}
fn common_mop(
input: impl ToExpr<Type = Self>,
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>> {
input.to_expr()
}
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth> {
new_common_mop_ty
}
fn with_common_mop<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_common_mop: impl ToExpr<
Type = CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let _ = input.to_expr();
new_common_mop.to_expr()
}
}
#[hdl]
pub struct CommonMOpImmParts<ImmInSrcCount: Size> {
// fields must be in this exact order
@ -45,7 +178,7 @@ pub struct CommonMOpImmParts<ImmInSrcCount: Size> {
type CommonMOpWithMaxSrcCount = CommonMOpForImm<{ COMMON_MOP_SRC_LEN }>;
type CommonMOpForImm<const SRC_COUNT: usize> =
CommonMOp<ConstUsize<0>, ConstUsize<{ MOP_MIN_REG_WIDTH }>, ConstUsize<SRC_COUNT>>;
CommonMOp<ConstUsize<0>, (), ConstUsize<{ MOP_MIN_REG_WIDTH }>, ConstUsize<SRC_COUNT>>;
pub const COMMON_MOP_0_IMM_WIDTH: usize = CommonMOpForImm::<0>::IMM_WIDTH;
pub const COMMON_MOP_1_IMM_WIDTH: usize = CommonMOpForImm::<1>::IMM_WIDTH;
@ -53,8 +186,8 @@ pub const COMMON_MOP_2_IMM_WIDTH: usize = CommonMOpForImm::<2>::IMM_WIDTH;
pub const COMMON_MOP_3_IMM_WIDTH: usize = CommonMOpForImm::<3>::IMM_WIDTH;
const COMMON_MOP_0_IMM_IN_SRC_COUNT: usize = CommonMOpForImm::<0>::IMM_IN_SRC_COUNT;
impl<PrefixPad: KnownSize, RegWidth: Size, SrcCount: KnownSize>
CommonMOp<PrefixPad, RegWidth, SrcCount>
impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize>
CommonMOp<PrefixPad, DestReg, SrcRegWidth, SrcCount>
{
pub const IMM_IN_SRC_COUNT: usize = {
assert!(SrcCount::VALUE <= COMMON_MOP_SRC_LEN, "too many sources");
@ -62,7 +195,7 @@ impl<PrefixPad: KnownSize, RegWidth: Size, SrcCount: KnownSize>
(COMMON_MOP_SRC_LEN - COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM)
- SrcCount::VALUE.saturating_sub(COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM)
};
pub const IMM_IN_SRC_RANGE: std::ops::Range<usize> =
pub const IMM_IN_SRC_RANGE: Range<usize> =
(COMMON_MOP_SRC_LEN - Self::IMM_IN_SRC_COUNT)..COMMON_MOP_SRC_LEN;
pub const IMM_WIDTH: usize = {
MOP_IMM_WIDTH - (COMMON_MOP_0_IMM_IN_SRC_COUNT - Self::IMM_IN_SRC_COUNT) * MOP_MIN_REG_WIDTH
@ -82,8 +215,8 @@ impl<PrefixPad: KnownSize, RegWidth: Size, SrcCount: KnownSize>
#[hdl]
pub fn new(
prefix_pad: impl ToExpr<Type = UIntType<PrefixPad>>,
dest: impl ToExpr<Type = UIntType<RegWidth>>,
src: impl ToExpr<Type = ArrayType<UIntType<RegWidth>, SrcCount>>,
dest: impl ToExpr<Type = DestReg>,
src: impl ToExpr<Type = ArrayType<UIntType<SrcRegWidth>, SrcCount>>,
imm: impl ToExpr<Type = SInt>,
) -> Expr<Self> {
let prefix_pad = prefix_pad.to_expr();
@ -91,22 +224,21 @@ impl<PrefixPad: KnownSize, RegWidth: Size, SrcCount: KnownSize>
let src_in = src.to_expr();
let imm = imm.to_expr();
assert_eq!(Expr::ty(imm), Self::imm_ty());
let reg_ty = Expr::ty(dest);
assert_eq!(reg_ty, Expr::ty(src_in).element());
let src_reg_ty = Expr::ty(src_in).element();
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
let mut src = [0_hdl_u0.cast_to(reg_ty); COMMON_MOP_SRC_LEN];
let mut src = [0_hdl_u0.cast_to(src_reg_ty); COMMON_MOP_SRC_LEN];
for i in 0..SrcCount::VALUE {
src[i] = src_in[i];
}
for (reversed_src_index, src_index) in Self::IMM_IN_SRC_RANGE.rev().enumerate() {
src[src_index] = imm_parts.reversed_src[reversed_src_index].cast_to(reg_ty);
src[src_index] = imm_parts.reversed_src[reversed_src_index].cast_to(src_reg_ty);
}
#[hdl]
Self {
prefix_pad,
dest,
src: ArrayLiteral::new(
reg_ty,
src_reg_ty,
Interned::from_iter(src.iter().map(|v| Expr::canonical(*v))),
)
.to_expr(),
@ -136,17 +268,16 @@ impl<PrefixPad: KnownSize, RegWidth: Size, SrcCount: KnownSize>
#[hdl]
pub fn connect_to_imm(expr: impl ToExpr<Type = Self>, imm: impl ToExpr<Type = SInt>) {
let expr = expr.to_expr();
let reg_ty = Expr::ty(expr).dest;
assert_eq!(reg_ty, Expr::ty(expr).src.element());
let src_reg_ty = Expr::ty(expr).src.element();
let imm = imm.to_expr();
assert_eq!(Expr::ty(imm), Self::imm_ty());
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
let mut src = [Some(0_hdl_u0.cast_to(reg_ty)); COMMON_MOP_SRC_LEN];
let mut src = [Some(0_hdl_u0.cast_to(src_reg_ty)); COMMON_MOP_SRC_LEN];
for i in 0..SrcCount::VALUE {
src[i] = None;
}
for (reversed_src_index, src_index) in Self::IMM_IN_SRC_RANGE.rev().enumerate() {
src[src_index] = Some(imm_parts.reversed_src[reversed_src_index].cast_to(reg_ty));
src[src_index] = Some(imm_parts.reversed_src[reversed_src_index].cast_to(src_reg_ty));
}
for i in 0..COMMON_MOP_SRC_LEN {
if let Some(v) = src[i] {
@ -156,82 +287,307 @@ impl<PrefixPad: KnownSize, RegWidth: Size, SrcCount: KnownSize>
}
}
#[hdl]
pub struct AluCommonMOp<RegWidth: Size, SrcCount: KnownSize> {
pub common: CommonMOp<ConstUsize<0>, RegWidth, SrcCount>,
pub output_integer_mode: OutputIntegerMode,
macro_rules! common_mop_struct {
(
#[mapped(<$NewDestReg:ident, $SrcRegWidth:ident> $mapped_ty:ty)]
$(#[$struct_meta:meta])*
$vis:vis struct $MOp:ident<$($Generic:ident: $GenericBound:ident),* $(,)?> {
#[common]
$(#[$common_meta:meta])*
$common_vis:vis $common:ident: $common_ty:ty,
$(
$(#[$field_meta:meta])*
$field_vis:vis $field:ident: $field_ty:ty,
)*
}
) => {
$(#[$struct_meta])*
$vis struct $MOp<$($Generic: $GenericBound),*> {
$(#[$common_meta])*
$common_vis $common: $common_ty,
$(
$(#[$field_meta])*
$field_vis $field: $field_ty,
)*
}
impl<$($Generic: $GenericBound),*> CommonMOpTrait for $MOp<$($Generic),*> {
type PrefixPad = <$common_ty as CommonMOpTrait>::PrefixPad;
type SrcCount = <$common_ty as CommonMOpTrait>::SrcCount;
type CommonMOpTraitMapped<$NewDestReg: Type, $SrcRegWidth: Size> = $mapped_ty;
type CommonMOpTraitDestReg = <$common_ty as CommonMOpTrait>::CommonMOpTraitDestReg;
type CommonMOpTraitSrcRegWidth = <$common_ty as CommonMOpTrait>::CommonMOpTraitSrcRegWidth;
fn common_mop_ty(
self,
) -> CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount> {
CommonMOpTrait::common_mop_ty(self.$common)
}
fn common_mop(
input: impl ToExpr<Type = Self>,
) -> Expr<CommonMOp<Self::PrefixPad, Self::DestReg, Self::SrcRegWidth, Self::SrcCount>> {
CommonMOpTrait::common_mop(input.to_expr().$common)
}
fn with_common_mop_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_common_mop_ty: CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth> {
$MOp {
$common: CommonMOpTrait::with_common_mop_ty(self.$common, new_common_mop_ty),
$($field: self.$field,)*
}
}
#[hdl]
fn with_common_mop<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_common_mop: impl ToExpr<
Type = CommonMOp<Self::PrefixPad, NewDestReg, NewSrcRegWidth, Self::SrcCount>,
>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let input = input.to_expr();
#[hdl]
$MOp {
$common: CommonMOpTrait::with_common_mop(input.$common, new_common_mop),
$($field: input.$field,)*
}
}
}
};
}
#[hdl]
pub struct AddSubMOp<RegWidth: Size, SrcCount: KnownSize> {
pub alu_common: AluCommonMOp<RegWidth, SrcCount>,
pub invert_src0: Bool,
pub invert_carry_in: Bool,
pub invert_carry_out: Bool,
pub add_pc: Bool,
macro_rules! mop_enum {
(
$(#[$enum_meta:meta])*
$vis:vis enum $MOp:ident<$DestReg:ident: Type, $SrcRegWidth:ident: Size> {
$(#[$first_variant_meta:meta])*
$FirstVariant:ident($first_ty:ty),
$(
$(#[$variant_meta:meta])*
$Variant:ident($ty:ty),
)*
}
) => {
$(#[$enum_meta])*
$vis enum $MOp<$DestReg: Type, $SrcRegWidth: Size> {
$(#[$first_variant_meta])*
$FirstVariant($first_ty),
$(
$(#[$variant_meta])*
$Variant($ty),
)*
}
impl<$DestReg: Type, $SrcRegWidth: Size> MOpTrait for $MOp<$DestReg, $SrcRegWidth> {
type Mapped<NewDestReg: Type, NewSrcRegWidth: Size> = $MOp<NewDestReg, NewSrcRegWidth>;
type DestReg = $DestReg;
type SrcRegWidth = $SrcRegWidth;
fn dest_reg_ty(self) -> Self::DestReg {
self.$FirstVariant.dest_reg_ty()
}
#[hdl]
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> {
let input = input.to_expr();
#[hdl]
let dest_reg = wire(Expr::ty(input).dest_reg_ty());
#[hdl]
match input {
$MOp::<_, _>::$FirstVariant(v) => connect(dest_reg, MOpTrait::dest_reg(v)),
$($MOp::<_, _>::$Variant(v) => connect(dest_reg, MOpTrait::dest_reg(v)),)*
}
dest_reg
}
fn mapped_ty<NewDestReg: Type, NewSrcRegWidth: Size>(
self,
new_dest_reg: NewDestReg,
new_src_reg_width: NewSrcRegWidth::SizeType,
) -> Self::Mapped<NewDestReg, NewSrcRegWidth> {
$MOp[new_dest_reg][new_src_reg_width]
}
#[hdl]
fn map_regs<NewDestReg: Type, NewSrcRegWidth: Size>(
input: impl ToExpr<Type = Self>,
new_dest: impl ToExpr<Type = NewDestReg>,
new_src_reg_width: NewSrcRegWidth::SizeType,
map_src: &mut impl FnMut(
Expr<UIntType<Self::SrcRegWidth>>,
usize,
) -> Expr<UIntType<NewSrcRegWidth>>,
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
let input = input.to_expr();
let new_dest = new_dest.to_expr();
let mapped_ty = Expr::ty(input).mapped_ty(Expr::ty(new_dest), new_src_reg_width);
#[hdl]
let mapped_regs = wire(mapped_ty);
#[hdl]
match input {
$MOp::<_, _>::$FirstVariant(v) => connect(mapped_regs, mapped_ty.$FirstVariant(MOpTrait::map_regs(v, new_dest, new_src_reg_width, map_src))),
$($MOp::<_, _>::$Variant(v) => connect(mapped_regs, mapped_ty.$Variant(MOpTrait::map_regs(v, new_dest, new_src_reg_width, map_src))),)*
}
mapped_regs
}
}
};
}
#[hdl]
pub struct LogicalMOp<RegWidth: Size> {
pub alu_common: AluCommonMOp<RegWidth, ConstUsize<2>>,
pub lut: UInt<4>,
pub(crate) use mop_enum;
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> AluCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
#[hdl]
pub struct AluCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub common: CommonMOp<ConstUsize<0>, DestReg, SrcRegWidth, SrcCount>,
pub output_integer_mode: OutputIntegerMode,
}
}
#[hdl]
pub struct BranchMOp<RegWidth: Size> {
pub alu_common: AluCommonMOp<RegWidth, ConstUsize<2>>,
pub lut: UInt<4>,
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> AddSubMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
#[hdl]
pub struct AddSubMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>,
pub invert_src0: Bool,
pub invert_carry_in: Bool,
pub invert_carry_out: Bool,
pub add_pc: Bool,
}
}
#[hdl]
pub enum AluBranchMOp<RegWidth: Size> {
AddSub(AddSubMOp<RegWidth, ConstUsize<3>>),
AddSubI(AddSubMOp<RegWidth, ConstUsize<2>>),
Logical(LogicalMOp<RegWidth>),
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> LogicalMOp<NewDestReg, NewSrcRegWidth>)]
#[hdl]
pub struct LogicalMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
pub lut: UInt<4>,
}
}
#[hdl]
pub struct ReadL2RegMOp<RegWidth: Size> {
pub common: CommonMOp<ConstUsize<1>, RegWidth, ConstUsize<0>>,
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> BranchMOp<NewDestReg, NewSrcRegWidth>)]
#[hdl]
pub struct BranchMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
pub lut: UInt<4>,
}
}
#[hdl]
pub struct WriteL2RegMOp<RegWidth: Size> {
pub common: CommonMOp<ConstUsize<1>, RegWidth, ConstUsize<1>>,
mop_enum! {
#[hdl]
pub enum AluBranchMOp<DestReg: Type, SrcRegWidth: Size> {
AddSub(AddSubMOp<DestReg, SrcRegWidth, ConstUsize<3>>),
AddSubI(AddSubMOp<DestReg, SrcRegWidth, ConstUsize<2>>),
Logical(LogicalMOp<DestReg, SrcRegWidth>),
}
}
#[hdl]
pub enum L2RegisterFileMOp<RegWidth: Size> {
ReadL2Reg(ReadL2RegMOp<RegWidth>),
WriteL2Reg(WriteL2RegMOp<RegWidth>),
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> ReadL2RegMOp<NewDestReg, NewSrcRegWidth>)]
#[hdl]
pub struct ReadL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<0>>,
}
}
#[hdl]
pub struct LoadStoreCommonMOp<RegWidth: Size, SrcCount: KnownSize> {
pub common: CommonMOp<ConstUsize<1>, RegWidth, SrcCount>,
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> WriteL2RegMOp<NewDestReg, NewSrcRegWidth>)]
#[hdl]
pub struct WriteL2RegMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<1>>,
}
}
#[hdl]
pub struct LoadMOp<RegWidth: Size> {
pub load_store_common: LoadStoreCommonMOp<RegWidth, ConstUsize<1>>,
mop_enum! {
#[hdl]
pub enum L2RegisterFileMOp<DestReg: Type, SrcRegWidth: Size> {
ReadL2Reg(ReadL2RegMOp<DestReg, SrcRegWidth>),
WriteL2Reg(WriteL2RegMOp<DestReg, SrcRegWidth>),
}
}
#[hdl]
pub struct StoreMOp<RegWidth: Size> {
pub load_store_common: LoadStoreCommonMOp<RegWidth, ConstUsize<2>>,
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> LoadStoreCommonMOp<NewDestReg, NewSrcRegWidth, SrcCount>)]
#[hdl]
pub struct LoadStoreCommonMOp<DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize> {
#[common]
pub common: CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, SrcCount>,
}
}
#[hdl]
pub enum LoadStoreMOp<RegWidth: Size> {
Load(CommonMOp<ConstUsize<1>, RegWidth, ConstUsize<0>>),
Store(CommonMOp<ConstUsize<1>, RegWidth, ConstUsize<1>>),
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> LoadMOp<NewDestReg, NewSrcRegWidth>)]
#[hdl]
pub struct LoadMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<1>>,
}
}
common_mop_struct! {
#[mapped(<NewDestReg, NewSrcRegWidth> StoreMOp<NewDestReg, NewSrcRegWidth>)]
#[hdl]
pub struct StoreMOp<DestReg: Type, SrcRegWidth: Size> {
#[common]
pub load_store_common: LoadStoreCommonMOp<DestReg, SrcRegWidth, ConstUsize<2>>,
}
}
mop_enum! {
#[hdl]
pub enum LoadStoreMOp<DestReg: Type, SrcRegWidth: Size> {
Load(CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<0>>),
Store(CommonMOp<ConstUsize<1>, DestReg, SrcRegWidth, ConstUsize<1>>),
}
}
#[hdl]
/// 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 value: UIntType<Width>,
pub adj_value: UIntType<Width>,
}
impl<Width: Size> UnitNum<Width> {
#[hdl]
pub fn const_zero(self) -> Expr<Self> {
#[hdl]
UnitNum {
adj_value: CONST_ZERO_UNIT_NUM.cast_to(self.adj_value),
}
}
#[hdl]
pub fn from_index(self, index: usize) -> Expr<Self> {
#[hdl]
UnitNum {
adj_value: (index + 1).cast_to(self.adj_value),
}
}
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
let expr = expr.to_expr();
Expr::ty(expr)
.from_index(index)
.adj_value
.cmp_eq(expr.adj_value)
}
#[hdl]
pub fn as_index(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<UIntType<Width>>> {
let expr = expr.to_expr();
#[hdl]
let unit_index = wire(HdlOption[Expr::ty(expr).adj_value]);
connect(unit_index, Expr::ty(unit_index).HdlNone());
#[hdl]
if expr.adj_value.cmp_ne(0u8) {
connect(
unit_index,
HdlSome((expr.adj_value - 1u8).cast_to(Expr::ty(expr).adj_value)),
);
}
unit_index
}
}
pub const CONST_ZERO_UNIT_NUM: usize = 0;
@ -248,6 +604,20 @@ pub struct PRegNum<UnitNumWidth: Size, OutRegNumWidth: Size> {
pub unit_out_reg: UnitOutRegNum<OutRegNumWidth>,
}
impl<UnitNumWidth: Size, OutRegNumWidth: Size> PRegNum<UnitNumWidth, OutRegNumWidth> {
#[hdl]
pub fn const_zero(self) -> Expr<Self> {
#[hdl]
PRegNum {
unit_num: self.unit_num.const_zero(),
unit_out_reg: #[hdl]
UnitOutRegNum {
value: 0u8.cast_to(self.unit_out_reg.value),
},
}
}
}
#[hdl]
/// µOp Register Number -- register in a micro-operation before register renaming
#[doc(alias = "UOpRegNum")] // help you find it in the docs if you mis-spell it
@ -261,7 +631,110 @@ pub struct MOpRegNum {
impl MOpRegNum {
pub const WIDTH: usize = 8;
pub const CONST_ZERO_REG_NUM: u32 = 0;
#[hdl]
pub fn const_zero() -> Expr<Self> {
#[hdl]
MOpRegNum {
value: Self::CONST_ZERO_REG_NUM.cast_to_static(),
}
}
/// a lot of instructions write to flag registers that we want
/// to register allocate separately.
///
/// e.g. x86 `CF` is not modified by `INC`, but is by `ADD`, so to not slow down `INC`,
/// we'd need to have `CF` be renamed separately from other flags such as `ZF`.
///
/// Note this doesn't mean that each instruction has to write to multiple physical registers,
/// all registers written by an instruction are renamed to the same physical register.
//
// TODO: maybe add more registers later.
pub const FLAG_REG_NUMS: Range<u32> = 0xFE..0x100;
/// registers handled by a special small rename table (for flags and stuff, since it has more read/write ports)
pub const SPECIAL_REG_NUMS: Range<u32> = Self::FLAG_REG_NUMS;
/// registers handled by the large rename table for normal registers (has less read/write ports)
pub const NORMAL_REG_NUMS: Range<u32> =
Self::CONST_ZERO_REG_NUM + 1..Self::SPECIAL_REG_NUMS.start;
}
#[hdl]
pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>;
/// all the registers this instruction will write to, they are all renamed to the same physical register.
pub struct MOpDestReg {
/// some instructions have multiple destination registers, e.g. x86 div
pub normal_regs: Array<MOpRegNum, { MOpDestReg::NORMAL_REG_COUNT }>,
/// a lot of instructions also write to flag registers.
///
/// when an element with index `index` is `HdlSome(())`,
/// then the register to write to is [`MOpRegNum::FLAG_REG_NUMS[index]`][MOpRegNum::FLAG_REG_NUMS].
pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum MOpDestRegKind {
NormalReg {
/// index in `MOpDestReg::normal_regs`
dest_reg_index: usize,
},
FlagReg {
/// index in `MOpDestReg::flag_regs`
flag_reg_index: usize,
/// value for `MOpRegNum::value`
reg_num: u32,
},
}
impl MOpDestReg {
pub const NORMAL_REG_COUNT: usize = 2;
pub const REG_COUNT: usize = Self::NORMAL_REG_COUNT + range_u32_len(&MOpRegNum::FLAG_REG_NUMS);
pub const REG_KINDS: [MOpDestRegKind; Self::REG_COUNT] = {
let mut retval = [MOpDestRegKind::NormalReg { dest_reg_index: 0 }; Self::REG_COUNT];
let mut write_index = 0;
let mut dest_reg_index = 0;
while dest_reg_index < Self::NORMAL_REG_COUNT {
retval[write_index] = MOpDestRegKind::NormalReg { dest_reg_index };
write_index += 1;
dest_reg_index += 1;
}
let mut flag_reg_index = 0;
while flag_reg_index < range_u32_len(&MOpRegNum::FLAG_REG_NUMS) {
retval[write_index] = MOpDestRegKind::FlagReg {
flag_reg_index,
reg_num: flag_reg_index as u32 + MOpRegNum::FLAG_REG_NUMS.start,
};
write_index += 1;
flag_reg_index += 1;
}
// make sure we didn't miss filling any
assert!(write_index == Self::REG_COUNT);
retval
};
#[hdl]
pub fn regs(this: impl ToExpr<Type = Self>) -> [Expr<MOpRegNum>; Self::REG_COUNT] {
let this = this.to_expr();
std::array::from_fn(|index| match Self::REG_KINDS[index] {
MOpDestRegKind::NormalReg { dest_reg_index } => this.normal_regs[dest_reg_index],
MOpDestRegKind::FlagReg {
flag_reg_index,
reg_num,
} => {
#[hdl]
let flag_reg = wire();
connect(flag_reg, MOpRegNum::const_zero());
#[hdl]
if let HdlSome(v) = this.flag_regs[flag_reg_index] {
let () = *v;
connect(
flag_reg,
#[hdl]
MOpRegNum {
value: reg_num.cast_to_static(),
},
);
}
flag_reg
}
})
}
}
#[hdl]
pub type MOp = UnitMOp<MOpDestReg, ConstUsize<{ MOpRegNum::WIDTH }>>;

View file

@ -2,7 +2,9 @@
// See Notices.txt for copyright information
use crate::{
config::CpuConfig,
instruction::MOp,
instruction::{
MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN,
},
unit::{TrapData, UnitTrait},
util::tree_reduce::tree_reduce_with_state,
};
@ -17,7 +19,7 @@ pub mod unit_free_regs_tracker;
#[hdl]
pub struct FetchedDecodedMOp {
pub uop: MOp,
pub mop: 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)
@ -52,11 +54,27 @@ pub fn reg_alloc(config: &CpuConfig) {
HdlNone(),
);
// TODO: finish
// the large rename table for normal registers (has less read/write ports)
#[hdl]
let mut rename_table_normal_mem = memory(config.p_reg_num());
rename_table_normal_mem.depth(MOpRegNum::NORMAL_REG_NUMS.len());
// a special small rename table (for flags and stuff, since it has more read/write ports)
#[hdl]
let mut rename_table_special_mem = memory(config.p_reg_num());
rename_table_special_mem.depth(MOpRegNum::SPECIAL_REG_NUMS.len());
#[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()]);
let selected_unit_indexes =
wire(Array[HdlOption[UInt[config.unit_num_width()]]][config.fetch_width.get()]);
#[hdl]
let renamed_mops = wire(Array[HdlOption[config.unit_mop_in_unit()]][config.fetch_width.get()]);
#[hdl]
let renamed_mops_out_reg = wire(Array[HdlOption[config.p_reg_num()]][config.fetch_width.get()]);
for fetch_index in 0..config.fetch_width.get() {
connect(
fetch_decode_interface.decoded_insns[fetch_index].ready,
@ -66,50 +84,160 @@ pub fn reg_alloc(config: &CpuConfig) {
available_units[fetch_index],
repeat(false, config.unit_kinds.len()),
);
connect(
renamed_mops[fetch_index],
Expr::ty(renamed_mops).element().HdlNone(),
);
#[hdl]
struct RenameTableReadPort<T> {
addr: MOpRegNum,
#[hdl(flip)]
data: HdlOption<T>,
}
let make_rename_table_read_port =
|mem: &mut MemBuilder<_>,
reg_range: std::ops::Range<u32>,
src_index: usize,
table_name: &str| {
let read_port = mem.new_read_port();
connect(read_port.clk, cd.clk);
connect_any(read_port.addr, 0u8);
connect(read_port.en, false);
let wire = wire_with_loc(
&format!("{table_name}_{fetch_index}_src_{src_index}"),
SourceLocation::caller(),
RenameTableReadPort[config.p_reg_num()],
);
connect(wire.addr, MOpRegNum::const_zero());
connect(wire.data, Expr::ty(wire.data).HdlNone());
#[hdl]
if wire.addr.value.cmp_ge(reg_range.start) & wire.addr.value.cmp_lt(reg_range.end) {
connect_any(read_port.addr, wire.addr.value - reg_range.start);
connect(read_port.en, true);
connect(wire.data, HdlSome(read_port.data));
for prev_fetch_index in 0..fetch_index {
#[hdl]
if let HdlSome(decoded_insn) =
fetch_decode_interface.decoded_insns[prev_fetch_index].data
{
#[hdl]
if let HdlSome(renamed_mop_out_reg) =
renamed_mops_out_reg[prev_fetch_index]
{
let dest_reg = MOpTrait::dest_reg(decoded_insn.mop);
for dest_reg in MOpDestReg::regs(dest_reg) {
#[hdl]
if dest_reg.value.cmp_eq(wire.addr.value) {
connect(wire.data, HdlSome(renamed_mop_out_reg));
}
}
}
}
}
}
wire
};
let rename_table_normal_read_ports: [_; COMMON_MOP_SRC_LEN] =
std::array::from_fn(|src_index| {
make_rename_table_read_port(
&mut rename_table_normal_mem,
MOpRegNum::NORMAL_REG_NUMS,
src_index,
"rename_table_normal",
)
});
let rename_table_special_read_ports: [_; COMMON_MOP_SRC_LEN] =
std::array::from_fn(|src_index| {
make_rename_table_read_port(
&mut rename_table_special_mem,
MOpRegNum::FLAG_REG_NUMS,
src_index,
"rename_table_special",
)
});
#[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)),
config.available_units_for_kind(MOp::kind(decoded_insn.mop)),
);
#[hdl]
if let HdlSome(renamed_mop_out_reg) = renamed_mops_out_reg[fetch_index] {
let dest_reg = MOpTrait::dest_reg(decoded_insn.mop);
connect(
renamed_mops[fetch_index],
HdlSome(MOpTrait::map_regs(
decoded_insn.mop,
renamed_mop_out_reg.unit_out_reg,
config.p_reg_num_width(),
&mut |src_reg, src_index| {
let src_reg = #[hdl]
MOpRegNum { value: src_reg };
let renamed_src_reg = wire_with_loc(
&format!("renamed_src_reg_{fetch_index}_{src_index}"),
SourceLocation::caller(),
config.p_reg_num(),
);
connect(rename_table_normal_read_ports[src_index].addr, src_reg);
connect(rename_table_special_read_ports[src_index].addr, src_reg);
#[hdl]
if let HdlSome(v) = rename_table_normal_read_ports[src_index].data {
connect(renamed_src_reg, v);
} else if let HdlSome(v) =
rename_table_special_read_ports[src_index].data
{
connect(renamed_src_reg, v);
} else {
connect(renamed_src_reg, config.p_reg_num().const_zero());
}
renamed_src_reg.cast_to_bits()
},
)),
);
// TODO: write dest_reg to rename table
// rename_table_mem.new_write_port()
}
}
connect(
selected_unit_nums[fetch_index],
selected_unit_indexes[fetch_index],
tree_reduce_with_state(
0..config.unit_kinds.len(),
&mut 0usize,
|_state, unit_index| {
let selected_unit_leaf = wire_with_loc(
&format!("selected_unit_leaf_{fetch_index}_{unit_index}"),
let selected_unit_index_leaf = wire_with_loc(
&format!("selected_unit_index_leaf_{fetch_index}_{unit_index}"),
SourceLocation::caller(),
HdlOption[config.unit_num()],
HdlOption[UInt[config.unit_num_width()]],
);
connect(selected_unit_leaf, HdlOption[config.unit_num()].HdlNone());
let unit_num = wire_with_loc(
&format!("unit_num_{fetch_index}_{unit_index}"),
connect(
selected_unit_index_leaf,
Expr::ty(selected_unit_index_leaf).HdlNone(),
);
let unit_index_wire = wire_with_loc(
&format!("unit_index_{fetch_index}_{unit_index}"),
SourceLocation::caller(),
config.unit_num(),
UInt[config.unit_num_width()],
);
connect_any(unit_num.value, unit_index);
connect_any(unit_index_wire, unit_index);
#[hdl]
if available_units[fetch_index][unit_index] {
connect(selected_unit_leaf, HdlSome(unit_num))
connect(selected_unit_index_leaf, HdlSome(unit_index_wire))
}
selected_unit_leaf
selected_unit_index_leaf
},
|state, l, r| {
let selected_unit_node = wire_with_loc(
&format!("selected_unit_node_{fetch_index}_{state}"),
let selected_unit_index_node = wire_with_loc(
&format!("selected_unit_index_node_{fetch_index}_{state}"),
SourceLocation::caller(),
Expr::ty(l),
);
*state += 1;
connect(selected_unit_node, l);
connect(selected_unit_index_node, l);
#[hdl]
if let HdlNone = l {
connect(selected_unit_node, r);
connect(selected_unit_index_node, r);
}
selected_unit_node
selected_unit_index_node
},
)
.expect("expected at least one unit"),
@ -120,14 +248,21 @@ pub fn reg_alloc(config: &CpuConfig) {
// TODO: handle assigning multiple instructions to a unit at a time
for later_fetch_index in fetch_index + 1..config.fetch_width.get() {
#[hdl]
if let HdlSome(selected_unit_num) = selected_unit_nums[fetch_index] {
if let HdlSome(selected_unit_index) = selected_unit_indexes[fetch_index] {
connect(
available_units[later_fetch_index][selected_unit_num.value],
available_units[later_fetch_index][selected_unit_index],
false,
);
}
}
}
connect(
renamed_mops_out_reg,
repeat(
HdlOption[config.p_reg_num()].HdlNone(),
config.fetch_width.get(),
),
);
for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() {
let dyn_unit = unit_kind.unit(config);
let unit = instance_with_loc(
@ -136,6 +271,7 @@ pub fn reg_alloc(config: &CpuConfig) {
SourceLocation::caller(),
);
connect(dyn_unit.cd(unit), cd);
let unit_input = dyn_unit.input(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
@ -156,6 +292,7 @@ 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());
for fetch_index in 0..config.fetch_width.get() {
#[hdl]
if let HdlNone = unit_free_regs_tracker.alloc_out[0].data {
@ -163,10 +300,45 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(available_units[fetch_index][unit_index], false);
}
#[hdl]
if let HdlSome(unit_num) = selected_unit_nums[fetch_index] {
if !unit_input.ready {
// must come after to override connects in loops above
connect(available_units[fetch_index][unit_index], false);
}
#[hdl]
if let HdlSome(selected_unit_index) = selected_unit_indexes[fetch_index] {
#[hdl]
if unit_num.value.cmp_eq(unit_index) {
if selected_unit_index.cmp_eq(unit_index) {
connect(unit_free_regs_tracker.alloc_out[0].ready, true);
#[hdl]
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));
} else {
connect(
unit_input.data,
HdlSome(Expr::ty(unit_input).data.HdlSome.uninit()),
);
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
}
#[hdl]
if let HdlSome(unit_out_reg) = unit_free_regs_tracker.alloc_out[0].data {
let unit_num = config.unit_num().from_index(unit_index);
let unit_out_reg = #[hdl]
UnitOutRegNum {
value: unit_out_reg,
};
connect(
renamed_mops_out_reg[fetch_index],
HdlSome(
#[hdl]
PRegNum {
unit_num,
unit_out_reg,
},
),
);
}
}
}
}

View file

@ -3,7 +3,9 @@
use crate::{
config::CpuConfig,
instruction::{AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, PRegNum},
instruction::{
mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, PRegNum, UnitOutRegNum,
},
register::PRegValue,
};
use fayalite::{
@ -21,9 +23,10 @@ macro_rules! all_units {
#[unit_kind = $UnitKind:ident]
#[hdl]
$(#[$enum_meta:meta])*
$vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> {
$vis:vis enum $UnitMOpEnum:ident<$DestReg:ident: Type, $SrcRegWidth:ident: Size> {
$(
#[create_dyn_unit_fn = $create_dyn_unit_fn:expr]
#[extract = $extract:ident]
$(#[$variant_meta:meta])*
$Unit:ident($Op:ty),
)*
@ -65,26 +68,43 @@ macro_rules! all_units {
)*
}
#[hdl]
$(#[$enum_meta])*
$vis enum $UnitMOpEnum<$RegWidth: Size> {
$(
$(#[$variant_meta])*
$Unit($Op),
)*
mop_enum! {
#[hdl]
$(#[$enum_meta])*
$vis enum $UnitMOpEnum<$DestReg: Type, $SrcRegWidth: Size> {
$(
$(#[$variant_meta])*
$Unit($Op),
)*
}
}
impl<$RegWidth: Size> $UnitMOpEnum<$RegWidth> {
impl<$DestReg: Type, $SrcRegWidth: Size> $UnitMOpEnum<$DestReg, $SrcRegWidth> {
#[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()),)*
$($UnitMOpEnum::<_, _>::$Unit(_) => connect(unit_kind, $HdlUnitKind.$Unit()),)*
}
unit_kind
}
$(
#[hdl]
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
let expr = expr.to_expr();
let ty = Expr::ty(expr);
#[hdl]
let $extract = wire(HdlOption[ty.$Unit]);
connect($extract, HdlOption[ty.$Unit].HdlNone());
#[hdl]
if let $UnitMOpEnum::<_, _>::$Unit(v) = expr {
connect($extract, HdlSome(v));
}
$extract
}
)*
}
impl CpuConfig {
@ -108,13 +128,16 @@ all_units! {
#[hdl_unit_kind = HdlUnitKind]
#[unit_kind = UnitKind]
#[hdl]
pub enum UnitMOp<RegWidth: Size> {
pub enum UnitMOp<DestReg: Type, SrcRegWidth: Size> {
#[create_dyn_unit_fn = |config| alu_branch::AluBranch::new(config).to_dyn()]
AluBranch(AluBranchMOp<RegWidth>),
#[extract = alu_branch_mop]
AluBranch(AluBranchMOp<DestReg, SrcRegWidth>),
#[create_dyn_unit_fn = |config| todo!()]
L2RegisterFile(L2RegisterFileMOp<RegWidth>),
#[extract = l2_register_file_mop]
L2RegisterFile(L2RegisterFileMOp<DestReg, SrcRegWidth>),
#[create_dyn_unit_fn = |config| todo!()]
LoadStore(LoadStoreMOp<RegWidth>),
#[extract = load_store_mop]
LoadStore(LoadStoreMOp<DestReg, SrcRegWidth>),
}
}
@ -159,9 +182,15 @@ pub trait UnitTrait:
fn unit_kind(&self) -> UnitKind;
fn extract_mop(
&self,
mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>>;
fn make_module(&self) -> Interned<Module<Self::Type>>;
// TODO: add other inputs
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>>;
fn cancel_input(
&self,
this: Expr<Self::Type>,
@ -214,10 +243,21 @@ impl UnitTrait for DynUnit {
self.unit_kind
}
fn extract_mop(
&self,
mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>> {
self.unit.extract_mop(mop)
}
fn make_module(&self) -> Interned<Module<Self::Type>> {
self.unit.make_module()
}
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
self.unit.input(this)
}
fn cancel_input(
&self,
this: Expr<Self::Type>,
@ -265,10 +305,21 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
self.0.unit_kind()
}
fn extract_mop(
&self,
mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>> {
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 input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
Expr::from_bundle(Expr::as_bundle(self.0.input(Expr::from_bundle(this))))
}
fn cancel_input(
&self,
this: Expr<Self::Type>,

View file

@ -3,8 +3,8 @@
use crate::{
config::CpuConfig,
instruction::AluBranchMOp,
unit::{DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitOutput, UnitTrait},
instruction::{AluBranchMOp, UnitOutRegNum},
unit::{DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitMOp, UnitOutput, UnitTrait},
};
use fayalite::{
intern::{Intern, Interned},
@ -16,7 +16,11 @@ use fayalite::{
pub fn alu_branch(config: &CpuConfig) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let input: ReadyValid<AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>> =
m.input(ReadyValid[AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()]]);
// TODO: finish
connect(input.ready, true);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -37,7 +41,7 @@ impl AluBranch {
impl UnitTrait for AluBranch {
type Type = alu_branch;
type ExtraOut = ();
type MOp = AluBranchMOp<DynSize>;
type MOp = AluBranchMOp<UnitOutRegNum<DynSize>, DynSize>;
fn ty(&self) -> Self::Type {
self.module.io_ty()
@ -48,17 +52,28 @@ impl UnitTrait for AluBranch {
}
fn mop_ty(&self) -> Self::MOp {
AluBranchMOp[self.config.p_reg_num().canonical().bit_width()]
self.module.io_ty().input.data.HdlSome
}
fn unit_kind(&self) -> UnitKind {
UnitKind::AluBranch
}
fn extract_mop(
&self,
mop: Expr<UnitMOp<UnitOutRegNum<DynSize>, DynSize>>,
) -> Expr<HdlOption<Self::MOp>> {
UnitMOp::alu_branch_mop(mop)
}
fn make_module(&self) -> Interned<Module<Self::Type>> {
self.module
}
fn input(&self, this: Expr<Self::Type>) -> Expr<ReadyValid<Self::MOp>> {
this.input
}
fn cancel_input(
&self,
this: Expr<Self::Type>,

View file

@ -5,7 +5,7 @@ pub mod tree_reduce;
pub(crate) const fn range_u32_len(range: &std::ops::Range<u32>) -> usize {
let retval = range.end.saturating_sub(range.start);
assert!(retval as usize as u32 != retval, "len overflowed");
assert!(retval as usize as u32 == retval, "len overflowed");
retval as usize
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff