From 12481cfab39158df4f031529fea4eae9bcac0466 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Fri, 20 Dec 2024 00:26:16 -0800 Subject: [PATCH] start debugging reg_alloc with simulator --- crates/cpu/src/config.rs | 19 +- crates/cpu/src/instruction.rs | 146 +++- crates/cpu/src/reg_alloc.rs | 12 +- crates/cpu/src/unit.rs | 4 +- crates/cpu/src/unit/alu_branch.rs | 83 +++ crates/cpu/tests/expected/reg_alloc.vcd | 880 ++++++++++++++++++++++++ crates/cpu/tests/reg_alloc.rs | 101 +++ scripts/check-copyright.sh | 3 + 8 files changed, 1211 insertions(+), 37 deletions(-) create mode 100644 crates/cpu/src/unit/alu_branch.rs create mode 100644 crates/cpu/tests/expected/reg_alloc.vcd create mode 100644 crates/cpu/tests/reg_alloc.rs diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index c7e2e25..9335f51 100644 --- a/crates/cpu/src/config.rs +++ b/crates/cpu/src/config.rs @@ -16,8 +16,25 @@ pub struct CpuConfig { } impl CpuConfig { + pub const DEFAULT_OUT_REG_NUM_WIDTH: usize = 4; + pub const DEFAULT_FETCH_WIDTH: NonZeroUsize = { + let Some(v) = NonZeroUsize::new(1) else { + unreachable!(); + }; + v + }; + pub fn new(unit_kinds: Vec) -> Self { + Self { + unit_kinds, + out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH, + fetch_width: Self::DEFAULT_FETCH_WIDTH, + } + } + pub fn non_const_unit_nums(&self) -> std::ops::Range { + (CONST_ZERO_UNIT_NUM + 1)..(self.unit_kinds.len() + 1) + } pub fn unit_num_width(&self) -> usize { - UInt::range((CONST_ZERO_UNIT_NUM + 1)..self.unit_kinds.len()).width() + UInt::range(self.non_const_unit_nums()).width() } pub fn unit_num(&self) -> UnitNum { UnitNum[self.unit_num_width()] diff --git a/crates/cpu/src/instruction.rs b/crates/cpu/src/instruction.rs index af6d96b..5810c90 100644 --- a/crates/cpu/src/instruction.rs +++ b/crates/cpu/src/instruction.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::unit::UnitMOp; -use fayalite::prelude::*; +use fayalite::{expr::ops::ArrayLiteral, intern::Interned, prelude::*}; use std::marker::PhantomData; pub mod power_isa; @@ -20,58 +20,138 @@ pub enum OutputIntegerMode { pub const MOP_IMM_WIDTH: usize = 34; pub const MOP_MIN_REG_WIDTH: usize = 8; -pub const COMMON_MOP_OTHER_WIDTH: usize = - MOP_IMM_WIDTH - (COMMON_MOP_SRC_REG_COUNT - COMMON_MOP_IMM_SRC_REG_COUNT) * MOP_MIN_REG_WIDTH; -pub const COMMON_MOP_SRC_REG_COUNT: usize = 3; -pub const COMMON_MOP_IMM_SRC_REG_COUNT: usize = 2; +pub const COMMON_MOP_SRC_LEN: usize = 3; +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 { pub prefix_pad: UIntType, pub dest: UIntType, - pub src: Array, { COMMON_MOP_SRC_REG_COUNT }>, - pub other: UInt<{ COMMON_MOP_OTHER_WIDTH }>, + pub src: Array, { COMMON_MOP_SRC_LEN }>, + pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>, + pub imm_sign: SInt<1>, pub _phantom: PhantomData, } +#[hdl] +pub struct CommonMOpImmParts { + // fields must be in this exact order + pub imm_low: UInt<{ COMMON_MOP_IMM_LOW_WIDTH }>, + pub reversed_src: ArrayType, ImmInSrcCount>, + pub imm_sign: SInt<1>, +} + +type CommonMOpWithMaxSrcCount = CommonMOpForImm<{ COMMON_MOP_SRC_LEN }>; + +type CommonMOpForImm = + CommonMOp, ConstUsize<{ MOP_MIN_REG_WIDTH }>, ConstUsize>; + +pub const COMMON_MOP_0_IMM_WIDTH: usize = CommonMOpForImm::<0>::IMM_WIDTH; +pub const COMMON_MOP_1_IMM_WIDTH: usize = CommonMOpForImm::<1>::IMM_WIDTH; +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 CommonMOp { - pub fn imm_ty(self) -> SInt { - assert!(self.src.element().width() >= MOP_MIN_REG_WIDTH); - assert!(SrcCount::VALUE <= COMMON_MOP_SRC_REG_COUNT); - SInt[(COMMON_MOP_SRC_REG_COUNT - SrcCount::VALUE) * MOP_MIN_REG_WIDTH - + COMMON_MOP_OTHER_WIDTH] + pub const IMM_IN_SRC_COUNT: usize = { + assert!(SrcCount::VALUE <= COMMON_MOP_SRC_LEN, "too many sources"); + const _: () = assert!(COMMON_MOP_MIN_SRC_LEN_WITH_FULL_IMM <= COMMON_MOP_SRC_LEN); + (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 = + (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 + }; + pub fn imm_ty() -> SInt { + SInt::new(Self::IMM_WIDTH) + } + pub fn imm_parts_ty() -> CommonMOpImmParts { + let retval = CommonMOpImmParts[Self::IMM_IN_SRC_COUNT]; + assert_eq!( + retval.canonical().bit_width(), + Self::IMM_WIDTH, + "{retval:#?}" + ); + retval + } + #[hdl] + pub fn new( + prefix_pad: impl ToExpr>, + dest: impl ToExpr>, + src: impl ToExpr, SrcCount>>, + imm: impl ToExpr, + ) -> Expr { + let prefix_pad = prefix_pad.to_expr(); + let dest = dest.to_expr(); + 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 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]; + 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); + } + #[hdl] + Self { + prefix_pad, + dest, + src: ArrayLiteral::new( + reg_ty, + Interned::from_iter(src.iter().map(|v| Expr::canonical(*v))), + ) + .to_expr(), + imm_low: Expr::from_dyn_int(imm[..COMMON_MOP_IMM_LOW_WIDTH]), + imm_sign: Expr::from_dyn_int(imm >> (Self::IMM_WIDTH - 1)), + _phantom: PhantomData, + } } #[hdl] pub fn imm(expr: impl ToExpr) -> Expr { let expr = expr.to_expr(); - assert!(Expr::ty(expr).src.element().width() >= MOP_MIN_REG_WIDTH); - let mut acc = expr.other[..COMMON_MOP_OTHER_WIDTH - 1]; - for i in SrcCount::VALUE..COMMON_MOP_SRC_REG_COUNT { - acc = (acc, expr.src[i][..MOP_MIN_REG_WIDTH]).cast_to_bits(); - } - acc = (acc, expr.other[COMMON_MOP_OTHER_WIDTH - 1]).cast_to_bits(); - #[hdl] - let imm = wire(Expr::ty(expr).imm_ty()); - debug_assert_eq!(Expr::ty(acc).width(), Expr::ty(imm).width()); - connect(imm, acc.cast_to(Expr::ty(imm))); - imm + let reversed_src = Vec::from_iter( + Self::IMM_IN_SRC_RANGE + .rev() + .map(|src_index| expr.src[src_index].cast_to_static()), + ); + let imm_parts = { + #[hdl] + CommonMOpImmParts { + imm_low: expr.imm_low, + reversed_src, + imm_sign: expr.imm_sign, + } + }; + imm_parts.cast_to_bits().cast_bits_to(Self::imm_ty()) } #[hdl] pub fn connect_to_imm(expr: impl ToExpr, imm: impl ToExpr) { let expr = expr.to_expr(); + let reg_ty = Expr::ty(expr).dest; + assert_eq!(reg_ty, Expr::ty(expr).src.element()); let imm = imm.to_expr(); - let imm_ty = Expr::ty(expr).imm_ty(); - assert_eq!(Expr::ty(imm), imm_ty); - let mut pos = COMMON_MOP_OTHER_WIDTH - 1; - connect_any( - expr.other, - (imm[..pos], imm[imm_ty.width() - 1]).cast_to_bits(), - ); - for i in SrcCount::VALUE..COMMON_MOP_SRC_REG_COUNT { - connect_any(expr.src[i], imm[pos..pos + MOP_MIN_REG_WIDTH]); - pos += MOP_MIN_REG_WIDTH; + 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]; + 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)); + } + for i in 0..COMMON_MOP_SRC_LEN { + if let Some(v) = src[i] { + connect(expr.src[i], v); + } } } } diff --git a/crates/cpu/src/reg_alloc.rs b/crates/cpu/src/reg_alloc.rs index 684c47b..61c5188 100644 --- a/crates/cpu/src/reg_alloc.rs +++ b/crates/cpu/src/reg_alloc.rs @@ -2,9 +2,9 @@ // See Notices.txt for copyright information use crate::{ config::CpuConfig, - instruction::{MOp, UnitNum}, + instruction::MOp, unit::{TrapData, UnitTrait}, - util::tree_reduce::{tree_reduce, tree_reduce_with_state}, + util::tree_reduce::tree_reduce_with_state, }; use fayalite::{module::instance_with_loc, prelude::*, util::ready_valid::ReadyValid}; use std::num::NonZeroUsize; @@ -124,5 +124,13 @@ pub fn reg_alloc(config: &CpuConfig) { ); connect(unit_free_regs_tracker.cd, cd); // TODO: finish + connect( + unit_free_regs_tracker.free_in[0].data, + HdlOption[UInt[config.out_reg_num_width]].uninit(), // FIXME: just for debugging + ); + connect( + unit_free_regs_tracker.alloc_out[0].ready, + Bool.uninit(), // FIXME: just for debugging + ); } } diff --git a/crates/cpu/src/unit.rs b/crates/cpu/src/unit.rs index 14e8cd7..a6bcaeb 100644 --- a/crates/cpu/src/unit.rs +++ b/crates/cpu/src/unit.rs @@ -13,6 +13,8 @@ use fayalite::{ util::ready_valid::ReadyValid, }; +pub mod alu_branch; + macro_rules! all_units { ( #[hdl_unit_kind = $HdlUnitKind:ident] @@ -107,7 +109,7 @@ all_units! { #[unit_kind = UnitKind] #[hdl] pub enum UnitMOp { - #[create_dyn_unit_fn = |config| todo!()] + #[create_dyn_unit_fn = |config| alu_branch::AluBranch::new(config).to_dyn()] AluBranch(AluBranchMOp), #[create_dyn_unit_fn = |config| todo!()] L2RegisterFile(L2RegisterFileMOp), diff --git a/crates/cpu/src/unit/alu_branch.rs b/crates/cpu/src/unit/alu_branch.rs new file mode 100644 index 0000000..d98ca40 --- /dev/null +++ b/crates/cpu/src/unit/alu_branch.rs @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use crate::{ + config::CpuConfig, + instruction::AluBranchMOp, + unit::{DynUnit, DynUnitWrapper, UnitCancelInput, UnitKind, UnitOutput, UnitTrait}, +}; +use fayalite::{ + intern::{Intern, Interned}, + prelude::*, + util::ready_valid::ReadyValid, +}; + +#[hdl_module] +pub fn alu_branch(config: &CpuConfig) { + #[hdl] + let cd: ClockDomain = m.input(); + // TODO: finish +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct AluBranch { + config: Interned, + module: Interned>, +} + +impl AluBranch { + pub fn new(config: &CpuConfig) -> Self { + Self { + config: config.intern(), + module: alu_branch(config), + } + } +} + +impl UnitTrait for AluBranch { + type Type = alu_branch; + type ExtraOut = (); + type MOp = AluBranchMOp; + + fn ty(&self) -> Self::Type { + self.module.io_ty() + } + + fn extra_out_ty(&self) -> Self::ExtraOut { + () + } + + fn mop_ty(&self) -> Self::MOp { + AluBranchMOp[self.config.p_reg_num().canonical().bit_width()] + } + + fn unit_kind(&self) -> UnitKind { + UnitKind::AluBranch + } + + fn make_module(&self) -> Interned> { + self.module + } + + fn cancel_input( + &self, + this: Expr, + ) -> Expr>> { + todo!() + } + + fn output( + &self, + this: Expr, + ) -> Expr>> { + todo!() + } + + fn cd(&self, this: Expr) -> Expr { + this.cd + } + + fn to_dyn(&self) -> DynUnit { + DynUnitWrapper(*self).to_dyn() + } +} diff --git a/crates/cpu/tests/expected/reg_alloc.vcd b/crates/cpu/tests/expected/reg_alloc.vcd new file mode 100644 index 0000000..ea43839 --- /dev/null +++ b/crates/cpu/tests/expected/reg_alloc.vcd @@ -0,0 +1,880 @@ +$timescale 1 ps $end +$scope module reg_alloc $end +$scope struct cd $end +$var wire 1 ! clk $end +$var wire 1 " rst $end +$upscope $end +$scope struct fetch_decode_interface $end +$scope struct decoded_insns $end +$scope struct [0] $end +$scope struct data $end +$var string 1 # \$tag $end +$scope struct HdlSome $end +$scope struct uop $end +$var string 1 $ \$tag $end +$scope struct AluBranch $end +$var string 1 % \$tag $end +$scope struct AddSub $end +$scope struct alu_common $end +$scope struct common $end +$var string 0 & prefix_pad $end +$var wire 8 ' dest $end +$scope struct src $end +$var wire 8 ( \[0] $end +$var wire 8 ) \[1] $end +$var wire 8 * \[2] $end +$upscope $end +$var wire 25 + imm_low $end +$var wire 1 , imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$var string 1 - output_integer_mode $end +$upscope $end +$var wire 1 . invert_src0 $end +$var wire 1 / invert_carry_in $end +$var wire 1 0 invert_carry_out $end +$var wire 1 1 add_pc $end +$upscope $end +$scope struct AddSubI $end +$scope struct alu_common $end +$scope struct common $end +$var string 0 2 prefix_pad $end +$var wire 8 3 dest $end +$scope struct src $end +$var wire 8 4 \[0] $end +$var wire 8 5 \[1] $end +$var wire 8 6 \[2] $end +$upscope $end +$var wire 25 7 imm_low $end +$var wire 1 8 imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$var string 1 9 output_integer_mode $end +$upscope $end +$var wire 1 : invert_src0 $end +$var wire 1 ; invert_carry_in $end +$var wire 1 < invert_carry_out $end +$var wire 1 = add_pc $end +$upscope $end +$scope struct Logical $end +$scope struct alu_common $end +$scope struct common $end +$var string 0 > prefix_pad $end +$var wire 8 ? dest $end +$scope struct src $end +$var wire 8 @ \[0] $end +$var wire 8 A \[1] $end +$var wire 8 B \[2] $end +$upscope $end +$var wire 25 C imm_low $end +$var wire 1 D imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$var string 1 E output_integer_mode $end +$upscope $end +$var wire 4 F lut $end +$upscope $end +$upscope $end +$scope struct L2RegisterFile $end +$var string 1 G \$tag $end +$scope struct ReadL2Reg $end +$scope struct common $end +$var wire 1 H prefix_pad $end +$var wire 8 I dest $end +$scope struct src $end +$var wire 8 J \[0] $end +$var wire 8 K \[1] $end +$var wire 8 L \[2] $end +$upscope $end +$var wire 25 M imm_low $end +$var wire 1 N imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$upscope $end +$scope struct WriteL2Reg $end +$scope struct common $end +$var wire 1 O prefix_pad $end +$var wire 8 P dest $end +$scope struct src $end +$var wire 8 Q \[0] $end +$var wire 8 R \[1] $end +$var wire 8 S \[2] $end +$upscope $end +$var wire 25 T imm_low $end +$var wire 1 U imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$scope struct LoadStore $end +$var string 1 V \$tag $end +$scope struct Load $end +$var wire 1 W prefix_pad $end +$var wire 8 X dest $end +$scope struct src $end +$var wire 8 Y \[0] $end +$var wire 8 Z \[1] $end +$var wire 8 [ \[2] $end +$upscope $end +$var wire 25 \ imm_low $end +$var wire 1 ] imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$scope struct Store $end +$var wire 1 ^ prefix_pad $end +$var wire 8 _ dest $end +$scope struct src $end +$var wire 8 ` \[0] $end +$var wire 8 a \[1] $end +$var wire 8 b \[2] $end +$upscope $end +$var wire 25 c imm_low $end +$var wire 1 d imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$var wire 1 e is_unrelated_pc $end +$var wire 64 f pc $end +$upscope $end +$upscope $end +$var wire 1 g ready $end +$upscope $end +$scope struct [1] $end +$scope struct data $end +$var string 1 h \$tag $end +$scope struct HdlSome $end +$scope struct uop $end +$var string 1 i \$tag $end +$scope struct AluBranch $end +$var string 1 j \$tag $end +$scope struct AddSub $end +$scope struct alu_common $end +$scope struct common $end +$var string 0 k prefix_pad $end +$var wire 8 l dest $end +$scope struct src $end +$var wire 8 m \[0] $end +$var wire 8 n \[1] $end +$var wire 8 o \[2] $end +$upscope $end +$var wire 25 p imm_low $end +$var wire 1 q imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$var string 1 r output_integer_mode $end +$upscope $end +$var wire 1 s invert_src0 $end +$var wire 1 t invert_carry_in $end +$var wire 1 u invert_carry_out $end +$var wire 1 v add_pc $end +$upscope $end +$scope struct AddSubI $end +$scope struct alu_common $end +$scope struct common $end +$var string 0 w prefix_pad $end +$var wire 8 x dest $end +$scope struct src $end +$var wire 8 y \[0] $end +$var wire 8 z \[1] $end +$var wire 8 { \[2] $end +$upscope $end +$var wire 25 | imm_low $end +$var wire 1 } imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$var string 1 ~ output_integer_mode $end +$upscope $end +$var wire 1 !" invert_src0 $end +$var wire 1 "" invert_carry_in $end +$var wire 1 #" invert_carry_out $end +$var wire 1 $" add_pc $end +$upscope $end +$scope struct Logical $end +$scope struct alu_common $end +$scope struct common $end +$var string 0 %" prefix_pad $end +$var wire 8 &" dest $end +$scope struct src $end +$var wire 8 '" \[0] $end +$var wire 8 (" \[1] $end +$var wire 8 )" \[2] $end +$upscope $end +$var wire 25 *" imm_low $end +$var wire 1 +" imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$var string 1 ," output_integer_mode $end +$upscope $end +$var wire 4 -" lut $end +$upscope $end +$upscope $end +$scope struct L2RegisterFile $end +$var string 1 ." \$tag $end +$scope struct ReadL2Reg $end +$scope struct common $end +$var wire 1 /" prefix_pad $end +$var wire 8 0" dest $end +$scope struct src $end +$var wire 8 1" \[0] $end +$var wire 8 2" \[1] $end +$var wire 8 3" \[2] $end +$upscope $end +$var wire 25 4" imm_low $end +$var wire 1 5" imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$upscope $end +$scope struct WriteL2Reg $end +$scope struct common $end +$var wire 1 6" prefix_pad $end +$var wire 8 7" dest $end +$scope struct src $end +$var wire 8 8" \[0] $end +$var wire 8 9" \[1] $end +$var wire 8 :" \[2] $end +$upscope $end +$var wire 25 ;" imm_low $end +$var wire 1 <" imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$scope struct LoadStore $end +$var string 1 =" \$tag $end +$scope struct Load $end +$var wire 1 >" prefix_pad $end +$var wire 8 ?" dest $end +$scope struct src $end +$var wire 8 @" \[0] $end +$var wire 8 A" \[1] $end +$var wire 8 B" \[2] $end +$upscope $end +$var wire 25 C" imm_low $end +$var wire 1 D" imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$scope struct Store $end +$var wire 1 E" prefix_pad $end +$var wire 8 F" dest $end +$scope struct src $end +$var wire 8 G" \[0] $end +$var wire 8 H" \[1] $end +$var wire 8 I" \[2] $end +$upscope $end +$var wire 25 J" imm_low $end +$var wire 1 K" imm_sign $end +$scope struct _phantom $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$var wire 1 L" is_unrelated_pc $end +$var wire 64 M" pc $end +$upscope $end +$upscope $end +$var wire 1 N" ready $end +$upscope $end +$upscope $end +$scope struct fetch_decode_special_op $end +$scope struct data $end +$var string 1 O" \$tag $end +$scope struct HdlSome $end +$var string 1 P" \$tag $end +$scope struct Trap $end +$upscope $end +$upscope $end +$upscope $end +$var wire 1 Q" ready $end +$upscope $end +$upscope $end +$scope struct available_units $end +$scope struct [0] $end +$var wire 1 R" \[0] $end +$upscope $end +$scope struct [1] $end +$var wire 1 S" \[0] $end +$upscope $end +$upscope $end +$scope struct selected_unit_nums $end +$scope struct [0] $end +$var string 1 T" \$tag $end +$scope struct HdlSome $end +$var wire 1 U" value $end +$upscope $end +$upscope $end +$scope struct [1] $end +$var string 1 V" \$tag $end +$scope struct HdlSome $end +$var wire 1 W" value $end +$upscope $end +$upscope $end +$upscope $end +$var string 1 X" unit_kind $end +$scope struct available_units_for_kind $end +$var wire 1 Y" \[0] $end +$upscope $end +$scope struct selected_unit_leaf $end +$var string 1 Z" \$tag $end +$scope struct HdlSome $end +$var wire 1 [" value $end +$upscope $end +$upscope $end +$scope struct unit_num $end +$var wire 1 \" value $end +$upscope $end +$var string 1 ]" unit_kind $end +$scope struct available_units_for_kind $end +$var wire 1 ^" \[0] $end +$upscope $end +$scope struct selected_unit_leaf $end +$var string 1 _" \$tag $end +$scope struct HdlSome $end +$var wire 1 `" value $end +$upscope $end +$upscope $end +$scope struct unit_num $end +$var wire 1 a" value $end +$upscope $end +$scope struct unit_0 $end +$scope struct cd $end +$var wire 1 d" clk $end +$var wire 1 e" rst $end +$upscope $end +$upscope $end +$scope module alu_branch $end +$scope struct cd $end +$var wire 1 b" clk $end +$var wire 1 c" rst $end +$upscope $end +$upscope $end +$scope struct unit_0_free_regs_tracker $end +$scope struct cd $end +$var wire 1 Q# clk $end +$var wire 1 R# rst $end +$upscope $end +$scope struct free_in $end +$scope struct [0] $end +$scope struct data $end +$var string 1 S# \$tag $end +$var wire 4 T# HdlSome $end +$upscope $end +$var wire 1 U# ready $end +$upscope $end +$upscope $end +$scope struct alloc_out $end +$scope struct [0] $end +$scope struct data $end +$var string 1 V# \$tag $end +$var wire 4 W# HdlSome $end +$upscope $end +$var wire 1 X# ready $end +$upscope $end +$upscope $end +$upscope $end +$scope module unit_free_regs_tracker $end +$scope struct cd $end +$var wire 1 f" clk $end +$var wire 1 g" rst $end +$upscope $end +$scope struct free_in $end +$scope struct [0] $end +$scope struct data $end +$var string 1 h" \$tag $end +$var wire 4 i" HdlSome $end +$upscope $end +$var wire 1 j" ready $end +$upscope $end +$upscope $end +$scope struct alloc_out $end +$scope struct [0] $end +$scope struct data $end +$var string 1 k" \$tag $end +$var wire 4 l" HdlSome $end +$upscope $end +$var wire 1 m" ready $end +$upscope $end +$upscope $end +$scope struct allocated_reg $end +$var reg 1 n" \[0] $end +$var reg 1 o" \[1] $end +$var reg 1 p" \[2] $end +$var reg 1 q" \[3] $end +$var reg 1 r" \[4] $end +$var reg 1 s" \[5] $end +$var reg 1 t" \[6] $end +$var reg 1 u" \[7] $end +$var reg 1 v" \[8] $end +$var reg 1 w" \[9] $end +$var reg 1 x" \[10] $end +$var reg 1 y" \[11] $end +$var reg 1 z" \[12] $end +$var reg 1 {" \[13] $end +$var reg 1 |" \[14] $end +$var reg 1 }" \[15] $end +$upscope $end +$scope struct firing_data $end +$var string 1 ~" \$tag $end +$var wire 4 !# HdlSome $end +$upscope $end +$var wire 1 "# reduced_count_0_2 $end +$var wire 1 ## reduced_count_overflowed_0_2 $end +$scope struct reduced_alloc_nums_0_2 $end +$var wire 1 $# \[0] $end +$upscope $end +$var wire 1 %# reduced_count_2_4 $end +$var wire 1 &# reduced_count_overflowed_2_4 $end +$scope struct reduced_alloc_nums_2_4 $end +$var wire 1 '# \[0] $end +$upscope $end +$var wire 1 (# reduced_count_0_4 $end +$var wire 1 )# reduced_count_overflowed_0_4 $end +$scope struct reduced_alloc_nums_0_4 $end +$var wire 2 *# \[0] $end +$upscope $end +$var wire 1 +# reduced_count_4_6 $end +$var wire 1 ,# reduced_count_overflowed_4_6 $end +$scope struct reduced_alloc_nums_4_6 $end +$var wire 1 -# \[0] $end +$upscope $end +$var wire 1 .# reduced_count_6_8 $end +$var wire 1 /# reduced_count_overflowed_6_8 $end +$scope struct reduced_alloc_nums_6_8 $end +$var wire 1 0# \[0] $end +$upscope $end +$var wire 1 1# reduced_count_4_8 $end +$var wire 1 2# reduced_count_overflowed_4_8 $end +$scope struct reduced_alloc_nums_4_8 $end +$var wire 2 3# \[0] $end +$upscope $end +$var wire 1 4# reduced_count_0_8 $end +$var wire 1 5# reduced_count_overflowed_0_8 $end +$scope struct reduced_alloc_nums_0_8 $end +$var wire 3 6# \[0] $end +$upscope $end +$var wire 1 7# reduced_count_8_10 $end +$var wire 1 8# reduced_count_overflowed_8_10 $end +$scope struct reduced_alloc_nums_8_10 $end +$var wire 1 9# \[0] $end +$upscope $end +$var wire 1 :# reduced_count_10_12 $end +$var wire 1 ;# reduced_count_overflowed_10_12 $end +$scope struct reduced_alloc_nums_10_12 $end +$var wire 1 <# \[0] $end +$upscope $end +$var wire 1 =# reduced_count_8_12 $end +$var wire 1 ># reduced_count_overflowed_8_12 $end +$scope struct reduced_alloc_nums_8_12 $end +$var wire 2 ?# \[0] $end +$upscope $end +$var wire 1 @# reduced_count_12_14 $end +$var wire 1 A# reduced_count_overflowed_12_14 $end +$scope struct reduced_alloc_nums_12_14 $end +$var wire 1 B# \[0] $end +$upscope $end +$var wire 1 C# reduced_count_14_16 $end +$var wire 1 D# reduced_count_overflowed_14_16 $end +$scope struct reduced_alloc_nums_14_16 $end +$var wire 1 E# \[0] $end +$upscope $end +$var wire 1 F# reduced_count_12_16 $end +$var wire 1 G# reduced_count_overflowed_12_16 $end +$scope struct reduced_alloc_nums_12_16 $end +$var wire 2 H# \[0] $end +$upscope $end +$var wire 1 I# reduced_count_8_16 $end +$var wire 1 J# reduced_count_overflowed_8_16 $end +$scope struct reduced_alloc_nums_8_16 $end +$var wire 3 K# \[0] $end +$upscope $end +$var wire 1 L# reduced_count_0_16 $end +$var wire 1 M# reduced_count_overflowed_0_16 $end +$scope struct reduced_alloc_nums_0_16 $end +$var wire 4 N# \[0] $end +$upscope $end +$scope struct firing_data $end +$var string 1 O# \$tag $end +$var wire 4 P# HdlSome $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +1" +sHdlSome\x20(1) # +sAluBranch\x20(0) $ +sAddSub\x20(0) % +s0 & +b1 ' +b10 ( +b11 ) +b100 * +b1001000110100 + +0, +sFull64\x20(0) - +1. +1/ +10 +11 +s0 2 +b1 3 +b10 4 +b11 5 +b100 6 +b1001000110100 7 +08 +sFull64\x20(0) 9 +1: +1; +1< +1= +s0 > +b1 ? +b10 @ +b11 A +b100 B +b1001000110100 C +0D +sFull64\x20(0) E +b1111 F +sReadL2Reg\x20(0) G +0H +b1 I +b10 J +b11 K +b100 L +b1001000110100 M +0N +0O +b1 P +b10 Q +b11 R +b100 S +b1001000110100 T +0U +sLoad\x20(0) V +0W +b1 X +b10 Y +b11 Z +b100 [ +b1001000110100 \ +0] +0^ +b1 _ +b10 ` +b11 a +b100 b +b1001000110100 c +0d +1e +b1000000000000 f +1g +sHdlSome\x20(1) h +sAluBranch\x20(0) i +sLogical\x20(2) j +s0 k +b10 l +b11 m +b100 n +b0 o +b0 p +0q +sFull64\x20(0) r +0s +1t +1u +0v +s0 w +b10 x +b11 y +b100 z +b0 { +b0 | +0} +sFull64\x20(0) ~ +0!" +1"" +1#" +0$" +s0 %" +b10 &" +b11 '" +b100 (" +b0 )" +b0 *" +0+" +sFull64\x20(0) ," +b110 -" +sReadL2Reg\x20(0) ." +1/" +b10 0" +b11 1" +b100 2" +b0 3" +b0 4" +05" +16" +b10 7" +b11 8" +b100 9" +b0 :" +b0 ;" +0<" +sLoad\x20(0) =" +1>" +b10 ?" +b11 @" +b100 A" +b0 B" +b0 C" +0D" +1E" +b10 F" +b11 G" +b100 H" +b0 I" +b0 J" +0K" +0L" +b1000000000100 M" +1N" +sHdlNone\x20(0) O" +sTrap\x20(0) P" +1Q" +1R" +1S" +sHdlSome\x20(1) T" +0U" +sHdlSome\x20(1) V" +0W" +sAluBranch\x20(0) X" +1Y" +sHdlSome\x20(1) Z" +0[" +0\" +sAluBranch\x20(0) ]" +1^" +sHdlSome\x20(1) _" +0`" +0a" +0b" +1c" +0d" +1e" +0f" +1g" +sHdlNone\x20(0) h" +b0 i" +1j" +sHdlSome\x20(1) k" +b0 l" +0m" +0n" +0o" +0p" +0q" +0r" +0s" +0t" +0u" +0v" +0w" +0x" +0y" +0z" +0{" +0|" +0}" +sHdlNone\x20(0) ~" +b0 !# +0"# +1## +0$# +0%# +1&# +0'# +0(# +1)# +b0 *# +0+# +1,# +0-# +0.# +1/# +00# +01# +12# +b0 3# +04# +15# +b0 6# +07# +18# +09# +0:# +1;# +0<# +0=# +1># +b0 ?# +0@# +1A# +0B# +0C# +1D# +0E# +0F# +1G# +b0 H# +0I# +1J# +b0 K# +0L# +1M# +b0 N# +sHdlNone\x20(0) O# +b0 P# +0Q# +1R# +sHdlNone\x20(0) S# +b0 T# +1U# +sHdlSome\x20(1) V# +b0 W# +0X# +$end +#500000 +1! +1b" +1d" +1f" +1Q# +#1000000 +0! +0" +0b" +0c" +0d" +0e" +0f" +0g" +0Q# +0R# +#1500000 +1! +1b" +1d" +1f" +1Q# +#2000000 +0! +0b" +0d" +0f" +0Q# +#2500000 +1! +1b" +1d" +1f" +1Q# +#3000000 +0! +0b" +0d" +0f" +0Q# +#3500000 +1! +1b" +1d" +1f" +1Q# +#4000000 +0! +0b" +0d" +0f" +0Q# +#4500000 +1! +1b" +1d" +1f" +1Q# +#5000000 +0! +0b" +0d" +0f" +0Q# +#5500000 +1! +1b" +1d" +1f" +1Q# +#6000000 +0! +0b" +0d" +0f" +0Q# +#6500000 +1! +1b" +1d" +1f" +1Q# +#7000000 +0! +0b" +0d" +0f" +0Q# +#7500000 +1! +1b" +1d" +1f" +1Q# +#8000000 +0! +0b" +0d" +0f" +0Q# +#8500000 +1! +1b" +1d" +1f" +1Q# +#9000000 +0! +0b" +0d" +0f" +0Q# +#9500000 +1! +1b" +1d" +1f" +1Q# +#10000000 diff --git a/crates/cpu/tests/reg_alloc.rs b/crates/cpu/tests/reg_alloc.rs new file mode 100644 index 0000000..975a73e --- /dev/null +++ b/crates/cpu/tests/reg_alloc.rs @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +use cpu::{ + config::CpuConfig, + instruction::{ + AddSubMOp, AluCommonMOp, CommonMOp, LogicalMOp, MOp, OutputIntegerMode, + COMMON_MOP_2_IMM_WIDTH, COMMON_MOP_3_IMM_WIDTH, + }, + reg_alloc::{reg_alloc, FetchedDecodedMOp}, + unit::UnitKind, +}; +use fayalite::{ + prelude::*, + sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation}, + util::RcWriter, +}; +use std::num::NonZeroUsize; + +#[hdl] +#[test] +fn test_reg_alloc() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut config = CpuConfig::new(vec![UnitKind::AluBranch]); + config.fetch_width = NonZeroUsize::new(2).unwrap(); + let mut sim = Simulation::new(reg_alloc(&config)); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + let fetch_decode_interface = sim.io().fetch_decode_interface; + sim.write_clock(sim.io().cd.clk, false); + sim.write_reset(sim.io().cd.rst, true); + sim.write_bool(fetch_decode_interface.fetch_decode_special_op.ready, true); + sim.write( + fetch_decode_interface.decoded_insns[0].data, + HdlSome( + #[hdl] + FetchedDecodedMOp { + uop: MOp.AluBranch(MOp.AluBranch.AddSub( + #[hdl] + AddSubMOp { + alu_common: #[hdl] + AluCommonMOp { + common: CommonMOp::new( + 0_hdl_u0, + 1u8, + [2u8, 3u8, 4u8], + 0x1234.cast_to(SInt[COMMON_MOP_3_IMM_WIDTH]), + ), + output_integer_mode: OutputIntegerMode.Full64(), + }, + invert_src0: true, + invert_carry_in: true, + invert_carry_out: true, + add_pc: true, + }, + )), + is_unrelated_pc: true, + pc: 0x1000_hdl_u64, + }, + ), + ); + sim.write( + fetch_decode_interface.decoded_insns[1].data, + HdlSome( + #[hdl] + FetchedDecodedMOp { + uop: MOp.AluBranch(MOp.AluBranch.Logical( + #[hdl] + LogicalMOp { + alu_common: #[hdl] + AluCommonMOp { + common: CommonMOp::new( + 0_hdl_u0, + 2u8, + [3u8, 4u8], + SInt[COMMON_MOP_2_IMM_WIDTH].zero(), + ), + output_integer_mode: OutputIntegerMode.Full64(), + }, + lut: 0b0110_hdl_u4, + }, + )), + is_unrelated_pc: false, + pc: 0x1004_hdl_u64, + }, + ), + ); + for cycle in 0..10 { + sim.advance_time(SimDuration::from_nanos(500)); + sim.write_clock(sim.io().cd.clk, true); + sim.advance_time(SimDuration::from_nanos(500)); + sim.write_clock(sim.io().cd.clk, false); + sim.write_reset(sim.io().cd.rst, false); + } + // FIXME: vcd is just whatever reg_alloc does now, which isn't known to be correct + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("expected/reg_alloc.vcd") { + panic!(); + } +} diff --git a/scripts/check-copyright.sh b/scripts/check-copyright.sh index 5acfdf9..65c2081 100755 --- a/scripts/check-copyright.sh +++ b/scripts/check-copyright.sh @@ -45,6 +45,9 @@ function main() */LICENSE.md|*/Notices.txt) # copyright file ;; + /crates/cpu/tests/expected/*.vcd) + # file that can't contain copyright header + ;; /.forgejo/workflows/*.yml|*/.gitignore|*.toml) check_file "$file" "${POUND_HEADER[@]}" ;;