unit_base is basically finished, implemented AddSub[I], didn't check any tests yet
This commit is contained in:
parent
3f6e5cc600
commit
3bd5c77a3f
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue