From 1a72425156ac8b3164006ca63399716ba17a01f1 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 5 Nov 2024 17:33:24 -0800 Subject: [PATCH 1/2] update fayalite dependency --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a0fc9c..f3934a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,8 +299,8 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fayalite" -version = "0.2.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c" +version = "0.2.1" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e" dependencies = [ "bitvec", "blake3", @@ -322,16 +322,16 @@ dependencies = [ [[package]] name = "fayalite-proc-macros" -version = "0.2.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c" +version = "0.2.1" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e" dependencies = [ "fayalite-proc-macros-impl", ] [[package]] name = "fayalite-proc-macros-impl" -version = "0.2.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c" +version = "0.2.1" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e" dependencies = [ "base16ct", "num-bigint", @@ -345,8 +345,8 @@ dependencies = [ [[package]] name = "fayalite-visit-gen" -version = "0.2.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c" +version = "0.2.1" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e" dependencies = [ "indexmap", "prettyplease", diff --git a/Cargo.toml b/Cargo.toml index 97ebec3..6853484 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,4 @@ categories = [] rust-version = "1.79" [workspace.dependencies] -fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.2.0", branch = "master" } +fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.2.1", branch = "master" } From b51109f4f609895c871cca62453c21f714278140 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 5 Nov 2024 17:34:31 -0800 Subject: [PATCH 2/2] WIP implementing reg_alloc --- crates/cpu/src/config.rs | 2 + crates/cpu/src/instruction.rs | 1 + crates/cpu/src/reg_alloc.rs | 127 ++++++++++++++++++++++++++++++++-- crates/cpu/src/unit.rs | 21 ++++++ 4 files changed, 146 insertions(+), 5 deletions(-) diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index e144e32..c7e2e25 100644 --- a/crates/cpu/src/config.rs +++ b/crates/cpu/src/config.rs @@ -5,12 +5,14 @@ use crate::{ unit::UnitKind, }; use fayalite::prelude::*; +use std::num::NonZeroUsize; #[derive(Clone, Eq, PartialEq, Hash, Debug)] #[non_exhaustive] pub struct CpuConfig { pub unit_kinds: Vec, pub out_reg_num_width: usize, + pub fetch_width: NonZeroUsize, } impl CpuConfig { diff --git a/crates/cpu/src/instruction.rs b/crates/cpu/src/instruction.rs index 66adb27..af6d96b 100644 --- a/crates/cpu/src/instruction.rs +++ b/crates/cpu/src/instruction.rs @@ -183,4 +183,5 @@ impl MOpRegNum { pub const CONST_ZERO_REG_NUM: u32 = 0; } +#[hdl] pub type MOp = UnitMOp>; diff --git a/crates/cpu/src/reg_alloc.rs b/crates/cpu/src/reg_alloc.rs index c47d6ff..684c47b 100644 --- a/crates/cpu/src/reg_alloc.rs +++ b/crates/cpu/src/reg_alloc.rs @@ -1,11 +1,128 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use crate::config::CpuConfig; -use fayalite::prelude::*; +use crate::{ + config::CpuConfig, + instruction::{MOp, UnitNum}, + unit::{TrapData, UnitTrait}, + util::tree_reduce::{tree_reduce, tree_reduce_with_state}, +}; +use fayalite::{module::instance_with_loc, prelude::*, util::ready_valid::ReadyValid}; +use std::num::NonZeroUsize; pub mod unit_free_regs_tracker; -#[hdl_module] -pub fn reg_alloc(config: CpuConfig) { - todo!() +#[hdl] +pub struct FetchedDecodedMOp { + pub uop: MOp, + /// true if pc doesn't have to be related to the previous instruction. + /// (enable to stop detecting when the current instruction isn't + /// supposed to be run next, e.g. on branch mis-prediction) + pub is_unrelated_pc: Bool, + pub pc: UInt<64>, +} + +#[hdl] +pub enum FetchDecodeSpecialOp { + Trap(TrapData), + ICacheFlush, +} + +#[hdl] +pub struct FetchDecodeInterface { + pub decoded_insns: ArrayType, FetchWidth>, + #[hdl(flip)] + pub fetch_decode_special_op: ReadyValid, +} + +#[hdl_module] +/// combination register allocator, register renaming, unit selection, and retire handling +pub fn reg_alloc(config: &CpuConfig) { + #[hdl] + let cd: ClockDomain = m.input(); + #[hdl] + let fetch_decode_interface: FetchDecodeInterface = + m.input(FetchDecodeInterface[config.fetch_width.get()]); + // TODO: propagate traps, branch mis-predictions, and special ops + connect( + fetch_decode_interface.fetch_decode_special_op.data, + HdlNone(), + ); + // TODO: finish + #[hdl] + let available_units = + wire(Array[Array[Bool][config.unit_kinds.len()]][config.fetch_width.get()]); + #[hdl] + let selected_unit_nums = wire(Array[HdlOption[config.unit_num()]][config.fetch_width.get()]); + for fetch_index in 0..config.fetch_width.get() { + connect( + fetch_decode_interface.decoded_insns[fetch_index].ready, + true, + ); + connect( + available_units[fetch_index], + repeat(false, config.unit_kinds.len()), + ); + #[hdl] + if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data { + connect( + available_units[fetch_index], + config.available_units_for_kind(MOp::kind(decoded_insn.uop)), + ); + } + connect( + selected_unit_nums[fetch_index], + tree_reduce_with_state( + 0..config.unit_kinds.len(), + &mut (), + |_state, unit_index| { + #[hdl] + let selected_unit_leaf = wire(HdlOption[config.unit_num()]); + connect(selected_unit_leaf, HdlOption[config.unit_num()].HdlNone()); + #[hdl] + let unit_num = wire(config.unit_num()); + connect_any(unit_num.value, unit_index); + #[hdl] + if available_units[fetch_index][unit_index] { + connect(selected_unit_leaf, HdlSome(unit_num)) + } + selected_unit_leaf + }, + |_state, l, r| { + #[hdl] + let selected_unit_node = wire(Expr::ty(l)); + connect(selected_unit_node, l); + #[hdl] + if let HdlNone = l { + connect(selected_unit_node, r); + } + selected_unit_node + }, + ) + .expect("expected at least one unit"), + ); + } + for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() { + let dyn_unit = unit_kind.unit(config); + let unit = instance_with_loc( + &format!("unit_{unit_index}"), + dyn_unit.make_module(), + SourceLocation::caller(), + ); + connect(dyn_unit.cd(unit), cd); + // TODO: handle assigning multiple instructions to a unit at a time + let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap(); + // TODO: handle retiring multiple instructions from a unit at a time + let retire_from_unit_at_once = NonZeroUsize::new(1).unwrap(); + let unit_free_regs_tracker = instance_with_loc( + &format!("unit_{unit_index}_free_regs_tracker"), + unit_free_regs_tracker::unit_free_regs_tracker( + retire_from_unit_at_once, + assign_to_unit_at_once, + config.out_reg_num_width, + ), + SourceLocation::caller(), + ); + connect(unit_free_regs_tracker.cd, cd); + // TODO: finish + } } diff --git a/crates/cpu/src/unit.rs b/crates/cpu/src/unit.rs index ad1e581..14e8cd7 100644 --- a/crates/cpu/src/unit.rs +++ b/crates/cpu/src/unit.rs @@ -21,6 +21,7 @@ macro_rules! all_units { $(#[$enum_meta:meta])* $vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> { $( + #[create_dyn_unit_fn = $create_dyn_unit_fn:expr] $(#[$variant_meta:meta])* $Unit:ident($Op:ty), )* @@ -35,6 +36,14 @@ macro_rules! all_units { )* } + impl $UnitKind { + pub fn unit(self, config: &CpuConfig) -> DynUnit { + match self { + $($UnitKind::$Unit => $create_dyn_unit_fn(config),)* + } + } + } + impl ToExpr for $UnitKind { type Type = $HdlUnitKind; @@ -98,8 +107,11 @@ all_units! { #[unit_kind = UnitKind] #[hdl] pub enum UnitMOp { + #[create_dyn_unit_fn = |config| todo!()] AluBranch(AluBranchMOp), + #[create_dyn_unit_fn = |config| todo!()] L2RegisterFile(L2RegisterFileMOp), + #[create_dyn_unit_fn = |config| todo!()] LoadStore(LoadStoreMOp), } } @@ -156,6 +168,7 @@ pub trait UnitTrait: &self, this: Expr, ) -> Expr>>; + fn cd(&self, this: Expr) -> Expr; fn to_dyn(&self) -> DynUnit; } @@ -217,6 +230,10 @@ impl UnitTrait for DynUnit { self.unit.output(this) } + fn cd(&self, this: Expr) -> Expr { + self.unit.cd(this) + } + fn to_dyn(&self) -> DynUnit { *self } @@ -264,6 +281,10 @@ impl UnitTrait for DynUnitWrapper) -> Expr { + self.0.cd(Expr::from_bundle(this)) + } + fn to_dyn(&self) -> DynUnit { let unit = self.intern(); DynUnit {