Compare commits
2 commits
265b5a9cec
...
b51109f4f6
Author | SHA1 | Date | |
---|---|---|---|
b51109f4f6 | |||
1a72425156 |
6 changed files with 155 additions and 14 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -299,8 +299,8 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite"
|
name = "fayalite"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"blake3",
|
"blake3",
|
||||||
|
@ -322,16 +322,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros"
|
name = "fayalite-proc-macros"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite-proc-macros-impl",
|
"fayalite-proc-macros-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros-impl"
|
name = "fayalite-proc-macros-impl"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
|
@ -345,8 +345,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-visit-gen"
|
name = "fayalite-visit-gen"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#cb17913004259b6e0908a477a67e5a6b621b5c1c"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#3d5d8c54b6f2b7bbb0a31458c00139359ca3006e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
|
|
|
@ -14,4 +14,4 @@ categories = []
|
||||||
rust-version = "1.79"
|
rust-version = "1.79"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[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" }
|
||||||
|
|
|
@ -5,12 +5,14 @@ use crate::{
|
||||||
unit::UnitKind,
|
unit::UnitKind,
|
||||||
};
|
};
|
||||||
use fayalite::prelude::*;
|
use fayalite::prelude::*;
|
||||||
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct CpuConfig {
|
pub struct CpuConfig {
|
||||||
pub unit_kinds: Vec<UnitKind>,
|
pub unit_kinds: Vec<UnitKind>,
|
||||||
pub out_reg_num_width: usize,
|
pub out_reg_num_width: usize,
|
||||||
|
pub fetch_width: NonZeroUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpuConfig {
|
impl CpuConfig {
|
||||||
|
|
|
@ -183,4 +183,5 @@ impl MOpRegNum {
|
||||||
pub const CONST_ZERO_REG_NUM: u32 = 0;
|
pub const CONST_ZERO_REG_NUM: u32 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl]
|
||||||
pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>;
|
pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>;
|
||||||
|
|
|
@ -1,11 +1,128 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::config::CpuConfig;
|
use crate::{
|
||||||
use fayalite::prelude::*;
|
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;
|
pub mod unit_free_regs_tracker;
|
||||||
|
|
||||||
#[hdl_module]
|
#[hdl]
|
||||||
pub fn reg_alloc(config: CpuConfig) {
|
pub struct FetchedDecodedMOp {
|
||||||
todo!()
|
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<FetchWidth: Size> {
|
||||||
|
pub decoded_insns: ArrayType<ReadyValid<FetchedDecodedMOp>, FetchWidth>,
|
||||||
|
#[hdl(flip)]
|
||||||
|
pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<DynSize> =
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ macro_rules! all_units {
|
||||||
$(#[$enum_meta:meta])*
|
$(#[$enum_meta:meta])*
|
||||||
$vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> {
|
$vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> {
|
||||||
$(
|
$(
|
||||||
|
#[create_dyn_unit_fn = $create_dyn_unit_fn:expr]
|
||||||
$(#[$variant_meta:meta])*
|
$(#[$variant_meta:meta])*
|
||||||
$Unit:ident($Op:ty),
|
$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 {
|
impl ToExpr for $UnitKind {
|
||||||
type Type = $HdlUnitKind;
|
type Type = $HdlUnitKind;
|
||||||
|
|
||||||
|
@ -98,8 +107,11 @@ all_units! {
|
||||||
#[unit_kind = UnitKind]
|
#[unit_kind = UnitKind]
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub enum UnitMOp<RegWidth: Size> {
|
pub enum UnitMOp<RegWidth: Size> {
|
||||||
|
#[create_dyn_unit_fn = |config| todo!()]
|
||||||
AluBranch(AluBranchMOp<RegWidth>),
|
AluBranch(AluBranchMOp<RegWidth>),
|
||||||
|
#[create_dyn_unit_fn = |config| todo!()]
|
||||||
L2RegisterFile(L2RegisterFileMOp<RegWidth>),
|
L2RegisterFile(L2RegisterFileMOp<RegWidth>),
|
||||||
|
#[create_dyn_unit_fn = |config| todo!()]
|
||||||
LoadStore(LoadStoreMOp<RegWidth>),
|
LoadStore(LoadStoreMOp<RegWidth>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +168,7 @@ pub trait UnitTrait:
|
||||||
&self,
|
&self,
|
||||||
this: Expr<Self::Type>,
|
this: Expr<Self::Type>,
|
||||||
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>;
|
) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>;
|
||||||
|
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
|
||||||
|
|
||||||
fn to_dyn(&self) -> DynUnit;
|
fn to_dyn(&self) -> DynUnit;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +230,10 @@ impl UnitTrait for DynUnit {
|
||||||
self.unit.output(this)
|
self.unit.output(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||||
|
self.unit.cd(this)
|
||||||
|
}
|
||||||
|
|
||||||
fn to_dyn(&self) -> DynUnit {
|
fn to_dyn(&self) -> DynUnit {
|
||||||
*self
|
*self
|
||||||
}
|
}
|
||||||
|
@ -264,6 +281,10 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
|
||||||
Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this))))
|
Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
|
||||||
|
self.0.cd(Expr::from_bundle(this))
|
||||||
|
}
|
||||||
|
|
||||||
fn to_dyn(&self) -> DynUnit {
|
fn to_dyn(&self) -> DynUnit {
|
||||||
let unit = self.intern();
|
let unit = self.intern();
|
||||||
DynUnit {
|
DynUnit {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue