implement "Create the next-instruction logic" and "Create a model of the instruction fetch/decode control system" #5
19 changed files with 308383 additions and 1257 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -210,6 +210,8 @@ name = "cpu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite",
|
"fayalite",
|
||||||
|
"serde",
|
||||||
|
"simple-mermaid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -303,7 +305,7 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite"
|
name = "fayalite"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
|
|
@ -330,7 +332,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros"
|
name = "fayalite-proc-macros"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fayalite-proc-macros-impl",
|
"fayalite-proc-macros-impl",
|
||||||
]
|
]
|
||||||
|
|
@ -338,7 +340,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-proc-macros-impl"
|
name = "fayalite-proc-macros-impl"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base16ct",
|
"base16ct",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
|
|
@ -353,7 +355,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fayalite-visit-gen"
|
name = "fayalite-visit-gen"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#edcc5927a5f9ebca6df5720bb1f5931e50095a57"
|
source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#c97b44d9d646a4aa64fcc046538fc2354bb708ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
|
|
@ -689,6 +691,12 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple-mermaid"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589144a964b4b30fe3a83b4bb1a09e2475aac194ec832a046a23e75bddf9eb29"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ rust-version = "1.89.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
|
fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" }
|
||||||
|
serde = { version = "1.0.202", features = ["derive"] }
|
||||||
|
simple-mermaid = "0.2.0"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,5 @@ version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fayalite.workspace = true
|
fayalite.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
simple-mermaid.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use fayalite::prelude::*;
|
use fayalite::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct UnitConfig {
|
pub struct UnitConfig {
|
||||||
pub kind: UnitKind,
|
pub kind: UnitKind,
|
||||||
|
|
@ -27,12 +28,15 @@ impl UnitConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct CpuConfig {
|
pub struct CpuConfig {
|
||||||
pub units: Vec<UnitConfig>,
|
pub units: Vec<UnitConfig>,
|
||||||
pub out_reg_num_width: usize,
|
pub out_reg_num_width: usize,
|
||||||
pub fetch_width: NonZeroUsize,
|
pub fetch_width: NonZeroUsize,
|
||||||
|
pub max_branches_per_fetch: NonZeroUsize,
|
||||||
|
pub max_fetches_in_flight: NonZeroUsize,
|
||||||
|
pub log2_fetch_width_in_bytes: u8,
|
||||||
/// default value for [`UnitConfig::max_in_flight`]
|
/// default value for [`UnitConfig::max_in_flight`]
|
||||||
pub default_unit_max_in_flight: NonZeroUsize,
|
pub default_unit_max_in_flight: NonZeroUsize,
|
||||||
pub rob_size: NonZeroUsize,
|
pub rob_size: NonZeroUsize,
|
||||||
|
|
@ -46,6 +50,19 @@ impl CpuConfig {
|
||||||
};
|
};
|
||||||
v
|
v
|
||||||
};
|
};
|
||||||
|
pub const DEFAULT_MAX_BRANCHES_PER_FETCH: NonZeroUsize = {
|
||||||
|
let Some(v) = NonZeroUsize::new(1) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
v
|
||||||
|
};
|
||||||
|
pub const DEFAULT_MAX_FETCHES_IN_FLIGHT: NonZeroUsize = {
|
||||||
|
let Some(v) = NonZeroUsize::new(16) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
v
|
||||||
|
};
|
||||||
|
pub const DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES: u8 = 3;
|
||||||
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = {
|
||||||
let Some(v) = NonZeroUsize::new(8) else {
|
let Some(v) = NonZeroUsize::new(8) else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|
@ -57,6 +74,9 @@ impl CpuConfig {
|
||||||
units,
|
units,
|
||||||
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
|
||||||
fetch_width: Self::DEFAULT_FETCH_WIDTH,
|
fetch_width: Self::DEFAULT_FETCH_WIDTH,
|
||||||
|
max_branches_per_fetch: Self::DEFAULT_MAX_BRANCHES_PER_FETCH,
|
||||||
|
max_fetches_in_flight: Self::DEFAULT_MAX_FETCHES_IN_FLIGHT,
|
||||||
|
log2_fetch_width_in_bytes: Self::DEFAULT_LOG2_FETCH_WIDTH_IN_BYTES,
|
||||||
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
|
||||||
rob_size,
|
rob_size,
|
||||||
}
|
}
|
||||||
|
|
@ -116,4 +136,42 @@ impl CpuConfig {
|
||||||
UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width]
|
UnitToRegAlloc[mop_ty][extra_out_ty][self.unit_num_width()][self.out_reg_num_width]
|
||||||
[self.non_const_unit_nums().len()]
|
[self.non_const_unit_nums().len()]
|
||||||
}
|
}
|
||||||
|
pub fn fetch_width_in_bytes(&self) -> usize {
|
||||||
|
1usize
|
||||||
|
.checked_shl(self.log2_fetch_width_in_bytes.into())
|
||||||
|
.expect("log2_fetch_width_in_bytes is too big")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.fetch_width.get()))]
|
||||||
|
pub type CpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.fetch_width.get() * 2))]
|
||||||
|
pub type TwiceCpuConfigFetchWidth<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.max_branches_per_fetch.get()))]
|
||||||
|
pub type CpuConfigMaxBranchesPerFetch<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.max_fetches_in_flight.get()))]
|
||||||
|
pub type CpuConfigMaxFetchesInFlight<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.log2_fetch_width_in_bytes.into()))]
|
||||||
|
pub type CpuConfigLog2FetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.fetch_width_in_bytes()))]
|
||||||
|
pub type CpuConfigFetchWidthInBytes<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
#[hdl(get(|c| c.rob_size.get()))]
|
||||||
|
pub type CpuConfigRobSize<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||||
|
|
||||||
|
pub trait PhantomConstCpuConfig:
|
||||||
|
PhantomConstGet<CpuConfig>
|
||||||
|
+ Into<PhantomConst<CpuConfig>>
|
||||||
|
+ From<PhantomConst<CpuConfig>>
|
||||||
|
+ Type
|
||||||
|
+ ToSimValue<Type = Self>
|
||||||
|
+ ToExpr<Type = Self>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhantomConstCpuConfig for PhantomConst<CpuConfig> {}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
use crate::{unit::UnitMOp, util::range_u32_len};
|
use crate::{unit::UnitMOp, util::range_u32_len};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
expr::ops::{ArrayLiteral, ExprPartialEq},
|
expr::{HdlPartialEqImpl, ops::ArrayLiteral},
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
sim::value::SimValuePartialEq,
|
|
||||||
};
|
};
|
||||||
use std::{fmt, marker::PhantomData, ops::Range};
|
use std::{borrow::Cow, fmt, marker::PhantomData, ops::Range};
|
||||||
|
|
||||||
pub mod power_isa;
|
pub mod power_isa;
|
||||||
|
|
||||||
|
|
@ -172,20 +171,38 @@ pub enum OutputIntegerMode {
|
||||||
SignExt8,
|
SignExt8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExprPartialEq<Self> for OutputIntegerMode {
|
impl HdlPartialEqImpl<Self> for OutputIntegerMode {
|
||||||
fn cmp_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
#[track_caller]
|
||||||
|
fn cmp_value_eq(
|
||||||
|
lhs: Self,
|
||||||
|
lhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
rhs: Self,
|
||||||
|
rhs_value: Cow<'_, Self::SimValue>,
|
||||||
|
) -> bool {
|
||||||
|
SimValue::opaque(&SimValue::from_value(lhs, lhs_value.into_owned()))
|
||||||
|
== SimValue::opaque(&SimValue::from_value(rhs, rhs_value.into_owned()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn cmp_sim_value_eq(
|
||||||
|
lhs: Cow<'_, SimValue<Self>>,
|
||||||
|
rhs: Cow<'_, SimValue<Self>>,
|
||||||
|
) -> SimValue<Bool> {
|
||||||
|
(SimValue::opaque(&lhs) == SimValue::opaque(&rhs)).to_sim_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn cmp_sim_value_ne(
|
||||||
|
lhs: Cow<'_, SimValue<Self>>,
|
||||||
|
rhs: Cow<'_, SimValue<Self>>,
|
||||||
|
) -> SimValue<Bool> {
|
||||||
|
(SimValue::opaque(&lhs) != SimValue::opaque(&rhs)).to_sim_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn cmp_expr_eq(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
||||||
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
lhs.cast_to_bits().cmp_eq(rhs.cast_to_bits())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp_ne(lhs: Expr<Self>, rhs: Expr<Self>) -> Expr<Bool> {
|
|
||||||
lhs.cast_to_bits().cmp_ne(rhs.cast_to_bits())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SimValuePartialEq<Self> for OutputIntegerMode {
|
|
||||||
fn sim_value_eq(this: &SimValue<Self>, other: &SimValue<Self>) -> bool {
|
|
||||||
SimValue::opaque(this) == SimValue::opaque(other)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const MOP_IMM_WIDTH: usize = 34;
|
pub const MOP_IMM_WIDTH: usize = 34;
|
||||||
|
|
@ -296,8 +313,8 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
|
||||||
let dest = dest.to_expr();
|
let dest = dest.to_expr();
|
||||||
let src_in = src.to_expr();
|
let src_in = src.to_expr();
|
||||||
let imm = imm.to_expr();
|
let imm = imm.to_expr();
|
||||||
assert_eq!(Expr::ty(imm), Self::imm_ty());
|
assert_eq!(imm.ty(), Self::imm_ty());
|
||||||
let src_reg_ty = Expr::ty(src_in).element();
|
let src_reg_ty = src_in.ty().element();
|
||||||
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
|
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
|
||||||
let mut src = [0_hdl_u0.cast_to(src_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 {
|
for i in 0..SrcCount::VALUE {
|
||||||
|
|
@ -341,9 +358,9 @@ impl<PrefixPad: KnownSize, DestReg: Type, SrcRegWidth: Size, SrcCount: KnownSize
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn connect_to_imm(expr: impl ToExpr<Type = Self>, imm: impl ToExpr<Type = SInt>) {
|
pub fn connect_to_imm(expr: impl ToExpr<Type = Self>, imm: impl ToExpr<Type = SInt>) {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
let src_reg_ty = Expr::ty(expr).src.element();
|
let src_reg_ty = expr.ty().src.element();
|
||||||
let imm = imm.to_expr();
|
let imm = imm.to_expr();
|
||||||
assert_eq!(Expr::ty(imm), Self::imm_ty());
|
assert_eq!(imm.ty(), Self::imm_ty());
|
||||||
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
|
let imm_parts = imm.cast_to_bits().cast_bits_to(Self::imm_parts_ty());
|
||||||
let mut src = [Some(0_hdl_u0.cast_to(src_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 {
|
for i in 0..SrcCount::VALUE {
|
||||||
|
|
@ -496,7 +513,7 @@ macro_rules! mop_enum {
|
||||||
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> {
|
fn dest_reg(input: impl ToExpr<Type = Self>) -> Expr<Self::DestReg> {
|
||||||
let input = input.to_expr();
|
let input = input.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let dest_reg = wire(Expr::ty(input).dest_reg_ty());
|
let dest_reg = wire(input.ty().dest_reg_ty());
|
||||||
#[hdl]
|
#[hdl]
|
||||||
match input {
|
match input {
|
||||||
Self::$FirstVariant(v) => connect(dest_reg, <$first_ty as MOpTrait>::dest_reg(v)),
|
Self::$FirstVariant(v) => connect(dest_reg, <$first_ty as MOpTrait>::dest_reg(v)),
|
||||||
|
|
@ -537,7 +554,7 @@ macro_rules! mop_enum {
|
||||||
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
|
) -> Expr<Self::Mapped<NewDestReg, NewSrcRegWidth>> {
|
||||||
let input = input.to_expr();
|
let input = input.to_expr();
|
||||||
let new_dest = new_dest.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);
|
let mapped_ty = input.ty().mapped_ty(new_dest.ty(), new_src_reg_width);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let mapped_regs = wire(mapped_ty);
|
let mapped_regs = wire(mapped_ty);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -584,7 +601,7 @@ macro_rules! mop_enum {
|
||||||
MOpInto::mop_into_ty($MOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]$([$sizes_get_size(self)])*)
|
MOpInto::mop_into_ty($MOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]$([$sizes_get_size(self)])*)
|
||||||
}
|
}
|
||||||
fn mop_into(this: Expr<Self>) -> Expr<Target> {
|
fn mop_into(this: Expr<Self>) -> Expr<Target> {
|
||||||
MOpInto::mop_into(MOpInto::<$MOp<$DestReg, $SrcRegWidth, $($Sizes,)*>>::mop_into_ty(Expr::ty(this)).$Variant(this))
|
MOpInto::mop_into(MOpInto::<$MOp<$DestReg, $SrcRegWidth, $($Sizes,)*>>::mop_into_ty(this.ty()).$Variant(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -833,22 +850,19 @@ impl<Width: Size> UnitNum<Width> {
|
||||||
}
|
}
|
||||||
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
|
pub fn is_index(expr: impl ToExpr<Type = Self>, index: usize) -> Expr<Bool> {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
Expr::ty(expr)
|
expr.ty().from_index(index).adj_value.cmp_eq(expr.adj_value)
|
||||||
.from_index(index)
|
|
||||||
.adj_value
|
|
||||||
.cmp_eq(expr.adj_value)
|
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
pub fn as_index(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<UIntType<Width>>> {
|
pub fn as_index(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<UIntType<Width>>> {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let unit_index = wire(HdlOption[Expr::ty(expr).adj_value]);
|
let unit_index = wire(HdlOption[expr.ty().adj_value]);
|
||||||
connect(unit_index, Expr::ty(unit_index).HdlNone());
|
connect(unit_index, unit_index.ty().HdlNone());
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if expr.adj_value.cmp_ne(0u8) {
|
if expr.adj_value.cmp_ne(0u8) {
|
||||||
connect(
|
connect(
|
||||||
unit_index,
|
unit_index,
|
||||||
HdlSome((expr.adj_value - 1u8).cast_to(Expr::ty(expr).adj_value)),
|
HdlSome((expr.adj_value - 1u8).cast_to(expr.ty().adj_value)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
unit_index
|
unit_index
|
||||||
|
|
@ -900,7 +914,7 @@ impl MOpRegNum {
|
||||||
pub fn const_zero() -> Expr<Self> {
|
pub fn const_zero() -> Expr<Self> {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
MOpRegNum {
|
MOpRegNum {
|
||||||
value: Self::CONST_ZERO_REG_NUM.cast_to_static(),
|
value: Self::CONST_ZERO_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// a lot of instructions write to flag registers that we want
|
/// a lot of instructions write to flag registers that we want
|
||||||
|
|
@ -1077,7 +1091,7 @@ impl MOpDestReg {
|
||||||
flag_reg,
|
flag_reg,
|
||||||
#[hdl]
|
#[hdl]
|
||||||
MOpRegNum {
|
MOpRegNum {
|
||||||
value: reg_num.cast_to_static(),
|
value: reg_num.cast_to_static::<UInt<_>>(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
|
pub mod next_pc;
|
||||||
pub mod reg_alloc;
|
pub mod reg_alloc;
|
||||||
pub mod register;
|
pub mod register;
|
||||||
pub mod unit;
|
pub mod unit;
|
||||||
|
|
|
||||||
4862
crates/cpu/src/next_pc.rs
Normal file
4862
crates/cpu/src/next_pc.rs
Normal file
File diff suppressed because it is too large
Load diff
24
crates/cpu/src/next_pc/next_pc.mermaid
Normal file
24
crates/cpu/src/next_pc/next_pc.mermaid
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
%% SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
%% See Notices.txt for copyright information
|
||||||
|
stateDiagram-v2
|
||||||
|
direction LR
|
||||||
|
|
||||||
|
state "Next PC" as next_pc
|
||||||
|
[*] --> next_pc
|
||||||
|
|
||||||
|
state "Fetch/Decode" as fetch_decode
|
||||||
|
next_pc --> fetch_decode
|
||||||
|
|
||||||
|
state "Branch Predictor" as br_pred
|
||||||
|
next_pc --> br_pred
|
||||||
|
br_pred --> next_pc: cancel following
|
||||||
|
|
||||||
|
state "Post-decode" as post_decode
|
||||||
|
fetch_decode --> post_decode
|
||||||
|
br_pred --> post_decode
|
||||||
|
post_decode --> next_pc: cancel following
|
||||||
|
|
||||||
|
state "Execute/Retire" as execute_retire
|
||||||
|
post_decode --> execute_retire
|
||||||
|
execute_retire --> [*]
|
||||||
|
execute_retire --> next_pc: cancel following
|
||||||
|
|
@ -241,7 +241,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
// TODO: finish
|
// TODO: finish
|
||||||
connect(
|
connect(
|
||||||
rob.renamed_insns_in[fetch_index].data,
|
rob.renamed_insns_in[fetch_index].data,
|
||||||
Expr::ty(rob).renamed_insns_in.element().data.HdlNone(),
|
rob.ty().renamed_insns_in.element().data.HdlNone(),
|
||||||
);
|
);
|
||||||
// TODO: finish
|
// TODO: finish
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -263,7 +263,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
renamed_mops[fetch_index],
|
renamed_mops[fetch_index],
|
||||||
Expr::ty(renamed_mops).element().HdlNone(),
|
renamed_mops.ty().element().HdlNone(),
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
struct RenameTableReadPort<T> {
|
struct RenameTableReadPort<T> {
|
||||||
|
|
@ -332,7 +332,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
let write_port = wire_with_loc(
|
let write_port = wire_with_loc(
|
||||||
&format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()),
|
&format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
Expr::ty(write_port_),
|
write_port_.ty(),
|
||||||
);
|
);
|
||||||
connect(write_port_, write_port);
|
connect(write_port_, write_port);
|
||||||
write_ports.push_back(write_port);
|
write_ports.push_back(write_port);
|
||||||
|
|
@ -343,7 +343,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
addr: 0_hdl_u0,
|
addr: 0_hdl_u0,
|
||||||
en: false,
|
en: false,
|
||||||
clk: cd.clk,
|
clk: cd.clk,
|
||||||
data: Expr::ty(write_port.data).uninit(),
|
data: write_port.data.ty().uninit(),
|
||||||
mask: splat_mask(config.p_reg_num(), true.to_expr()),
|
mask: splat_mask(config.p_reg_num(), true.to_expr()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -375,7 +375,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
config.renamed_mop_in_unit().TransformedMove,
|
config.renamed_mop_in_unit().TransformedMove,
|
||||||
|renamed_mop, renamed_move_op: Expr<MoveRegMOp<_, _>>| {
|
|renamed_mop, renamed_move_op: Expr<MoveRegMOp<_, _>>| {
|
||||||
// TODO: finish handling MoveRegMOp
|
// TODO: finish handling MoveRegMOp
|
||||||
connect(renamed_mop, Expr::ty(renamed_mop).HdlNone());
|
connect(renamed_mop, renamed_mop.ty().HdlNone());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -429,7 +429,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
connect(
|
connect(
|
||||||
selected_unit_index_leaf,
|
selected_unit_index_leaf,
|
||||||
Expr::ty(selected_unit_index_leaf).HdlNone(),
|
selected_unit_index_leaf.ty().HdlNone(),
|
||||||
);
|
);
|
||||||
let unit_index_wire = wire_with_loc(
|
let unit_index_wire = wire_with_loc(
|
||||||
&format!("unit_index_{fetch_index}_{unit_index}"),
|
&format!("unit_index_{fetch_index}_{unit_index}"),
|
||||||
|
|
@ -447,7 +447,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
let selected_unit_index_node = wire_with_loc(
|
let selected_unit_index_node = wire_with_loc(
|
||||||
&format!("selected_unit_index_node_{fetch_index}_{state}"),
|
&format!("selected_unit_index_node_{fetch_index}_{state}"),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
Expr::ty(l),
|
l.ty(),
|
||||||
);
|
);
|
||||||
*state += 1;
|
*state += 1;
|
||||||
connect(selected_unit_index_node, l);
|
connect(selected_unit_index_node, l);
|
||||||
|
|
@ -516,7 +516,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
connect(unit_free_regs_tracker.alloc_out[0].ready, false);
|
connect(unit_free_regs_tracker.alloc_out[0].ready, false);
|
||||||
connect(
|
connect(
|
||||||
unit_to_reg_alloc.input.data,
|
unit_to_reg_alloc.input.data,
|
||||||
Expr::ty(unit_to_reg_alloc.input).data.HdlNone(),
|
unit_to_reg_alloc.input.ty().data.HdlNone(),
|
||||||
);
|
);
|
||||||
for fetch_index in 0..config.fetch_width.get() {
|
for fetch_index in 0..config.fetch_width.get() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -550,7 +550,7 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
} else {
|
} else {
|
||||||
connect(
|
connect(
|
||||||
unit_to_reg_alloc.input.data,
|
unit_to_reg_alloc.input.data,
|
||||||
HdlSome(Expr::ty(unit_to_reg_alloc.input).data.HdlSome.uninit()),
|
HdlSome(unit_to_reg_alloc.input.ty().data.HdlSome.uninit()),
|
||||||
);
|
);
|
||||||
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
|
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
|
||||||
}
|
}
|
||||||
|
|
@ -578,7 +578,8 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info);
|
connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info);
|
||||||
connect(
|
connect(
|
||||||
unit_forwarding_info.unit_output_writes[unit_index],
|
unit_forwarding_info.unit_output_writes[unit_index],
|
||||||
Expr::ty(unit_forwarding_info)
|
unit_forwarding_info
|
||||||
|
.ty()
|
||||||
.unit_output_writes
|
.unit_output_writes
|
||||||
.element()
|
.element()
|
||||||
.HdlNone(),
|
.HdlNone(),
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ pub fn unit_free_regs_tracker(
|
||||||
let reduced_alloc_nums = wire_with_loc(
|
let reduced_alloc_nums = wire_with_loc(
|
||||||
&format!("reduced_alloc_nums_{}_{}", range.start, range.end),
|
&format!("reduced_alloc_nums_{}_{}", range.start, range.end),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
Array[UInt[Expr::ty(l.alloc_nums).element().width() + 1]][alloc_at_once.get()],
|
Array[UInt[l.alloc_nums.ty().element().width() + 1]][alloc_at_once.get()],
|
||||||
);
|
);
|
||||||
for alloc_index in 0..alloc_at_once.get() {
|
for alloc_index in 0..alloc_at_once.get() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -195,7 +195,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let free_before_alloc_array = wire(Array[Expr::ty(free_reg)][alloc_at_once.get() + 1]);
|
let free_before_alloc_array = wire(Array[free_reg.ty()][alloc_at_once.get() + 1]);
|
||||||
connect(free_before_alloc_array[0], free_reg);
|
connect(free_before_alloc_array[0], free_reg);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let expected_alloc = wire(Array[HdlOption[reg_num_ty]][alloc_at_once.get()]);
|
let expected_alloc = wire(Array[HdlOption[reg_num_ty]][alloc_at_once.get()]);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use fayalite::{
|
||||||
intern::{Intern, Interned},
|
intern::{Intern, Interned},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod alu_branch;
|
pub mod alu_branch;
|
||||||
pub mod unit_base;
|
pub mod unit_base;
|
||||||
|
|
@ -36,7 +37,7 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
$(#[$enum_meta])*
|
$(#[$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 {
|
$vis enum $UnitKind {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta])*
|
$(#[$variant_meta])*
|
||||||
|
|
@ -52,9 +53,16 @@ macro_rules! all_units {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToExpr for $UnitKind {
|
impl ValueType for $UnitKind {
|
||||||
type Type = $HdlUnitKind;
|
type Type = $HdlUnitKind;
|
||||||
|
type ValueCategory = fayalite::expr::value_category::ValueCategoryExpr;
|
||||||
|
|
||||||
|
fn ty(&self) -> Self::Type {
|
||||||
|
$HdlUnitKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToExpr for $UnitKind {
|
||||||
fn to_expr(&self) -> Expr<Self::Type> {
|
fn to_expr(&self) -> Expr<Self::Type> {
|
||||||
match self {
|
match self {
|
||||||
$($UnitKind::$Unit => $HdlUnitKind.$Unit(),)*
|
$($UnitKind::$Unit => $HdlUnitKind.$Unit(),)*
|
||||||
|
|
@ -98,7 +106,7 @@ macro_rules! all_units {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
|
$vis fn $extract(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<$Op>> {
|
||||||
let expr = expr.to_expr();
|
let expr = expr.to_expr();
|
||||||
let ty = Expr::ty(expr);
|
let ty = expr.ty();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let $extract = wire(HdlOption[ty.$Unit]);
|
let $extract = wire(HdlOption[ty.$Unit]);
|
||||||
connect($extract, HdlOption[ty.$Unit].HdlNone());
|
connect($extract, HdlOption[ty.$Unit].HdlNone());
|
||||||
|
|
@ -164,10 +172,10 @@ macro_rules! all_units {
|
||||||
$TransformedMoveOp: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
$TransformedMoveOp: MOpTrait<DestReg = $DestReg, SrcRegWidth = $SrcRegWidth>,
|
||||||
{
|
{
|
||||||
let this = this.to_expr();
|
let this = this.to_expr();
|
||||||
let new_ty = Expr::ty(this).with_transformed_move_op_ty(new_transformed_move_op_ty);
|
let new_ty = this.ty().with_transformed_move_op_ty(new_transformed_move_op_ty);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let with_transformed_move_op = wire(HdlOption[new_ty]);
|
let with_transformed_move_op = wire(HdlOption[new_ty]);
|
||||||
connect(with_transformed_move_op, Expr::ty(with_transformed_move_op).HdlNone());
|
connect(with_transformed_move_op, with_transformed_move_op.ty().HdlNone());
|
||||||
// workaround #[hdl] match expanding to a loop, so you can't move variables in it
|
// workaround #[hdl] match expanding to a loop, so you can't move variables in it
|
||||||
let mut connect_transformed_move_op = Some(connect_transformed_move_op);
|
let mut connect_transformed_move_op = Some(connect_transformed_move_op);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -209,7 +217,7 @@ macro_rules! all_units {
|
||||||
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
||||||
}
|
}
|
||||||
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
||||||
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$BeforeUnit(this)
|
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(this.ty()).$BeforeUnit(this)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
|
|
||||||
|
|
@ -218,7 +226,7 @@ macro_rules! all_units {
|
||||||
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
RenamedMOp[MOpTrait::dest_reg_ty(self)][MOpTrait::src_reg_width(self)]
|
||||||
}
|
}
|
||||||
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
fn mop_into(this: Expr<Self>) -> Expr<RenamedMOp<$DestReg, $SrcRegWidth>> {
|
||||||
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(Expr::ty(this)).$AfterUnit(this)
|
MOpInto::<RenamedMOp<$DestReg, $SrcRegWidth>>::mop_into_ty(this.ty()).$AfterUnit(this)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -266,16 +266,13 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
|
||||||
let unit_base = instance(unit_base(
|
let unit_base = instance(unit_base(
|
||||||
config,
|
config,
|
||||||
unit_index,
|
unit_index,
|
||||||
Expr::ty(unit_to_reg_alloc).input.data.HdlSome.mop,
|
unit_to_reg_alloc.ty().input.data.HdlSome.mop,
|
||||||
(),
|
(),
|
||||||
));
|
));
|
||||||
connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc);
|
connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc);
|
||||||
connect(unit_base.cd, cd);
|
connect(unit_base.cd, cd);
|
||||||
connect(unit_base.execute_start.ready, true);
|
connect(unit_base.execute_start.ready, true);
|
||||||
connect(
|
connect(unit_base.execute_end, unit_base.execute_end.ty().HdlNone());
|
||||||
unit_base.execute_end,
|
|
||||||
Expr::ty(unit_base.execute_end).HdlNone(),
|
|
||||||
);
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
|
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ impl InFlightOpsSummary<DynSize> {
|
||||||
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
|
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
|
||||||
) -> Expr<Self> {
|
) -> Expr<Self> {
|
||||||
let in_flight_ops = in_flight_ops.to_expr();
|
let in_flight_ops = in_flight_ops.to_expr();
|
||||||
let max_in_flight = Expr::ty(in_flight_ops).len();
|
let max_in_flight = in_flight_ops.ty().len();
|
||||||
let index_range = 0..max_in_flight;
|
let index_range = 0..max_in_flight;
|
||||||
let index_ty = UInt::range(index_range.clone());
|
let index_ty = UInt::range(index_range.clone());
|
||||||
tree_reduce(
|
tree_reduce(
|
||||||
|
|
@ -259,7 +259,7 @@ pub fn unit_base<
|
||||||
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
|
let execute_end: HdlOption<ExecuteEnd<DynSize, ExtraOut>> =
|
||||||
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
|
m.input(HdlOption[ExecuteEnd[config.out_reg_num_width][extra_out_ty]]);
|
||||||
|
|
||||||
connect(execute_start.data, Expr::ty(execute_start).data.HdlNone());
|
connect(execute_start.data, execute_start.ty().data.HdlNone());
|
||||||
|
|
||||||
let max_in_flight = config.unit_max_in_flight(unit_index).get();
|
let max_in_flight = config.unit_max_in_flight(unit_index).get();
|
||||||
let in_flight_op_ty = InFlightOp[mop_ty];
|
let in_flight_op_ty = InFlightOp[mop_ty];
|
||||||
|
|
@ -270,7 +270,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
|
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let in_flight_ops_summary = wire(Expr::ty(in_flight_ops_summary_value));
|
let in_flight_ops_summary = wire(in_flight_ops_summary_value.ty());
|
||||||
connect(in_flight_ops_summary, in_flight_ops_summary_value);
|
connect(in_flight_ops_summary, in_flight_ops_summary_value);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
|
|
@ -302,7 +302,7 @@ pub fn unit_base<
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let input_src_regs_valid = wire();
|
let input_src_regs_valid = wire();
|
||||||
connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]);
|
connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]);
|
||||||
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..Expr::ty(unit_output_writes).len())
|
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..unit_output_writes.ty().len())
|
||||||
.map(|unit_index| {
|
.map(|unit_index| {
|
||||||
let mut mem = memory_with_loc(
|
let mut mem = memory_with_loc(
|
||||||
&format!("unit_{unit_index}_output_regs_valid"),
|
&format!("unit_{unit_index}_output_regs_valid"),
|
||||||
|
|
@ -313,7 +313,7 @@ pub fn unit_base<
|
||||||
mem
|
mem
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
for unit_index in 0..Expr::ty(unit_output_writes).len() {
|
for unit_index in 0..unit_output_writes.ty().len() {
|
||||||
let mut unit_output_regs = memory_with_loc(
|
let mut unit_output_regs = memory_with_loc(
|
||||||
&format!("unit_{unit_index}_output_regs"),
|
&format!("unit_{unit_index}_output_regs"),
|
||||||
PRegValue,
|
PRegValue,
|
||||||
|
|
@ -411,7 +411,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
unit_to_reg_alloc.output,
|
unit_to_reg_alloc.output,
|
||||||
Expr::ty(unit_to_reg_alloc.output).HdlNone(),
|
unit_to_reg_alloc.output.ty().HdlNone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -503,7 +503,7 @@ pub fn unit_base<
|
||||||
|
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
|
if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome(
|
||||||
in_flight_op_index.cast_to(Expr::ty(in_flight_ops_summary).ready_op_index.HdlSome),
|
in_flight_op_index.cast_to(in_flight_ops_summary.ty().ready_op_index.HdlSome),
|
||||||
)) {
|
)) {
|
||||||
connect(read_src_regs, src_regs);
|
connect(read_src_regs, src_regs);
|
||||||
}
|
}
|
||||||
|
|
@ -512,7 +512,7 @@ pub fn unit_base<
|
||||||
in_flight_op_next_src_ready_flags[in_flight_op_index],
|
in_flight_op_next_src_ready_flags[in_flight_op_index],
|
||||||
src_ready_flags,
|
src_ready_flags,
|
||||||
);
|
);
|
||||||
for unit_index in 0..Expr::ty(unit_output_writes).len() {
|
for unit_index in 0..unit_output_writes.ty().len() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,30 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
len: 0u8.cast_to(self.len),
|
len: 0u8.cast_to(self.len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn new_sim(self, uninit_element: impl ToSimValueWithType<T>) -> SimValue<Self> {
|
||||||
|
let uninit_element = uninit_element.into_sim_value_with_type(self.element());
|
||||||
|
#[hdl(sim)]
|
||||||
|
ArrayVec::<_, _> {
|
||||||
|
elements: SimValue::from_array_elements(
|
||||||
|
self.elements,
|
||||||
|
(0..self.elements.len()).map(|_| uninit_element.clone()),
|
||||||
|
),
|
||||||
|
len: 0u8.cast_to(self.len),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn new_full_sim(
|
||||||
|
self,
|
||||||
|
elements: impl ToSimValueWithType<ArrayType<T, N>>,
|
||||||
|
) -> SimValue<Self> {
|
||||||
|
let elements = elements.to_sim_value_with_type(self.elements);
|
||||||
|
#[hdl(sim)]
|
||||||
|
Self {
|
||||||
|
elements,
|
||||||
|
len: self.elements.len().to_sim_value_with_type(self.len),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn element(self) -> T {
|
pub fn element(self) -> T {
|
||||||
self.elements.element()
|
self.elements.element()
|
||||||
}
|
}
|
||||||
|
|
@ -39,8 +63,8 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
let elements = elements.to_expr();
|
let elements = elements.to_expr();
|
||||||
let len = len.to_expr();
|
let len = len.to_expr();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Length[N::from_usize(Expr::ty(elements).len())],
|
Length[N::from_usize(elements.ty().len())],
|
||||||
Expr::ty(len),
|
len.ty(),
|
||||||
"len type mismatch",
|
"len type mismatch",
|
||||||
);
|
);
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
@ -52,6 +76,9 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
pub fn len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> {
|
pub fn len(this: impl ToExpr<Type = Self>) -> Expr<Length<N>> {
|
||||||
this.to_expr().len
|
this.to_expr().len
|
||||||
}
|
}
|
||||||
|
pub fn len_sim(this: &SimValue<Self>) -> &SimValue<Length<N>> {
|
||||||
|
&this.len
|
||||||
|
}
|
||||||
pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> {
|
pub fn is_empty(this: impl ToExpr<Type = Self>) -> Expr<Bool> {
|
||||||
let len = Self::len(this);
|
let len = Self::len(this);
|
||||||
len.cmp_eq(0u8)
|
len.cmp_eq(0u8)
|
||||||
|
|
@ -75,6 +102,72 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn elements_sim_ref(this: &SimValue<Self>) -> &[SimValue<T>] {
|
||||||
|
&this.elements[..*this.len]
|
||||||
|
}
|
||||||
|
pub fn elements_sim_mut(this: &mut SimValue<Self>) -> &mut [SimValue<T>] {
|
||||||
|
let len = *this.len;
|
||||||
|
&mut this.elements[..len]
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub async fn async_for_each_sim(
|
||||||
|
this: impl ToSimValue<Type = Self>,
|
||||||
|
mut f: impl AsyncFnMut(usize, SimValue<T>),
|
||||||
|
) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this.into_sim_value();
|
||||||
|
for (index, element) in elements.into_iter().enumerate() {
|
||||||
|
if index.cmp_lt(*len) {
|
||||||
|
f(index, element).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub async fn async_for_each_sim_ref<'a>(
|
||||||
|
this: &'a SimValue<Self>,
|
||||||
|
mut f: impl AsyncFnMut(usize, &'a SimValue<T>),
|
||||||
|
) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this;
|
||||||
|
for (index, element) in elements.iter().enumerate() {
|
||||||
|
if index.cmp_lt(**len) {
|
||||||
|
f(index, element).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub async fn async_for_each_sim_mut<'a>(
|
||||||
|
this: &'a mut SimValue<Self>,
|
||||||
|
mut f: impl AsyncFnMut(usize, &'a mut SimValue<T>),
|
||||||
|
) {
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this;
|
||||||
|
for (index, element) in elements.iter_mut().enumerate() {
|
||||||
|
if index.cmp_lt(**len) {
|
||||||
|
f(index, element).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn try_push_sim(
|
||||||
|
this: &mut SimValue<Self>,
|
||||||
|
value: impl ToSimValueWithType<T>,
|
||||||
|
) -> Result<(), SimValue<T>> {
|
||||||
|
let value = value.into_sim_value_with_type(this.ty().element());
|
||||||
|
let capacity = this.ty().capacity();
|
||||||
|
#[hdl(sim)]
|
||||||
|
let ArrayVec::<_, _> { elements, len } = this;
|
||||||
|
if **len < capacity {
|
||||||
|
elements[**len] = value;
|
||||||
|
**len += 1;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn truncate_sim(this: &mut SimValue<Self>, len: usize) {
|
||||||
|
*this.len = len.min(*this.len);
|
||||||
|
}
|
||||||
pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> {
|
pub fn mapped_ty<U: Type>(self, new_element_ty: U) -> ArrayVec<U, N> {
|
||||||
ArrayVec {
|
ArrayVec {
|
||||||
elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())],
|
elements: ArrayType[new_element_ty][N::from_usize(self.elements.len())],
|
||||||
|
|
@ -89,7 +182,7 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
) -> Expr<ArrayVec<U, N>> {
|
) -> Expr<ArrayVec<U, N>> {
|
||||||
let this = this.to_expr();
|
let this = this.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let mapped_array_vec = wire(Expr::ty(this).mapped_ty(new_element_ty));
|
let mapped_array_vec = wire(this.ty().mapped_ty(new_element_ty));
|
||||||
connect(mapped_array_vec.len, this.len);
|
connect(mapped_array_vec.len, this.len);
|
||||||
Self::for_each(this, |index, element| {
|
Self::for_each(this, |index, element| {
|
||||||
connect(mapped_array_vec[index], f(index, element));
|
connect(mapped_array_vec[index], f(index, element));
|
||||||
|
|
@ -97,15 +190,42 @@ impl<T: Type, N: Size> ArrayVec<T, N> {
|
||||||
mapped_array_vec
|
mapped_array_vec
|
||||||
}
|
}
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
pub fn map_sim<U: Type>(
|
||||||
|
this: impl ToSimValue<Type = Self>,
|
||||||
|
uninit_element: impl ToSimValue<Type = U>,
|
||||||
|
mut f: impl FnMut(usize, SimValue<T>) -> SimValue<U>,
|
||||||
|
) -> SimValue<ArrayVec<U, N>> {
|
||||||
|
let this = this.into_sim_value();
|
||||||
|
let uninit_element = uninit_element.into_sim_value();
|
||||||
|
let ty = this.ty().mapped_ty(uninit_element.ty());
|
||||||
|
#[hdl(sim)]
|
||||||
|
let Self { elements, len } = this;
|
||||||
|
#[hdl(sim)]
|
||||||
|
ArrayVec::<_, _> {
|
||||||
|
elements: SimValue::from_array_elements(
|
||||||
|
ty.elements,
|
||||||
|
SimValue::into_value(elements)
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, element)| {
|
||||||
|
if index < *len {
|
||||||
|
f(index, element)
|
||||||
|
} else {
|
||||||
|
uninit_element.clone()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> {
|
pub fn as_array_of_options(this: impl ToExpr<Type = Self>) -> Expr<ArrayType<HdlOption<T>, N>> {
|
||||||
let this = this.to_expr();
|
let this = this.to_expr();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let array_vec_as_array_of_options = wire(
|
let array_vec_as_array_of_options =
|
||||||
ArrayType[HdlOption[Expr::ty(this).element()]]
|
wire(ArrayType[HdlOption[this.ty().element()]][N::from_usize(this.ty().capacity())]);
|
||||||
[N::from_usize(Expr::ty(this).capacity())],
|
|
||||||
);
|
|
||||||
for element in array_vec_as_array_of_options {
|
for element in array_vec_as_array_of_options {
|
||||||
connect(element, Expr::ty(element).HdlNone());
|
connect(element, element.ty().HdlNone());
|
||||||
}
|
}
|
||||||
Self::for_each(this, |index, element| {
|
Self::for_each(this, |index, element| {
|
||||||
connect(array_vec_as_array_of_options[index], HdlSome(element))
|
connect(array_vec_as_array_of_options[index], HdlSome(element))
|
||||||
|
|
@ -126,3 +246,34 @@ where
|
||||||
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
|
<ArrayType<T, N> as ExprIndex<Idx>>::expr_index(&this.elements, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Type> ArrayVec<T, ConstUsize<1>> {
|
||||||
|
#[hdl]
|
||||||
|
pub fn from_opt_sim(
|
||||||
|
opt: impl ToSimValue<Type = HdlOption<T>>,
|
||||||
|
uninit_element: impl ToSimValueWithType<T>,
|
||||||
|
) -> SimValue<Self> {
|
||||||
|
let opt = opt.into_sim_value();
|
||||||
|
let ty = ArrayVec[opt.ty().HdlSome][ConstUsize];
|
||||||
|
#[hdl(sim)]
|
||||||
|
match opt {
|
||||||
|
HdlSome(v) => ty.new_full_sim([v]),
|
||||||
|
HdlNone => ty.new_sim(uninit_element),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[hdl]
|
||||||
|
pub fn into_opt_sim(this: impl ToSimValue<Type = Self>) -> SimValue<HdlOption<T>> {
|
||||||
|
let this = this.into_sim_value();
|
||||||
|
#[hdl(sim)]
|
||||||
|
let Self { elements, len } = this;
|
||||||
|
let [element] = SimValue::into_value(elements);
|
||||||
|
let ty = HdlOption[element.ty()];
|
||||||
|
if *len == 0 {
|
||||||
|
#[hdl(sim)]
|
||||||
|
ty.HdlNone()
|
||||||
|
} else {
|
||||||
|
#[hdl(sim)]
|
||||||
|
ty.HdlSome(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
300436
crates/cpu/tests/expected/next_pc.vcd
Normal file
300436
crates/cpu/tests/expected/next_pc.vcd
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1558
crates/cpu/tests/next_pc.rs
Normal file
1558
crates/cpu/tests/next_pc.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -59,7 +59,7 @@ fn test_reg_alloc() {
|
||||||
[HdlSome(()), HdlNone()],
|
[HdlSome(()), HdlNone()],
|
||||||
},
|
},
|
||||||
[0u8; 2],
|
[0u8; 2],
|
||||||
0x12345678u32.cast_to_static(),
|
0x12345678u32.cast_to_static::<SInt<_>>(),
|
||||||
OutputIntegerMode.DupLow32(),
|
OutputIntegerMode.DupLow32(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -81,7 +81,7 @@ fn test_reg_alloc() {
|
||||||
[HdlSome(()), HdlNone()],
|
[HdlSome(()), HdlNone()],
|
||||||
},
|
},
|
||||||
[1u8, 0, 0],
|
[1u8, 0, 0],
|
||||||
1.cast_to_static(),
|
1.cast_to_static::<SInt<_>>(),
|
||||||
OutputIntegerMode.Full64(),
|
OutputIntegerMode.Full64(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
@ -99,7 +99,7 @@ fn test_reg_alloc() {
|
||||||
flag_regs: [HdlNone(), HdlSome(())],
|
flag_regs: [HdlNone(), HdlSome(())],
|
||||||
},
|
},
|
||||||
[2u8, 4u8],
|
[2u8, 4u8],
|
||||||
0.cast_to_static(),
|
0.cast_to_static::<SInt<_>>(),
|
||||||
OutputIntegerMode.Full64(),
|
OutputIntegerMode.Full64(),
|
||||||
0b0110_hdl_u4,
|
0b0110_hdl_u4,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ function check_file()
|
||||||
POUND_HEADER=('^"# SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"# See Notices.txt for copyright information"$')
|
POUND_HEADER=('^"# SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"# See Notices.txt for copyright information"$')
|
||||||
SLASH_HEADER=('^"// SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"// See Notices.txt for copyright information"$')
|
SLASH_HEADER=('^"// SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"// See Notices.txt for copyright information"$')
|
||||||
MD_HEADER=('^"<!--"$' '^"SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"See Notices.txt for copyright information"$')
|
MD_HEADER=('^"<!--"$' '^"SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"See Notices.txt for copyright information"$')
|
||||||
|
MERMAID_HEADER=('^"%% SPDX-License-Identifier: LGPL-3.0-or-later"$' '^"%% See Notices.txt for copyright information"$')
|
||||||
|
|
||||||
function main()
|
function main()
|
||||||
{
|
{
|
||||||
|
|
@ -51,6 +52,9 @@ function main()
|
||||||
/.forgejo/workflows/*.yml|*/.gitignore|*.toml)
|
/.forgejo/workflows/*.yml|*/.gitignore|*.toml)
|
||||||
check_file "$file" "${POUND_HEADER[@]}"
|
check_file "$file" "${POUND_HEADER[@]}"
|
||||||
;;
|
;;
|
||||||
|
*.mermaid)
|
||||||
|
check_file "$file" "${MERMAID_HEADER[@]}"
|
||||||
|
;;
|
||||||
*.md)
|
*.md)
|
||||||
check_file "$file" "${MD_HEADER[@]}"
|
check_file "$file" "${MD_HEADER[@]}"
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue