diff --git a/Cargo.lock b/Cargo.lock index 3b2d648..67bc26e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -207,6 +207,8 @@ name = "cpu" version = "0.1.0" dependencies = [ "fayalite", + "name_mangling_serde", + "serde", ] [[package]] @@ -300,7 +302,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fayalite" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#450e1004b6eef6fcdce74a94e3bded3e0268610d" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8" dependencies = [ "bitvec", "blake3", @@ -325,7 +327,7 @@ dependencies = [ [[package]] name = "fayalite-proc-macros" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#450e1004b6eef6fcdce74a94e3bded3e0268610d" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8" dependencies = [ "fayalite-proc-macros-impl", ] @@ -333,7 +335,7 @@ dependencies = [ [[package]] name = "fayalite-proc-macros-impl" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#450e1004b6eef6fcdce74a94e3bded3e0268610d" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8" dependencies = [ "base16ct", "num-bigint", @@ -348,7 +350,7 @@ dependencies = [ [[package]] name = "fayalite-visit-gen" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#450e1004b6eef6fcdce74a94e3bded3e0268610d" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#d453755bb2cd0b6f2340f3e49058d29a2ee279e8" dependencies = [ "indexmap", "prettyplease", diff --git a/Cargo.toml b/Cargo.toml index 94355a7..38cade6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ categories = [] rust-version = "1.82.0" [workspace.dependencies] +name_mangling_serde = { version = "=0.1.0", path = "crates/name_mangling_serde" } fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" } serde = { version = "1.0.202", features = ["derive"] } serde_json = { version = "1.0.117", features = ["preserve_order"] } diff --git a/crates/cpu/Cargo.toml b/crates/cpu/Cargo.toml index 783981d..9ff26c3 100644 --- a/crates/cpu/Cargo.toml +++ b/crates/cpu/Cargo.toml @@ -16,6 +16,8 @@ version.workspace = true [dependencies] fayalite.workspace = true +serde.workspace = true +name_mangling_serde.workspace = true [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(todo)'] } diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index d008b13..6a0d27a 100644 --- a/crates/cpu/src/config.rs +++ b/crates/cpu/src/config.rs @@ -1,17 +1,17 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information use crate::{ - instruction::{MOpTrait, PRegNum, RenamedMOp, UnitNum, UnitOutRegNum, CONST_ZERO_UNIT_NUM}, - unit::{ - unit_base::{ExecuteEnd, ExecuteStart}, - RenamedInsnData, RetireQueueIndex, UnitForwardingInfo, UnitKind, UnitOutputWrite, - UnitToRegAlloc, - }, + instruction::{PRegNum, CONST_ZERO_UNIT_NUM}, + unit::UnitKind, }; -use fayalite::prelude::*; +use fayalite::{ + intern::{Intern, Interned}, + prelude::*, +}; +use serde::{Deserialize, Serialize}; use std::num::NonZeroUsize; -#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] #[non_exhaustive] pub struct UnitConfig { pub kind: UnitKind, @@ -28,10 +28,10 @@ impl UnitConfig { } } -#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] #[non_exhaustive] pub struct CpuConfig { - pub units: Vec, + pub units: Interned<[UnitConfig]>, pub out_reg_num_width: usize, pub fetch_width: NonZeroUsize, /// default value for [`UnitConfig::max_in_flight`] @@ -52,7 +52,7 @@ impl CpuConfig { }; v }; - pub fn new(units: Vec) -> Self { + pub fn new(units: Interned<[UnitConfig]>) -> Self { Self { units, out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH, @@ -66,70 +66,83 @@ impl CpuConfig { pub fn unit_num_width(&self) -> usize { UInt::range(CONST_ZERO_UNIT_NUM..self.non_const_unit_nums().end).width() } - pub fn unit_num(&self) -> UnitNum { - UnitNum[self.unit_num_width()] - } - pub fn unit_out_reg_num(&self) -> UnitOutRegNum { - UnitOutRegNum[self.out_reg_num_width] - } - pub fn p_reg_num(&self) -> PRegNum { - 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 renamed_mop(&self) -> RenamedMOp { - RenamedMOp[self.p_reg_num_width()] - } - pub fn unit_output_write(&self) -> UnitOutputWrite { - UnitOutputWrite[self.out_reg_num_width] - } - pub fn unit_output_writes(&self) -> Array>> { - Array[HdlOption[self.unit_output_write()]][self.non_const_unit_nums().len()] - } - pub fn unit_forwarding_info(&self) -> UnitForwardingInfo { - 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) } - pub fn unit_to_reg_alloc< - MOp: Type + MOpTrait, - ExtraOut: Type, - >( - &self, - mop_ty: MOp, - extra_out_ty: ExtraOut, - ) -> UnitToRegAlloc { - UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width] - [self.non_const_unit_nums().len()][self.retire_queue_index_width()] - } pub fn retire_queue_index_width(&self) -> usize { let max_in_flight: usize = (0..self.units.len()) .map(|unit_index| self.unit_max_in_flight(unit_index).get()) .sum(); 2 + max_in_flight.next_power_of_two().ilog2() as usize } - pub fn retire_queue_index(&self) -> RetireQueueIndex { - RetireQueueIndex[self.retire_queue_index_width()] - } - pub fn renamed_insn_data( - &self, - mop: MOp, - dest: DestReg, - ) -> RenamedInsnData { - RenamedInsnData[mop][dest][self.retire_queue_index_width()] - } - pub fn execute_start(&self, mop: MOp) -> ExecuteStart { - ExecuteStart[mop][self.out_reg_num_width][self.retire_queue_index_width()] - } - pub fn execute_end( - &self, - extra_out_ty: ExtraOut, - ) -> ExecuteEnd { - ExecuteEnd[self.out_reg_num_width][self.retire_queue_index_width()][extra_out_ty] +} + +mod sealed { + pub trait Sealed {} +} + +impl sealed::Sealed for PhantomConst {} + +pub trait CpuConfigType: Type + ToExpr + sealed::Sealed { + fn get(self) -> Interned; +} + +impl CpuConfigType for PhantomConst { + fn get(self) -> Interned { + self.get() } } + +pub trait Identity { + type SelfType: ?Sized; + type ArgType: ?Sized; +} + +impl Identity for T { + type SelfType = T; + type ArgType = Arg; +} + +macro_rules! impl_cpu_config_accessors { + ( + $( + #[without_generics = $without_generics:ident] + $vis:vis type $ident:ident<$T:ident> = |$arg:ident| $expr:expr; + )* + ) => { + $( + #[allow(non_camel_case_types)] + $vis struct $without_generics; + + #[allow(non_upper_case_globals)] + $vis const $ident: $without_generics = $without_generics; + + $vis type $ident<$T> = >::SelfType; + + impl<$T: CpuConfigType> std::ops::Index<$T> for $without_generics { + type Output = usize; + + fn index(&self, $arg: $T) -> &Self::Output { + Interned::into_inner(Intern::intern_sized($expr)) + } + } + )* + }; +} + +impl_cpu_config_accessors! { + #[without_generics = __UnitNumWidth_WithoutGenerics] + pub type UnitNumWidth = |arg| arg.get().unit_num_width(); + #[without_generics = __UnitOutRegNumWidth_WithoutGenerics] + pub type UnitOutRegNumWidth = |arg| arg.get().out_reg_num_width; + #[without_generics = __PRegNumWidth_WithoutGenerics] + pub type PRegNumWidth = |arg| PRegNum[arg].canonical().bit_width(); + #[without_generics = __RetireQueueIndexWidth_WithoutGenerics] + pub type RetireQueueIndexWidth = |arg| arg.get().retire_queue_index_width(); + #[without_generics = __UnitCount_WithoutGenerics] + pub type UnitCount = |arg| arg.get().non_const_unit_nums().len(); + #[without_generics = __FetchWidth_WithoutGenerics] + pub type FetchWidth = |arg| arg.get().fetch_width.get(); +} diff --git a/crates/cpu/src/instruction.rs b/crates/cpu/src/instruction.rs index 7021a2c..0d85ff9 100644 --- a/crates/cpu/src/instruction.rs +++ b/crates/cpu/src/instruction.rs @@ -1,6 +1,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use crate::{unit::UnitMOp, util::range_u32_len}; +use crate::{ + config::{CpuConfigType, UnitNumWidth, UnitOutRegNumWidth}, + unit::UnitMOp, + util::range_u32_len, +}; use fayalite::{ expr::ops::{ArrayLiteral, ExprPartialEq}, intern::Interned, @@ -805,19 +809,21 @@ common_mop_struct! { } } -#[hdl(cmp_eq)] +#[hdl(cmp_eq, no_static)] /// 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 { - pub adj_value: UIntType, +pub struct UnitNum { + pub adj_value: UIntType>, + pub config: C, } -impl UnitNum { +impl UnitNum { #[hdl] pub fn const_zero(self) -> Expr { #[hdl] UnitNum { adj_value: CONST_ZERO_UNIT_NUM.cast_to(self.adj_value), + config: self.config, } } #[hdl] @@ -825,6 +831,7 @@ impl UnitNum { #[hdl] UnitNum { adj_value: (index + 1).cast_to(self.adj_value), + config: self.config, } } pub fn is_index(expr: impl ToExpr, index: usize) -> Expr { @@ -835,7 +842,7 @@ impl UnitNum { .cmp_eq(expr.adj_value) } #[hdl] - pub fn as_index(expr: impl ToExpr) -> Expr>> { + pub fn as_index(expr: impl ToExpr) -> Expr>> { let expr = expr.to_expr(); #[hdl] let unit_index = wire(HdlOption[Expr::ty(expr).adj_value]); @@ -853,19 +860,20 @@ impl UnitNum { pub const CONST_ZERO_UNIT_NUM: usize = 0; -#[hdl(cmp_eq)] -pub struct UnitOutRegNum { - pub value: UIntType, +#[hdl(cmp_eq, no_static)] +pub struct UnitOutRegNum { + pub value: UIntType>, + pub config: C, } -#[hdl(cmp_eq)] +#[hdl(cmp_eq, no_static)] /// Physical Register Number -- registers in the CPU's backend -pub struct PRegNum { - pub unit_num: UnitNum, - pub unit_out_reg: UnitOutRegNum, +pub struct PRegNum { + pub unit_num: UnitNum, + pub unit_out_reg: UnitOutRegNum, } -impl PRegNum { +impl PRegNum { #[hdl] pub fn const_zero(self) -> Expr { #[hdl] @@ -874,6 +882,7 @@ impl PRegNum { +#[hdl(no_static)] +pub struct InstructionRenameInputInsn { pub mop: MOp, pub pc: UInt<64>, - pub renamed_dest: PRegNum, + pub renamed_dest: PRegNum, } -impl CpuConfig { - pub fn instruction_rename_input_insn(&self) -> InstructionRenameInputInsn { - InstructionRenameInputInsn[self.unit_num_width()][self.out_reg_num_width] - } +#[hdl(no_static)] +struct InsnsInPrefixSummary { + all_ready: Bool, + ready_count: Length>, + retire_queue_used: Length>, + config: C, } +type C = PhantomConst; + #[hdl] -struct InsnsInPrefixSummary { - all_ready: Bool, - ready_count: Length, - retire_queue_used: Length, -} +pub type InstructionRenameInsnsOut = ArrayType< + ReadyValid>, PRegNum>>, + FetchWidth, +>; #[hdl_module] -pub fn instruction_rename(config: &CpuConfig) { +pub fn instruction_rename(config: PhantomConst) { #[hdl] let cd: ClockDomain = m.input(); #[hdl] - let insns_in: ReadyValidArray, DynSize> = - m.input(ReadyValidArray[config.instruction_rename_input_insn()][config.fetch_width.get()]); + let insns_in: ReadyValidArray, FetchWidth> = + m.input(ReadyValidArray[InstructionRenameInputInsn[config]][FetchWidth[config]]); #[hdl] - let start_retire_queue_index: RetireQueueIndex = m.input(config.retire_queue_index()); + let start_retire_queue_index: RetireQueueIndex = m.input(RetireQueueIndex[config]); #[hdl] - let end_retire_queue_index: RetireQueueIndex = m.output(config.retire_queue_index()); + let end_retire_queue_index: RetireQueueIndex = m.output(RetireQueueIndex[config]); #[hdl] - let insns_out: Array< - ReadyValid, PRegNum, DynSize>>, - > = m.output( - Array[ReadyValid[config.renamed_insn_data(config.renamed_mop(), config.p_reg_num())]] - [config.fetch_width.get()], - ); + let insns_out: InstructionRenameInsnsOut = m.output(InstructionRenameInsnsOut[config]); // TODO: handle resetting table after cancelling instructions #[hdl] - let insns_ready_or_move = wire(Array[Bool][config.fetch_width.get()]); + let insns_ready_or_move = wire(ArrayType[Bool][FetchWidth[config]]); for (insn_ready_or_move, insn_out) in insns_ready_or_move.into_iter().zip(insns_out) { connect(insn_ready_or_move, insn_out.ready); @@ -71,12 +69,11 @@ pub fn instruction_rename(config: &CpuConfig) { } }); - let insns_in_prefix_summary_ty = InsnsInPrefixSummary[config.fetch_width.get()]; + let insns_in_prefix_summary_ty = InsnsInPrefixSummary[config]; #[hdl] - let insns_in_prefix_summaries = - wire(Array[insns_in_prefix_summary_ty][config.fetch_width.get()]); + let insns_in_prefix_summaries = wire(ArrayType[insns_in_prefix_summary_ty][FetchWidth[config]]); let insns_in_prefix_summaries_vec = PrefixSumAlgorithm::WorkEfficient.run( - (0..config.fetch_width.get()).map(|fetch_index| { + (0..FetchWidth[config]).map(|fetch_index| { #[hdl] let insns_in_prefix_summary_in = wire(insns_in_prefix_summary_ty); #[hdl] @@ -84,6 +81,7 @@ pub fn instruction_rename(config: &CpuConfig) { all_ready, ready_count, retire_queue_used, + config: _, } = insns_in_prefix_summary_in; connect(all_ready, insns_out[fetch_index].ready); connect( @@ -112,6 +110,7 @@ pub fn instruction_rename(config: &CpuConfig) { all_ready, ready_count, retire_queue_used, + config: _, } = insns_in_prefix_summary_merge; connect(all_ready, l.all_ready & r.all_ready); #[hdl] @@ -143,16 +142,15 @@ pub fn instruction_rename(config: &CpuConfig) { } connect( insns_in.ready, - insns_in_prefix_summaries[config.fetch_width.get() - 1].ready_count, + insns_in_prefix_summaries[FetchWidth[config] - 1].ready_count, ); #[hdl] - let retire_queue_indexes = - wire(Array[config.retire_queue_index()][config.fetch_width.get() + 1]); + let retire_queue_indexes = wire(Array[RetireQueueIndex[config]][FetchWidth[config] + 1]); connect(retire_queue_indexes[0], start_retire_queue_index); connect( end_retire_queue_index, - retire_queue_indexes[config.fetch_width.get()], + retire_queue_indexes[FetchWidth[config]], ); for (retire_queue_index, insns_in_prefix_summary) in retire_queue_indexes .into_iter() @@ -171,7 +169,7 @@ pub fn instruction_rename(config: &CpuConfig) { MOpTrait::for_each_src_reg(MOp.uninit(), &mut |_, src_index| { src_reg_count = src_reg_count.max(src_index + 1); }); - for _ in 0..config.fetch_width.get() { + for _ in 0..FetchWidth[config] { for _ in 0..src_reg_count { port_configs.push(RenameTablePortConfig::Read { addr_range: MOpRegNum::NON_CONST_REG_NUMS, @@ -194,7 +192,7 @@ pub fn instruction_rename(config: &CpuConfig) { } for write_port in rename_table.write_ports { connect_any(write_port.addr, 0_hdl_u0); - connect_any(write_port.data, config.p_reg_num().const_zero()); + connect_any(write_port.data, PRegNum[config].const_zero()); } ArrayVec::for_each( @@ -203,16 +201,13 @@ pub fn instruction_rename(config: &CpuConfig) { let read_port_index = fetch_index * src_reg_count; let write_port_index = fetch_index * MOpDestReg::REG_COUNT; #[hdl] - let InstructionRenameInputInsn::<_, _> { + let InstructionRenameInputInsn::<_> { mop, pc, renamed_dest, } = input_insn; - let insn_out = MOpTrait::map_regs( - mop, - (), - config.p_reg_num_width(), - &mut |src_reg, src_index| { + let insn_out = + MOpTrait::map_regs(mop, (), PRegNumWidth[config], &mut |src_reg, src_index| { connect( rename_table.read_ports[read_port_index + src_index].addr, src_reg.cast_bits_to(MOpRegNum), @@ -220,8 +215,7 @@ pub fn instruction_rename(config: &CpuConfig) { rename_table.read_ports[read_port_index + src_index] .data .cast_to_bits() - }, - ); + }); for (i, dest_reg) in MOpDestReg::regs(MOpTrait::dest_reg(mop)) .into_iter() .enumerate() @@ -237,13 +231,13 @@ pub fn instruction_rename(config: &CpuConfig) { } let insn_out = UnitMOp::try_with_transformed_move_op( insn_out, - config.renamed_mop().TransformedMove, + RenamedMOp[PRegNumWidth[config]].TransformedMove, |insn_out: Expr>, move_reg: Expr>| { for i in 0..MOpDestReg::REG_COUNT { // execute move by using same PRegNum as src[0] for dest connect( rename_table.write_ports[write_port_index + i].data, - move_reg.common.src[0].cast_bits_to(config.p_reg_num()), + move_reg.common.src[0].cast_bits_to(PRegNum[config]), ); } // move already executed, so remove it diff --git a/crates/cpu/src/rename_table.rs b/crates/cpu/src/rename_table.rs index b88f696..a38e4aa 100644 --- a/crates/cpu/src/rename_table.rs +++ b/crates/cpu/src/rename_table.rs @@ -2,7 +2,7 @@ // See Notices.txt for copyright information use crate::{ - config::CpuConfig, + config::{CpuConfig, CpuConfigType}, instruction::{MOpRegNum, PRegNum}, util::range_intersection, }; @@ -13,17 +13,17 @@ use fayalite::{ }; use std::{mem, ops::Range}; -#[hdl] -pub struct RenameTableReadPort { +#[hdl(no_static)] +pub struct RenameTableReadPort { pub addr: MOpRegNum, #[hdl(flip)] - pub data: PRegNum, + pub data: PRegNum, } -#[hdl] -pub struct RenameTableWritePort { +#[hdl(no_static)] +pub struct RenameTableWritePort { pub addr: MOpRegNum, - pub data: PRegNum, + pub data: PRegNum, } #[derive(Clone, Debug)] @@ -32,6 +32,8 @@ pub enum RenameTablePortConfig { Write { addr_range: Range }, } +type C = PhantomConst; + /// register rename table. /// all read/write operations are done in the order of `port_configs`. /// So if `port_configs[0]` is a write and `port_configs[1]` is a read, @@ -40,7 +42,7 @@ pub enum RenameTablePortConfig { /// is a read and `port_configs[1]` is a write, then the read port will /// not see the data written by the write port until the *next* clock cycle. #[hdl_module] -pub fn rename_table(config: &CpuConfig, port_configs: &[RenameTablePortConfig]) { +pub fn rename_table(config: PhantomConst, port_configs: &[RenameTablePortConfig]) { let read_count = port_configs .iter() .filter(|v| matches!(v, RenameTablePortConfig::Read { .. })) @@ -53,16 +55,14 @@ pub fn rename_table(config: &CpuConfig, port_configs: &[RenameTablePortConfig]) #[hdl] let cd: ClockDomain = m.input(); #[hdl] - let read_ports: Array> = m.input( - Array[RenameTableReadPort[config.unit_num_width()][config.out_reg_num_width]][read_count], - ); + let read_ports: Array> = + m.input(Array[RenameTableReadPort[config]][read_count]); #[hdl] - let write_ports: Array> = m.input( - Array[RenameTableWritePort[config.unit_num_width()][config.out_reg_num_width]][write_count], - ); + let write_ports: Array> = + m.input(Array[RenameTableWritePort[config]][write_count]); for read_port in read_ports { - connect(read_port.data, config.p_reg_num().const_zero()); + connect(read_port.data, PRegNum[config].const_zero()); } let port_configs_and_indexes = port_configs.iter().scan( @@ -103,7 +103,7 @@ pub fn rename_table(config: &CpuConfig, port_configs: &[RenameTablePortConfig]) } else { format!("mem_{:#x}_{:#x}", cur_addr_range.start, cur_addr_range.end) }, - config.p_reg_num(), + PRegNum[config], SourceLocation::caller(), ); mem.depth(cur_addr_range.len()); diff --git a/crates/cpu/src/retire_queue.rs b/crates/cpu/src/retire_queue.rs index 062e770..e19f5a1 100644 --- a/crates/cpu/src/retire_queue.rs +++ b/crates/cpu/src/retire_queue.rs @@ -4,9 +4,13 @@ use crate::config::CpuConfig; use fayalite::prelude::*; +#[hdl] +pub struct RenameRetireInterface {} + #[hdl_module] pub fn retire_queue(config: &CpuConfig) { #[hdl] let cd: ClockDomain = m.input(); + todo!(); } diff --git a/crates/cpu/src/unit.rs b/crates/cpu/src/unit.rs index dbe5315..7985081 100644 --- a/crates/cpu/src/unit.rs +++ b/crates/cpu/src/unit.rs @@ -2,7 +2,7 @@ // See Notices.txt for copyright information use crate::{ - config::CpuConfig, + config::{CpuConfig, CpuConfigType, RetireQueueIndexWidth, UnitCount}, instruction::{ mop_enum, AluBranchMOp, LoadStoreMOp, MOp, MOpDestReg, MOpInto, MOpRegNum, MOpTrait, RenamedMOp, UnitOutRegNum, @@ -16,7 +16,7 @@ use fayalite::{ prelude::*, util::ready_valid::ReadyValid, }; -use std::marker::PhantomData; +use serde::{Deserialize, Serialize}; pub mod alu_branch; pub mod unit_base; @@ -38,7 +38,7 @@ macro_rules! all_units { } ) => { $(#[$enum_meta])* - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)] $vis enum $UnitKind { $( $(#[$variant_meta])* @@ -47,7 +47,7 @@ macro_rules! all_units { } impl $UnitKind { - pub fn unit(self, config: &CpuConfig, unit_index: usize) -> DynUnit { + pub fn unit(self, config: PhantomConst, unit_index: usize) -> DynUnit { match self { $($UnitKind::$Unit => $create_dyn_unit_fn(config, unit_index),)* } @@ -261,20 +261,21 @@ pub struct GlobalState { } /// index into the retire queue (the queue of instructions that haven't yet retired) -#[hdl(cmp_eq)] -pub struct RetireQueueIndex { +#[hdl(cmp_eq, no_static)] +pub struct RetireQueueIndex { /// increases by one for each instruction added to the retire queue. /// /// this wraps around, so you must not compare it using `cmp_lt`/`cmp_gt` /// but instead must use [`Self::insns_until`] and compare the output with zero. - pub index: UIntType, + pub index: UIntType>, + pub config: C, } -impl RetireQueueIndex { +impl RetireQueueIndex { pub fn insns_until( this: impl ToExpr, target: impl ToExpr, - ) -> Expr> { + ) -> Expr>> { let this = this.to_expr(); let target = target.to_expr(); assert_eq!(Expr::ty(this), Expr::ty(target)); @@ -282,50 +283,32 @@ impl RetireQueueIndex { } } -#[hdl] -pub struct RenamedInsnData { - pub retire_queue_index: RetireQueueIndex, +#[hdl(no_static)] +pub struct RenamedInsnData { + pub retire_queue_index: RetireQueueIndex, pub pc: UInt<64>, pub dest: DestReg, pub mop: MOp, } -#[hdl] -pub struct UnitForwardingInfo { - pub unit_output_writes: ArrayType>, UnitCount>, - pub unit_reg_frees: ArrayType>, UnitCount>, - pub _phantom: PhantomData, +#[hdl(no_static)] +pub struct UnitForwardingInfo { + pub unit_output_writes: ArrayType>, UnitCount>, + pub unit_reg_frees: ArrayType>, UnitCount>, } -#[hdl] -pub struct UnitToRegAlloc< - MOp: Type, - ExtraOut: Type, - UnitNumWidth: Size, - OutRegNumWidth: Size, - UnitCount: Size, - RetireQueueIndexWidth: Size, -> { +#[hdl(no_static)] +pub struct UnitToRegAlloc { #[hdl(flip)] - pub unit_forwarding_info: UnitForwardingInfo, + pub unit_forwarding_info: UnitForwardingInfo, #[hdl(flip)] - pub input: - ReadyValid, RetireQueueIndexWidth>>, + pub input: ReadyValid>>, #[hdl(flip)] - pub cancel_input: HdlOption>, - pub output: HdlOption>, + pub cancel_input: HdlOption>, + pub output: HdlOption>, } -impl< - MOp: Type, - ExtraOut: Type, - UnitNumWidth: Size, - OutRegNumWidth: Size, - UnitCount: Size, - RetireQueueIndexWidth: Size, - > - UnitToRegAlloc -{ +impl UnitToRegAlloc { pub fn mop_ty(self) -> MOp { self.input.data.HdlSome.mop } @@ -340,12 +323,16 @@ pub struct UnitResultCompleted { pub extra_out: ExtraOut, } -#[hdl(cmp_eq)] -pub struct UnitOutputWrite { - pub dest: UnitOutRegNum, +#[hdl(cmp_eq, no_static)] +pub struct UnitOutputWrite { + pub dest: UnitOutRegNum, pub value: PRegValue, } +#[hdl] +pub type UnitOutputWrites = + ArrayType>, UnitCount>; + #[hdl(cmp_eq)] pub struct TrapData { // TODO @@ -363,30 +350,28 @@ impl UnitResult { } } -#[hdl] -pub struct UnitOutput { - pub dest: UnitOutRegNum, - pub retire_queue_index: RetireQueueIndex, +#[hdl(no_static)] +pub struct UnitOutput { + pub dest: UnitOutRegNum, + pub retire_queue_index: RetireQueueIndex, pub result: UnitResult, } -impl - UnitOutput -{ +impl UnitOutput { pub fn extra_out_ty(self) -> ExtraOut { self.result.extra_out_ty() } } -#[hdl(cmp_eq)] -pub struct UnitCancelInput { - pub target: RetireQueueIndex, +#[hdl(cmp_eq, no_static)] +pub struct UnitCancelInput { + pub target: RetireQueueIndex, } -impl UnitCancelInput { +impl UnitCancelInput { pub fn is_canceled( this: impl ToExpr, - insn_retire_queue_index: impl ToExpr>, + insn_retire_queue_index: impl ToExpr>, ) -> Expr { RetireQueueIndex::insns_until(insn_retire_queue_index, this.to_expr().target).cmp_ge(0i8) } @@ -412,7 +397,7 @@ pub trait UnitTrait: fn unit_to_reg_alloc( &self, this: Expr, - ) -> Expr>; + ) -> Expr, Self::MOp, Self::ExtraOut>>; fn cd(&self, this: Expr) -> Expr; @@ -471,7 +456,7 @@ impl UnitTrait for DynUnit { fn unit_to_reg_alloc( &self, this: Expr, - ) -> Expr> { + ) -> Expr, Self::MOp, Self::ExtraOut>> { self.unit.unit_to_reg_alloc(this) } @@ -523,7 +508,7 @@ impl UnitTrait for DynUnitWrapper, - ) -> Expr> { + ) -> Expr, Self::MOp, Self::ExtraOut>> { Expr::from_bundle(Expr::as_bundle( self.0.unit_to_reg_alloc(Expr::from_bundle(this)), )) diff --git a/crates/cpu/src/unit/alu_branch.rs b/crates/cpu/src/unit/alu_branch.rs index 2ffa23c..63d85af 100644 --- a/crates/cpu/src/unit/alu_branch.rs +++ b/crates/cpu/src/unit/alu_branch.rs @@ -2,7 +2,7 @@ // See Notices.txt for copyright information use crate::{ - config::CpuConfig, + config::{CpuConfig, PRegNumWidth}, instruction::{ AddSubMOp, AluBranchMOp, AluCommonMOp, CommonMOp, LogicalMOp, OutputIntegerMode, RenamedMOp, COMMON_MOP_SRC_LEN, @@ -15,10 +15,7 @@ use crate::{ }, }; use fayalite::{ - intern::{Intern, Interned}, - module::wire_with_loc, - prelude::*, - util::ready_valid::ReadyValid, + intern::Interned, module::wire_with_loc, prelude::*, util::ready_valid::ReadyValid, }; use std::{collections::HashMap, ops::RangeTo}; @@ -245,18 +242,15 @@ fn logical( } #[hdl_module] -pub fn alu_branch(config: &CpuConfig, unit_index: usize) { +pub fn alu_branch(config: PhantomConst, unit_index: usize) { #[hdl] let cd: ClockDomain = m.input(); #[hdl] let unit_to_reg_alloc: UnitToRegAlloc< + PhantomConst, AluBranchMOp<(), DynSize>, (), - DynSize, - DynSize, - DynSize, - DynSize, - > = m.output(config.unit_to_reg_alloc(AluBranchMOp[()][config.p_reg_num_width()], ())); + > = m.output(UnitToRegAlloc[config][AluBranchMOp[()][PRegNumWidth[config]]][()]); #[hdl] let global_state: GlobalState = m.input(); @@ -277,16 +271,16 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) { #[hdl] if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) { #[hdl] - let ExecuteStart::<_, _, _> { insn, src_values } = execute_start; + let ExecuteStart::<_, _> { insn, src_values } = execute_start; #[hdl] match insn.mop { AluBranchMOp::<_, _>::AddSub(mop) => connect( unit_base.execute_end, HdlSome( #[hdl] - ExecuteEnd::<_, _, _> { + ExecuteEnd::<_, _> { unit_output: #[hdl] - UnitOutput::<_, _, _> { + UnitOutput::<_, _> { dest: insn.dest, retire_queue_index: insn.retire_queue_index, result: UnitResult[()].Completed(add_sub( @@ -303,9 +297,9 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) { unit_base.execute_end, HdlSome( #[hdl] - ExecuteEnd::<_, _, _> { + ExecuteEnd::<_, _> { unit_output: #[hdl] - UnitOutput::<_, _, _> { + UnitOutput::<_, _> { dest: insn.dest, retire_queue_index: insn.retire_queue_index, result: UnitResult[()].Completed(add_sub( @@ -322,9 +316,9 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) { unit_base.execute_end, HdlSome( #[hdl] - ExecuteEnd::<_, _, _> { + ExecuteEnd::<_, _> { unit_output: #[hdl] - UnitOutput::<_, _, _> { + UnitOutput::<_, _> { dest: insn.dest, retire_queue_index: insn.retire_queue_index, result: UnitResult[()].Completed(logical( @@ -342,14 +336,14 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct AluBranch { - config: Interned, + config: PhantomConst, module: Interned>, } impl AluBranch { - pub fn new(config: &CpuConfig, unit_index: usize) -> Self { + pub fn new(config: PhantomConst, unit_index: usize) -> Self { Self { - config: config.intern(), + config, module: alu_branch(config, unit_index), } } @@ -387,7 +381,7 @@ impl UnitTrait for AluBranch { fn unit_to_reg_alloc( &self, this: Expr, - ) -> Expr> { + ) -> Expr, Self::MOp, Self::ExtraOut>> { this.unit_to_reg_alloc } diff --git a/crates/cpu/src/unit/unit_base.rs b/crates/cpu/src/unit/unit_base.rs index 86b83e7..13a14fe 100644 --- a/crates/cpu/src/unit/unit_base.rs +++ b/crates/cpu/src/unit/unit_base.rs @@ -2,7 +2,7 @@ // See Notices.txt for copyright information use crate::{ - config::CpuConfig, + config::{CpuConfig, CpuConfigType, UnitOutRegNumWidth}, instruction::{MOpTrait, PRegNum, UnitNum, UnitOutRegNum, COMMON_MOP_SRC_LEN}, register::PRegValue, unit::{ @@ -18,15 +18,15 @@ use fayalite::{ util::{prefix_sum::reduce, ready_valid::ReadyValid}, }; -#[hdl] -pub struct ExecuteStart { - pub insn: RenamedInsnData, RetireQueueIndexWidth>, +#[hdl(no_static)] +pub struct ExecuteStart { + pub insn: RenamedInsnData>, pub src_values: Array, } -#[hdl] -pub struct ExecuteEnd { - pub unit_output: UnitOutput, +#[hdl(no_static)] +pub struct ExecuteEnd { + pub unit_output: UnitOutput, } #[hdl] @@ -106,10 +106,10 @@ impl InFlightOpState { } } -#[hdl] -struct InFlightOp { +#[hdl(no_static)] +struct InFlightOp { state: InFlightOpState, - insn: RenamedInsnData, RetireQueueIndexWidth>, + insn: RenamedInsnData>, src_ready_flags: Array, } @@ -124,7 +124,7 @@ impl InFlightOpsSummary { fn new( op_index: usize, op_index_ty: UIntType, - in_flight_op: impl ToExpr>>, + in_flight_op: impl ToExpr, MOp>>>, ) -> Expr { let empty_op_index = wire_with_loc( &format!("empty_op_index_{op_index}"), @@ -141,7 +141,7 @@ impl InFlightOpsSummary { #[hdl] if let HdlSome(in_flight_op) = in_flight_op { #[hdl] - let InFlightOp::<_, _, _> { + let InFlightOp::<_, _> { state, insn: _, src_ready_flags, @@ -182,7 +182,7 @@ impl InFlightOpsSummary { impl InFlightOpsSummary { fn summarize( in_flight_ops: impl ToExpr< - Type = ArrayType>, MaxInFlight>, + Type = ArrayType, MOp>>, MaxInFlight>, >, ) -> Expr { let in_flight_ops = in_flight_ops.to_expr(); @@ -199,7 +199,7 @@ impl InFlightOpsSummary { #[hdl_module] pub fn unit_base, ExtraOut: Type>( - config: &CpuConfig, + config: PhantomConst, unit_index: usize, mop_ty: MOp, extra_out_ty: ExtraOut, @@ -207,20 +207,19 @@ pub fn unit_base, Extr #[hdl] let cd: ClockDomain = m.input(); #[hdl] - let unit_to_reg_alloc: UnitToRegAlloc = - m.output(config.unit_to_reg_alloc(mop_ty, extra_out_ty)); + let unit_to_reg_alloc: UnitToRegAlloc, MOp, ExtraOut> = + m.output(UnitToRegAlloc[config][mop_ty][extra_out_ty]); #[hdl] - let execute_start: ReadyValid> = - m.output(ReadyValid[config.execute_start(mop_ty)]); + let execute_start: ReadyValid, MOp>> = + m.output(ReadyValid[ExecuteStart[config][mop_ty]]); #[hdl] - let execute_end: HdlOption> = - m.input(HdlOption[config.execute_end(extra_out_ty)]); + let execute_end: HdlOption, ExtraOut>> = + m.input(HdlOption[ExecuteEnd[config][extra_out_ty]]); connect(execute_start.data, Expr::ty(execute_start).data.HdlNone()); - let max_in_flight = config.unit_max_in_flight(unit_index).get(); - let in_flight_op_ty = - InFlightOp[mop_ty][config.out_reg_num_width][config.retire_queue_index_width()]; + let max_in_flight = config.get().unit_max_in_flight(unit_index).get(); + let in_flight_op_ty = InFlightOp[config][mop_ty]; #[hdl] let in_flight_ops = reg_builder() .clock_domain(cd) @@ -237,16 +236,15 @@ pub fn unit_base, Extr ); #[hdl] - let UnitForwardingInfo::<_, _, _> { + let UnitForwardingInfo::<_> { unit_output_writes, unit_reg_frees, - _phantom: _, } = unit_to_reg_alloc.unit_forwarding_info; #[hdl] let read_src_regs = wire(mop_ty.src_regs_ty()); connect( read_src_regs, - repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize), + repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize), ); #[hdl] let read_src_values = wire(); @@ -255,7 +253,7 @@ pub fn unit_base, Extr let input_src_regs = wire(mop_ty.src_regs_ty()); connect( input_src_regs, - repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize), + repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize), ); #[hdl] let input_src_regs_valid = wire(); @@ -267,7 +265,7 @@ pub fn unit_base, Extr Bool, SourceLocation::caller(), ); - mem.depth(1 << config.out_reg_num_width); + mem.depth(1 << UnitOutRegNumWidth[config]); mem }) .collect(); @@ -277,11 +275,11 @@ pub fn unit_base, Extr PRegValue, SourceLocation::caller(), ); - unit_output_regs.depth(1 << config.out_reg_num_width); + unit_output_regs.depth(1 << UnitOutRegNumWidth[config]); for src_index in 0..COMMON_MOP_SRC_LEN { let read_port = unit_output_regs.new_read_port(); - let p_reg_num = read_src_regs[src_index].cast_bits_to(config.p_reg_num()); + let p_reg_num = read_src_regs[src_index].cast_bits_to(PRegNum[config]); connect_any(read_port.addr, p_reg_num.unit_out_reg.value); connect(read_port.en, false); connect(read_port.clk, cd.clk); @@ -294,7 +292,7 @@ pub fn unit_base, Extr for src_index in 0..COMMON_MOP_SRC_LEN { let read_port = unit_output_regs_valid[unit_index].new_read_port(); - let p_reg_num = input_src_regs[src_index].cast_bits_to(config.p_reg_num()); + let p_reg_num = input_src_regs[src_index].cast_bits_to(PRegNum[config]); connect_any(read_port.addr, p_reg_num.unit_out_reg.value); connect(read_port.en, false); connect(read_port.clk, cd.clk); @@ -325,8 +323,8 @@ pub fn unit_base, Extr connect_any(ready_write_port.addr, unit_output_write.dest.value); connect(ready_write_port.en, true); let p_reg_num = #[hdl] - PRegNum::<_, _> { - unit_num: config.unit_num().from_index(unit_index), + PRegNum::<_> { + unit_num: UnitNum[config].from_index(unit_index), unit_out_reg: unit_output_write.dest, }; for src_index in 0..COMMON_MOP_SRC_LEN { @@ -357,7 +355,7 @@ pub fn unit_base, Extr execute_start.data, HdlSome( #[hdl] - ExecuteStart::<_, _, _> { + ExecuteStart::<_, _> { insn: in_flight_op.insn, src_values: read_src_values, }, @@ -387,7 +385,7 @@ pub fn unit_base, Extr let input_mop_src_regs = wire(mop_ty.src_regs_ty()); connect( input_mop_src_regs, - repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize), + repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize), ); MOp::connect_src_regs(mop, input_mop_src_regs); let src_ready_flags = wire_with_loc( @@ -413,7 +411,7 @@ pub fn unit_base, Extr input_in_flight_op, HdlSome( #[hdl] - InFlightOp::<_, _, _> { + InFlightOp::<_, _> { state: InFlightOpState.Ready(), insn: input, src_ready_flags, @@ -449,7 +447,7 @@ pub fn unit_base, Extr #[hdl] if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] { #[hdl] - let InFlightOp::<_, _, _> { + let InFlightOp::<_, _> { state, insn, src_ready_flags, @@ -461,7 +459,7 @@ pub fn unit_base, Extr ); connect( src_regs, - repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize), + repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize), ); MOp::connect_src_regs(insn.mop, src_regs); @@ -485,8 +483,8 @@ pub fn unit_base, Extr value: _, } = unit_output_write; let p_reg_num = #[hdl] - PRegNum::<_, _> { - unit_num: config.unit_num().from_index(unit_index), + PRegNum::<_> { + unit_num: UnitNum[config].from_index(unit_index), unit_out_reg, }; for src_index in 0..COMMON_MOP_SRC_LEN { @@ -513,7 +511,7 @@ pub fn unit_base, Extr #[hdl] if let HdlSome(execute_end) = execute_end { #[hdl] - let ExecuteEnd::<_, _, _> { unit_output } = execute_end; + let ExecuteEnd::<_, _> { unit_output } = execute_end; #[hdl] if insn.dest.cmp_eq(unit_output.dest) { connect(in_flight_op_execute_ending[in_flight_op_index], true); @@ -559,7 +557,7 @@ pub fn unit_base, Extr in_flight_ops[in_flight_op_index], HdlSome( #[hdl] - InFlightOp::<_, _, _> { + InFlightOp::<_, _> { state, insn, src_ready_flags: in_flight_op_next_src_ready_flags[in_flight_op_index],