unit_base is basically finished, implemented AddSub[I], didn't check any tests yet
All checks were successful
/ deps (push) Successful in 54s
/ test (push) Successful in 26m41s

This commit is contained in:
Jacob Lifshay 2025-02-20 20:24:14 -08:00
parent 3f6e5cc600
commit 3bd5c77a3f
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
8 changed files with 21311 additions and 23900 deletions

View file

@ -509,8 +509,10 @@ common_mop_struct! {
#[common]
pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>,
pub invert_src0: Bool,
/// * if this is `true`, use `alu_common.src[1]`'s [`PRegFlagsPowerISA::xer_ca`] as a carry-in/borrow-in
/// * else, use `alu_common.src[1]` as a normal addend
pub src1_is_carry_in: Bool,
pub invert_carry_in: Bool,
pub invert_carry_out: Bool,
pub add_pc: Bool,
}
}

View file

@ -6,7 +6,10 @@ use crate::{
MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum,
COMMON_MOP_SRC_LEN,
},
unit::{unit_base::UnitForwardingInfo, TrapData, UnitTrait},
unit::{
unit_base::UnitInput, GlobalState, TrapData, UnitOutput, UnitOutputWrite, UnitResult,
UnitResultCompleted, UnitTrait,
},
util::tree_reduce::tree_reduce_with_state,
};
use fayalite::{
@ -17,7 +20,6 @@ use fayalite::{
};
use std::{
collections::{BTreeMap, VecDeque},
marker::PhantomData,
num::NonZeroUsize,
};
@ -54,6 +56,8 @@ pub fn reg_alloc(config: &CpuConfig) {
#[hdl]
let fetch_decode_interface: FetchDecodeInterface<DynSize> =
m.input(FetchDecodeInterface[config.fetch_width.get()]);
#[hdl]
let global_state: GlobalState = m.input();
// TODO: propagate traps, branch mis-predictions, and special ops
connect(
fetch_decode_interface.fetch_decode_special_op.data,
@ -85,7 +89,8 @@ pub fn reg_alloc(config: &CpuConfig) {
let selected_unit_indexes =
wire(Array[HdlOption[UInt[config.unit_num_width()]]][config.fetch_width.get()]);
#[hdl]
let renamed_mops = wire(Array[HdlOption[config.unit_mop_in_unit()]][config.fetch_width.get()]);
let renamed_mops =
wire(Array[HdlOption[UnitInput[config.unit_mop_in_unit()]]][config.fetch_width.get()]);
#[hdl]
let renamed_mops_out_reg = wire(Array[HdlOption[config.p_reg_num()]][config.fetch_width.get()]);
for fetch_index in 0..config.fetch_width.get() {
@ -196,19 +201,25 @@ pub fn reg_alloc(config: &CpuConfig) {
let dest_reg = MOpTrait::dest_reg(decoded_insn.mop);
connect(
renamed_mops[fetch_index],
HdlSome(MOpTrait::map_regs(
decoded_insn.mop,
renamed_mop_out_reg.unit_out_reg,
config.p_reg_num_width(),
&mut |src_reg, src_index| {
connect(
rename_table_read_ports[src_index].addr,
#[hdl]
MOpRegNum { value: src_reg },
);
rename_table_read_ports[src_index].data.cast_to_bits()
HdlSome(
#[hdl]
UnitInput::<_> {
mop: MOpTrait::map_regs(
decoded_insn.mop,
renamed_mop_out_reg.unit_out_reg,
config.p_reg_num_width(),
&mut |src_reg, src_index| {
connect(
rename_table_read_ports[src_index].addr,
#[hdl]
MOpRegNum { value: src_reg },
);
rename_table_read_ports[src_index].data.cast_to_bits()
},
),
pc: decoded_insn.pc,
},
)),
),
);
for (reg, reg_kind) in MOpDestReg::regs(dest_reg)
.into_iter()
@ -303,6 +314,8 @@ pub fn reg_alloc(config: &CpuConfig) {
config.fetch_width.get(),
),
);
#[hdl]
let unit_forwarding_info = wire(config.unit_forwarding_info());
for (unit_index, unit_config) in config.units.iter().enumerate() {
let dyn_unit = unit_config.kind.unit(config, unit_index);
let unit = instance_with_loc(
@ -311,6 +324,7 @@ pub fn reg_alloc(config: &CpuConfig) {
SourceLocation::caller(),
);
connect(dyn_unit.cd(unit), cd);
connect(dyn_unit.global_state(unit), global_state);
let unit_to_reg_alloc = dyn_unit.unit_to_reg_alloc(unit);
// TODO: handle assigning multiple instructions to a unit at a time
let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap();
@ -333,8 +347,8 @@ pub fn reg_alloc(config: &CpuConfig) {
);
connect(unit_free_regs_tracker.alloc_out[0].ready, false);
connect(
unit_to_reg_alloc.input_insn.data,
Expr::ty(unit_to_reg_alloc.input_insn).data.HdlNone(),
unit_to_reg_alloc.input.data,
Expr::ty(unit_to_reg_alloc.input).data.HdlNone(),
);
for fetch_index in 0..config.fetch_width.get() {
#[hdl]
@ -343,7 +357,7 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(available_units[fetch_index][unit_index], false);
}
#[hdl]
if !unit_to_reg_alloc.input_insn.ready {
if !unit_to_reg_alloc.input.ready {
// must come after to override connects in loops above
connect(available_units[fetch_index][unit_index], false);
}
@ -354,13 +368,21 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(unit_free_regs_tracker.alloc_out[0].ready, true);
#[hdl]
if let HdlSome(renamed_mop) =
HdlOption::and_then(renamed_mops[fetch_index], |v| dyn_unit.extract_mop(v))
HdlOption::and_then(renamed_mops[fetch_index], |v| {
#[hdl]
let UnitInput::<_> { mop, pc } = v;
let mop = dyn_unit.extract_mop(mop);
HdlOption::map(mop, |mop| {
#[hdl]
UnitInput::<_> { mop, pc }
})
})
{
connect(unit_to_reg_alloc.input_insn.data, HdlSome(renamed_mop));
connect(unit_to_reg_alloc.input.data, HdlSome(renamed_mop));
} else {
connect(
unit_to_reg_alloc.input_insn.data,
HdlSome(Expr::ty(unit_to_reg_alloc.input_insn).data.HdlSome.uninit()),
unit_to_reg_alloc.input.data,
HdlSome(Expr::ty(unit_to_reg_alloc.input).data.HdlSome.uninit()),
);
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
}
@ -385,18 +407,37 @@ pub fn reg_alloc(config: &CpuConfig) {
}
}
}
// TODO: connect outputs to other units
connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info);
connect(
unit_to_reg_alloc.unit_forwarding_info,
#[hdl]
UnitForwardingInfo::<_, _, _> {
unit_output_writes: repeat(
HdlOption[config.unit_output_write()].HdlNone(),
config.units.len(),
),
_phantom: PhantomData,
},
unit_forwarding_info.unit_output_writes[unit_index],
Expr::ty(unit_forwarding_info)
.unit_output_writes
.element()
.HdlNone(),
);
#[hdl]
if let HdlSome(output) = unit_to_reg_alloc.output {
#[hdl]
let UnitOutput::<_, _> { which, result } = output;
#[hdl]
match result {
UnitResult::<_>::Completed(completed) => {
#[hdl]
let UnitResultCompleted::<_> { value, extra_out } = completed;
connect(
unit_forwarding_info.unit_output_writes[unit_index],
HdlSome(
#[hdl]
UnitOutputWrite::<_> { which, value },
),
);
// TODO: handle extra_out
}
UnitResult::<_>::Trap(trap_data) => {
// TODO: handle traps
}
}
}
// TODO: handle cancellation
connect(
unit_to_reg_alloc.cancel_input,

View file

@ -39,20 +39,18 @@ impl PRegFlagsPowerISA {
}
#[hdl]
pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) {
// list all flags explicitly so we don't miss handling any new flags
#[hdl]
match flags {
// list all flags explicitly so we don't miss handling any new flags
PRegFlags {
pwr_ca_x86_cf: _,
pwr_ca32_x86_af: _,
pwr_ov_x86_of: _,
pwr_ov32_x86_df: _,
pwr_cr_lt_x86_sf: _,
pwr_cr_gt_x86_pf: _,
pwr_cr_eq_x86_zf: _,
pwr_so: _,
} => {}
}
let PRegFlags {
pwr_ca_x86_cf: _,
pwr_ca32_x86_af: _,
pwr_ov_x86_of: _,
pwr_ov32_x86_df: _,
pwr_cr_lt_x86_sf: _,
pwr_cr_gt_x86_pf: _,
pwr_cr_eq_x86_zf: _,
pwr_so: _,
} = flags;
}
}
@ -83,20 +81,19 @@ impl PRegFlagsX86 {
}
#[hdl]
pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) {
// list all flags explicitly so we don't miss handling any new flags
#[hdl]
match flags {
// list all flags explicitly so we don't miss handling any new flags
PRegFlags {
pwr_ca_x86_cf: _,
pwr_ca32_x86_af: _,
pwr_ov_x86_of: _,
pwr_ov32_x86_df: _,
pwr_cr_lt_x86_sf: _,
pwr_cr_gt_x86_pf: _,
pwr_cr_eq_x86_zf: _,
pwr_so: unused1,
} => connect(unused1, false),
}
let PRegFlags {
pwr_ca_x86_cf: _,
pwr_ca32_x86_af: _,
pwr_ov_x86_of: _,
pwr_ov32_x86_df: _,
pwr_cr_lt_x86_sf: _,
pwr_cr_gt_x86_pf: _,
pwr_cr_eq_x86_zf: _,
pwr_so: unused1,
} = flags;
connect(unused1, false);
}
}

View file

@ -6,7 +6,7 @@ use crate::{
instruction::{
mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum,
},
register::PRegValue,
register::{FlagsMode, PRegValue},
unit::unit_base::UnitToRegAlloc,
};
use fayalite::{
@ -142,6 +142,11 @@ all_units! {
}
}
#[hdl]
pub struct GlobalState {
pub flags_mode: FlagsMode,
}
#[hdl(cmp_eq)]
pub struct UnitResultCompleted<ExtraOut> {
pub value: PRegValue,
@ -215,6 +220,8 @@ pub trait UnitTrait:
fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState>;
fn to_dyn(&self) -> DynUnit;
}
@ -279,6 +286,10 @@ impl UnitTrait for DynUnit {
self.unit.cd(this)
}
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> {
self.unit.global_state(this)
}
fn to_dyn(&self) -> DynUnit {
*self
}
@ -332,6 +343,10 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
self.0.cd(Expr::from_bundle(this))
}
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> {
self.0.global_state(Expr::from_bundle(this))
}
fn to_dyn(&self) -> DynUnit {
let unit = self.intern();
DynUnit {

View file

@ -3,16 +3,246 @@
use crate::{
config::CpuConfig,
instruction::{AluBranchMOp, UnitOutRegNum},
instruction::{
AddSubMOp, AluBranchMOp, AluCommonMOp, CommonMOp, LogicalMOp, MOpTrait, OutputIntegerMode,
UnitOutRegNum, COMMON_MOP_SRC_LEN,
},
register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue},
unit::{
unit_base::{unit_base, UnitToRegAlloc},
DynUnit, DynUnitWrapper, UnitKind, UnitMOp, UnitTrait,
unit_base::{unit_base, ExecuteEnd, ExecuteStart, UnitToRegAlloc},
DynUnit, DynUnitWrapper, GlobalState, UnitKind, UnitMOp, UnitOutput, UnitResult,
UnitResultCompleted, UnitTrait,
},
};
use fayalite::{
intern::{Intern, Interned},
module::wire_with_loc,
prelude::*,
util::ready_valid::ReadyValid,
};
use std::{collections::HashMap, ops::RangeTo};
#[hdl]
fn add_sub<SrcCount: KnownSize>(
mop: Expr<AddSubMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>,
pc: Expr<UInt<64>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
#[hdl]
let AddSubMOp::<_, _, _> {
alu_common,
invert_src0,
src1_is_carry_in,
invert_carry_in,
add_pc,
} = mop;
#[hdl]
let AluCommonMOp::<_, _, _> {
common,
output_integer_mode,
} = alu_common;
let imm: Expr<UInt<64>> = CommonMOp::imm(common).cast_to_static();
#[hdl]
let carry_in_before_inversion = wire();
connect(carry_in_before_inversion, false);
#[hdl]
let src1 = wire();
connect(src1, 0u64);
#[hdl]
if src1_is_carry_in {
#[hdl]
match flags_mode {
FlagsMode::PowerISA(_) => {
connect(
carry_in_before_inversion,
PRegFlagsPowerISA::xer_ca(src_values[1].flags),
);
}
FlagsMode::X86(_) => {
connect(
carry_in_before_inversion,
PRegFlagsX86::cf(src_values[1].flags),
);
}
}
} else {
connect(src1, src_values[1].int_fp);
}
#[hdl]
let carry_in = wire();
connect(carry_in, carry_in_before_inversion ^ invert_carry_in);
#[hdl]
let src0 = wire();
connect(src0, src_values[0].int_fp);
#[hdl]
if invert_src0 {
connect(src0, !src_values[0].int_fp);
}
#[hdl]
let pc_or_zero = wire();
connect(pc_or_zero, 0u64);
#[hdl]
if add_pc {
connect(pc_or_zero, pc);
}
let sum_of_sliced = |slice: RangeTo<usize>| {
src0[slice] + src1[slice] + src_values[2].int_fp[slice] + pc_or_zero[slice] + imm[slice]
};
#[hdl]
let sum: UInt<64> = wire();
connect(sum, sum_of_sliced(..64).cast_to_static());
let carries =
HashMap::<usize, _>::from_iter([4, 7, 8, 15, 16, 31, 32, 63, 64].into_iter().map(
|bit_index| {
let carry_at = wire_with_loc(
&format!("carry_at_{bit_index}"),
SourceLocation::caller(),
Bool,
);
connect(carry_at, sum_of_sliced(..bit_index)[bit_index]);
(bit_index, carry_at)
},
));
#[hdl]
let int_fp: UInt<64> = wire();
#[hdl]
let x86_cf = wire();
#[hdl]
let x86_af = wire();
connect(x86_af, carries[&4]);
#[hdl]
let x86_of = wire();
#[hdl]
let x86_sf = wire();
#[hdl]
let x86_pf = wire();
connect(x86_pf, sum[..8].parity_even());
#[hdl]
let x86_zf = wire();
let set_x86_flags = |width| {
connect(x86_cf, carries[&width]);
connect(x86_of, carries[&width].cmp_ne(carries[&(width - 1)]));
connect(x86_sf, sum[width - 1]);
connect(x86_zf, sum[..width].cmp_eq(0u8));
};
#[hdl]
let pwr_ca = wire();
connect(pwr_ca, carries[&64]);
#[hdl]
let pwr_ca32 = wire();
connect(pwr_ca32, carries[&32]);
#[hdl]
let pwr_ov = wire();
connect(pwr_ov, carries[&64] ^ carries[&63]);
#[hdl]
let pwr_ov32 = wire();
connect(pwr_ov32, carries[&32] ^ carries[&31]);
#[hdl]
let pwr_cr_lt = wire();
connect(pwr_cr_lt, int_fp[63]);
#[hdl]
let pwr_cr_eq = wire();
connect(pwr_cr_eq, int_fp.cmp_eq(0u64));
#[hdl]
let pwr_cr_gt = wire();
connect(pwr_cr_gt, !pwr_cr_lt & !pwr_cr_eq);
#[hdl]
let pwr_so = wire();
// TODO: SO needs to OR-in the previous value of SO
connect(pwr_so, pwr_ov);
#[hdl]
match output_integer_mode {
OutputIntegerMode::Full64 => {
set_x86_flags(64);
connect(int_fp, sum);
}
OutputIntegerMode::DupLow32 => {
set_x86_flags(32);
connect(
int_fp,
[sum.cast_to_static::<UInt<32>>(); 2]
.cast_to_bits()
.cast_to_static(),
);
}
OutputIntegerMode::ZeroExt32 => {
set_x86_flags(32);
connect(int_fp, sum.cast_to_static::<UInt<32>>().cast_to_static());
}
OutputIntegerMode::SignExt32 => {
set_x86_flags(32);
connect(int_fp, sum.cast_to_static::<SInt<32>>().cast_to_static());
}
OutputIntegerMode::ZeroExt16 => {
set_x86_flags(16);
connect(int_fp, sum.cast_to_static::<UInt<16>>().cast_to_static());
}
OutputIntegerMode::SignExt16 => {
set_x86_flags(16);
connect(int_fp, sum.cast_to_static::<SInt<16>>().cast_to_static());
}
OutputIntegerMode::ZeroExt8 => {
set_x86_flags(8);
connect(int_fp, sum.cast_to_static::<UInt<8>>().cast_to_static());
}
OutputIntegerMode::SignExt8 => {
set_x86_flags(8);
connect(int_fp, sum.cast_to_static::<SInt<8>>().cast_to_static());
}
}
#[hdl]
let flags = wire();
#[hdl]
match flags_mode {
FlagsMode::PowerISA(_) => {
PRegFlagsPowerISA::clear_unused(flags);
connect(PRegFlagsPowerISA::xer_ca(flags), pwr_ca);
connect(PRegFlagsPowerISA::xer_ca32(flags), pwr_ca32);
connect(PRegFlagsPowerISA::xer_ov(flags), pwr_ov);
connect(PRegFlagsPowerISA::xer_ov32(flags), pwr_ov32);
connect(PRegFlagsPowerISA::cr_lt(flags), pwr_cr_lt);
connect(PRegFlagsPowerISA::cr_gt(flags), pwr_cr_gt);
connect(PRegFlagsPowerISA::cr_eq(flags), pwr_cr_eq);
connect(PRegFlagsPowerISA::so(flags), pwr_so);
}
FlagsMode::X86(_) => {
PRegFlagsX86::clear_unused(flags);
connect(PRegFlagsX86::cf(flags), x86_cf);
connect(PRegFlagsX86::af(flags), x86_af);
connect(PRegFlagsX86::of(flags), x86_of);
connect(PRegFlagsX86::sf(flags), x86_sf);
connect(PRegFlagsX86::pf(flags), x86_pf);
connect(PRegFlagsX86::zf(flags), x86_zf);
// this insn doesn't write DF, so it's output isn't used for reading DF
connect(PRegFlagsX86::df(flags), false);
}
}
#[hdl]
UnitResultCompleted::<_> {
value: #[hdl]
PRegValue { int_fp, flags },
extra_out: (),
}
}
#[hdl]
fn logical(
mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize>>,
flags_mode: Expr<FlagsMode>,
src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>,
) -> Expr<UnitResultCompleted<()>> {
// TODO: finish
#[hdl]
UnitResultCompleted::<_> {
value: PRegValue::zeroed(),
extra_out: (),
}
}
#[hdl_module]
pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
@ -29,20 +259,88 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) {
AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()],
(),
));
#[hdl]
let global_state: GlobalState = m.input();
#[hdl]
let unit_base = instance(unit_base(
config,
unit_index,
Expr::ty(unit_to_reg_alloc).input_insn.data.HdlSome,
Expr::ty(unit_to_reg_alloc).input.data.HdlSome.mop,
(),
));
connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc);
connect(unit_base.cd, cd);
connect(unit_base.execute_start.ready, true); // TODO: finish
connect(unit_base.execute_start.ready, true);
connect(
unit_base.execute_end,
Expr::ty(unit_base.execute_end).HdlNone(),
); // TODO: finish
);
#[hdl]
if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) {
#[hdl]
let ExecuteStart::<_> {
mop,
pc,
src_values,
} = execute_start;
#[hdl]
match mop {
AluBranchMOp::<_, _>::AddSub(mop) => connect(
unit_base.execute_end,
HdlSome(
#[hdl]
ExecuteEnd::<_, _> {
unit_output: #[hdl]
UnitOutput::<_, _> {
which: MOpTrait::dest_reg(mop),
result: UnitResult[()].Completed(add_sub(
mop,
pc,
global_state.flags_mode,
src_values,
)),
},
},
),
),
AluBranchMOp::<_, _>::AddSubI(mop) => connect(
unit_base.execute_end,
HdlSome(
#[hdl]
ExecuteEnd::<_, _> {
unit_output: #[hdl]
UnitOutput::<_, _> {
which: MOpTrait::dest_reg(mop),
result: UnitResult[()].Completed(add_sub(
mop,
pc,
global_state.flags_mode,
src_values,
)),
},
},
),
),
AluBranchMOp::<_, _>::Logical(mop) => connect(
unit_base.execute_end,
HdlSome(
#[hdl]
ExecuteEnd::<_, _> {
unit_output: #[hdl]
UnitOutput::<_, _> {
which: MOpTrait::dest_reg(mop),
result: UnitResult[()].Completed(logical(
mop,
global_state.flags_mode,
src_values,
)),
},
},
),
),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -103,6 +401,10 @@ impl UnitTrait for AluBranch {
this.cd
}
fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> {
this.global_state
}
fn to_dyn(&self) -> DynUnit {
DynUnitWrapper(*self).to_dyn()
}

View file

@ -3,12 +3,18 @@
use crate::{
config::CpuConfig,
instruction::{MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN},
instruction::{MOpTrait, PRegNum, UnitNum, UnitOutRegNum, COMMON_MOP_SRC_LEN},
register::PRegValue,
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
util::tree_reduce::tree_reduce,
};
use fayalite::{module::wire_with_loc, prelude::*, ty::StaticType, util::ready_valid::ReadyValid};
use fayalite::{
memory::splat_mask,
module::{memory_with_loc, wire_with_loc},
prelude::*,
ty::StaticType,
util::ready_valid::ReadyValid,
};
use std::marker::PhantomData;
#[hdl]
@ -17,6 +23,12 @@ pub struct UnitForwardingInfo<UnitNumWidth: Size, OutRegNumWidth: Size, UnitCoun
pub _phantom: PhantomData<UnitNumWidth>,
}
#[hdl]
pub struct UnitInput<MOp: Type> {
pub mop: MOp,
pub pc: UInt<64>,
}
#[hdl]
pub struct UnitToRegAlloc<
MOp: Type,
@ -28,7 +40,7 @@ pub struct UnitToRegAlloc<
#[hdl(flip)]
pub unit_forwarding_info: UnitForwardingInfo<UnitNumWidth, OutRegNumWidth, UnitCount>,
#[hdl(flip)]
pub input_insn: ReadyValid<MOp>,
pub input: ReadyValid<UnitInput<MOp>>,
#[hdl(flip)]
pub cancel_input: HdlOption<UnitCancelInput<OutRegNumWidth>>,
pub output: HdlOption<UnitOutput<OutRegNumWidth, ExtraOut>>,
@ -38,7 +50,7 @@ impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCo
UnitToRegAlloc<MOp, ExtraOut, UnitNumWidth, OutRegNumWidth, UnitCount>
{
pub fn mop_ty(self) -> MOp {
self.input_insn.data.HdlSome
self.input.data.HdlSome.mop
}
pub fn extra_out_ty(self) -> ExtraOut {
self.output.HdlSome.extra_out_ty()
@ -48,6 +60,7 @@ impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCo
#[hdl]
pub struct ExecuteStart<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> {
pub mop: MOp,
pub pc: UInt<64>,
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
}
@ -137,6 +150,7 @@ impl InFlightOpState {
struct InFlightOp<MOp: Type> {
state: InFlightOpState,
mop: MOp,
pc: UInt<64>,
src_ready_flags: Array<Bool, { COMMON_MOP_SRC_LEN }>,
}
@ -171,6 +185,7 @@ impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> {
let InFlightOp::<_> {
state,
mop: _,
pc: _,
src_ready_flags,
} = in_flight_op;
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
@ -258,21 +273,85 @@ pub fn unit_base<
connect(in_flight_ops_summary, in_flight_ops_summary_value);
connect(
unit_to_reg_alloc.input_insn.ready,
unit_to_reg_alloc.input.ready,
HdlOption::is_some(in_flight_ops_summary.empty_op_index),
);
// TODO: connect(execute_start.data, <read_regs>(in_flight_ops_summary.ready_op_index));
let unit_output_writes = unit_to_reg_alloc.unit_forwarding_info.unit_output_writes;
#[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),
);
#[hdl]
let read_src_values = wire();
connect(read_src_values, [PRegValue::zeroed(); COMMON_MOP_SRC_LEN]);
for unit_index in 0..Expr::ty(unit_output_writes).len() {
let mut unit_output_regs = memory_with_loc(
&format!("unit_{unit_index}_output_regs"),
PRegValue,
SourceLocation::caller(),
);
unit_output_regs.depth(1 << config.out_reg_num_width);
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());
connect_any(read_port.addr, p_reg_num.unit_out_reg.value);
connect(read_port.en, false);
connect(read_port.clk, cd.clk);
#[hdl]
if UnitNum::is_index(p_reg_num.unit_num, unit_index) {
connect(read_port.en, true);
connect(read_src_values[src_index], read_port.data);
}
}
let write_port = unit_output_regs.new_write_port();
connect_any(write_port.addr, 0u8);
connect(write_port.en, false);
connect(write_port.clk, cd.clk);
connect(write_port.data, PRegValue::zeroed());
connect(write_port.mask, splat_mask(PRegValue, true.to_expr()));
#[hdl]
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
connect_any(write_port.addr, unit_output_write.which.value);
connect(write_port.data, unit_output_write.value);
connect(write_port.en, true);
}
}
#[hdl]
if let HdlSome(ready_op_index) = in_flight_ops_summary.ready_op_index {
#[hdl]
if let HdlSome(in_flight_op) = in_flight_ops[ready_op_index] {
connect(
execute_start.data,
HdlSome(
#[hdl]
ExecuteStart::<_> {
mop: in_flight_op.mop,
pc: in_flight_op.pc,
src_values: read_src_values,
},
),
);
}
}
connect(
unit_to_reg_alloc.output,
Expr::ty(unit_to_reg_alloc.output).HdlNone(),
); // TODO: finish
);
#[hdl]
let input_in_flight_op = wire(HdlOption[in_flight_op_ty]);
connect(input_in_flight_op, HdlOption[in_flight_op_ty].HdlNone());
#[hdl]
if let HdlSome(mop) = ReadyValid::firing_data(unit_to_reg_alloc.input_insn) {
if let HdlSome(input) = ReadyValid::firing_data(unit_to_reg_alloc.input) {
#[hdl]
let UnitInput::<_> { mop, pc } = input;
#[hdl]
let input_mop_src_regs = wire(mop_ty.src_regs_ty());
connect(
@ -309,6 +388,7 @@ pub fn unit_base<
InFlightOp::<_> {
state: InFlightOpState.Ready(),
mop,
pc,
src_ready_flags,
},
),
@ -345,6 +425,7 @@ pub fn unit_base<
let InFlightOp::<_> {
state,
mop,
pc,
src_ready_flags,
} = in_flight_op;
let which = MOp::dest_reg(mop);
@ -359,11 +440,17 @@ pub fn unit_base<
);
MOp::connect_src_regs(mop, src_regs);
#[hdl]
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),
)) {
connect(read_src_regs, src_regs);
}
connect(
in_flight_op_next_src_ready_flags[in_flight_op_index],
src_ready_flags,
);
let unit_output_writes = unit_to_reg_alloc.unit_forwarding_info.unit_output_writes;
for unit_index in 0..Expr::ty(unit_output_writes).len() {
#[hdl]
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
@ -404,6 +491,13 @@ pub fn unit_base<
#[hdl]
if which.cmp_eq(unit_output.which) {
connect(in_flight_op_execute_ending[in_flight_op_index], true);
#[hdl]
if !in_flight_op_canceling[in_flight_op_index] {
#[hdl]
if let InFlightOpState::Running = state {
connect(unit_to_reg_alloc.output, HdlSome(unit_output));
}
}
}
}
#[hdl]
@ -439,7 +533,8 @@ pub fn unit_base<
InFlightOp::<_> {
state,
mop,
src_ready_flags,
pc,
src_ready_flags: in_flight_op_next_src_ready_flags[in_flight_op_index],
},
),
);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff