forked from libre-chip/cpu
WIP: adding test::decode_and_run_single_insn
This commit is contained in:
parent
7fc205e583
commit
a63d2990ef
4 changed files with 660 additions and 1 deletions
|
|
@ -11,5 +11,6 @@ pub mod powerisa_instructions_xml;
|
|||
pub mod reg_alloc;
|
||||
pub mod register;
|
||||
pub mod rename_execute_retire;
|
||||
pub mod test;
|
||||
pub mod unit;
|
||||
pub mod util;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{config::CpuConfig, rename_execute_retire::ExecuteToUnitInterface};
|
||||
use crate::{
|
||||
config::{CpuConfig, CpuConfigUnitCount},
|
||||
rename_execute_retire::ExecuteToUnitInterface,
|
||||
};
|
||||
use fayalite::{
|
||||
bundle::{BundleField, BundleType, NoBuilder},
|
||||
expr::ops::FieldAccess,
|
||||
intern::{Intern, Interned, Memoize},
|
||||
module::{connect_with_loc, wire_with_loc},
|
||||
prelude::*,
|
||||
ty::{
|
||||
OpaqueSimValue, OpaqueSimValueSlice, OpaqueSimValueWriter, OpaqueSimValueWritten,
|
||||
|
|
@ -102,6 +106,42 @@ impl<C: Type + PhantomConstGet<CpuConfig>> ExecuteToUnitInterfaces<C> {
|
|||
}
|
||||
MyMemoize(PhantomData).get_owned(this.to_expr())
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn unit_fields_as_array_wire_with_loc(
|
||||
this: impl ToExpr<Type = Self>,
|
||||
wire_name: &str,
|
||||
source_location: SourceLocation,
|
||||
array_wire_is_dest: bool,
|
||||
) -> Expr<ArrayType<ExecuteToUnitInterface<C>, CpuConfigUnitCount<C>>> {
|
||||
let this = this.to_expr();
|
||||
let config = this.ty().config;
|
||||
let array_wire = wire_with_loc(
|
||||
wire_name,
|
||||
source_location,
|
||||
ArrayType[ExecuteToUnitInterface[config]][CpuConfigUnitCount[config]],
|
||||
);
|
||||
for (unit_field, array_element) in Self::unit_fields(this).into_iter().zip(array_wire) {
|
||||
if array_wire_is_dest {
|
||||
connect_with_loc(array_element, unit_field, source_location);
|
||||
} else {
|
||||
connect_with_loc(unit_field, array_element, source_location);
|
||||
}
|
||||
}
|
||||
array_wire
|
||||
}
|
||||
#[track_caller]
|
||||
pub fn unit_fields_as_array_wire(
|
||||
this: impl ToExpr<Type = Self>,
|
||||
wire_name: &str,
|
||||
array_wire_is_dest: bool,
|
||||
) -> Expr<ArrayType<ExecuteToUnitInterface<C>, CpuConfigUnitCount<C>>> {
|
||||
Self::unit_fields_as_array_wire_with_loc(
|
||||
this,
|
||||
wire_name,
|
||||
SourceLocation::caller(),
|
||||
array_wire_is_dest,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
4
crates/cpu/src/test.rs
Normal file
4
crates/cpu/src/test.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
pub mod decode_and_run_single_insn;
|
||||
614
crates/cpu/src/test/decode_and_run_single_insn.rs
Normal file
614
crates/cpu/src/test/decode_and_run_single_insn.rs
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
|
||||
use crate::{
|
||||
config::{CpuConfig, CpuConfigUnitCount, PhantomConstCpuConfig},
|
||||
instruction::{MOp, MOpRegNum, MOpTrait, MoveRegMOp, PRegNum, UnitNum, UnitOutRegNum},
|
||||
next_pc::FETCH_BLOCK_ID_WIDTH,
|
||||
register::PRegValue,
|
||||
rename_execute_retire::{
|
||||
ExecuteToUnitInterface, GlobalState, MOpId, MOpInstance, NextPcPredictorOp, RenamedMOp,
|
||||
UnitEnqueue, to_unit_interfaces::ExecuteToUnitInterfaces,
|
||||
},
|
||||
unit::{HdlUnitKind, UnitMOp},
|
||||
util::array_vec::ArrayVec,
|
||||
};
|
||||
use fayalite::{
|
||||
bundle::BundleType,
|
||||
int::UIntInRangeType,
|
||||
intern::{Intern, Interned},
|
||||
module::wire_with_loc,
|
||||
prelude::*,
|
||||
util::{prefix_sum::reduce, ready_valid::ReadyValid},
|
||||
};
|
||||
|
||||
/// make arrays dynamically-sized to avoid putting large types on the stack
|
||||
#[hdl(get(|c| 1 << MOpRegNum::WIDTH))]
|
||||
type MOpRegCount<C: PhantomConstGet<CpuConfig>> = DynSize;
|
||||
|
||||
#[hdl(cmp_eq, no_static)]
|
||||
pub struct Registers<C: PhantomConstGet<CpuConfig>> {
|
||||
pub regs: ArrayType<TraceAsString<PRegValue>, MOpRegCount<C>>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig> Registers<C> {
|
||||
#[hdl]
|
||||
pub fn zeroed(self) -> Expr<Self> {
|
||||
#[hdl]
|
||||
Self {
|
||||
regs: repeat(PRegValue::zeroed().into_trace_as_string(), self.regs.len()),
|
||||
config: self.config,
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
pub fn zeroed_sim(self) -> SimValue<Self> {
|
||||
#[hdl(sim)]
|
||||
Self {
|
||||
regs: vec![PRegValue::zeroed_sim().into_trace_as_string(); self.regs.len()],
|
||||
config: self.config,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct DecodeOneInsnOutput<MaxMOpCount: Size> {
|
||||
pub mops: ArrayVec<TraceAsString<MOp>, MaxMOpCount>,
|
||||
pub size_in_bytes: UInt<4>,
|
||||
pub is_illegal: Bool,
|
||||
}
|
||||
|
||||
pub trait DecodeOneInsn: BundleType {
|
||||
type Input: Type;
|
||||
fn input_ty(self) -> Self::Input;
|
||||
type MaxMOpCount: Size;
|
||||
fn max_mop_count(self) -> <Self::MaxMOpCount as Size>::SizeType;
|
||||
fn connect_io(
|
||||
this: Expr<Self>,
|
||||
input: Expr<Self::Input>,
|
||||
output: Expr<DecodeOneInsnOutput<Self::MaxMOpCount>>,
|
||||
);
|
||||
}
|
||||
|
||||
pub type DecodeOneInsnInput<T> = <T as DecodeOneInsn>::Input;
|
||||
#[doc(hidden)]
|
||||
#[expect(non_upper_case_globals)]
|
||||
pub const DecodeOneInsnInput: DecodeOneInsnInputWithoutGenerics =
|
||||
DecodeOneInsnInputWithoutGenerics {};
|
||||
#[doc(hidden)]
|
||||
pub struct DecodeOneInsnInputWithoutGenerics {}
|
||||
|
||||
impl<T: DecodeOneInsn> std::ops::Index<T> for DecodeOneInsnInputWithoutGenerics {
|
||||
type Output = DecodeOneInsnInput<T>;
|
||||
|
||||
fn index(&self, index: T) -> &Self::Output {
|
||||
Interned::into_inner(index.input_ty().intern_sized())
|
||||
}
|
||||
}
|
||||
|
||||
pub type DecodeOneInsnMaxMOpCount<T> = <T as DecodeOneInsn>::MaxMOpCount;
|
||||
#[doc(hidden)]
|
||||
#[expect(non_upper_case_globals)]
|
||||
pub const DecodeOneInsnMaxMOpCount: DecodeOneInsnMaxMOpCountWithoutGenerics =
|
||||
DecodeOneInsnMaxMOpCountWithoutGenerics {};
|
||||
#[doc(hidden)]
|
||||
pub struct DecodeOneInsnMaxMOpCountWithoutGenerics {}
|
||||
|
||||
impl<T: DecodeOneInsn> std::ops::Index<T> for DecodeOneInsnMaxMOpCountWithoutGenerics {
|
||||
type Output = <T::MaxMOpCount as Size>::SizeType;
|
||||
|
||||
fn index(&self, index: T) -> &Self::Output {
|
||||
Interned::into_inner(index.max_mop_count().intern_sized())
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct DecodeAndRunSingleInsnInput<C: PhantomConstGet<CpuConfig>, I> {
|
||||
pub decoder_input: I,
|
||||
pub fetch_block_id: UInt<{ FETCH_BLOCK_ID_WIDTH }>,
|
||||
pub first_id: MOpId,
|
||||
pub pc: UInt<64>,
|
||||
pub predicted_next_pc: UInt<64>,
|
||||
pub regs: Registers<C>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
pub struct DecodeAndRunSingleInsnOutput<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
pub regs: Registers<C>,
|
||||
pub cancel_and_start_at: HdlOption<UInt<64>>,
|
||||
pub retired_insns: ArrayVec<NextPcPredictorOp<C>, MaxMOpCount>,
|
||||
pub config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct UnrenamedMOpState<C: PhantomConstGet<CpuConfig>> {
|
||||
unrenamed: MOpInstance<MOp>,
|
||||
renamed: HdlOption<TraceAsString<RenamedMOp<C>>>,
|
||||
unit_num: TraceAsString<UnitNum<C>>,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
enum Error {
|
||||
NoUnitsOfKind(HdlUnitKind),
|
||||
InconsistentState,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct CancelState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
cancel_index: UIntInRangeType<ConstUsize<0>, MaxMOpCount>,
|
||||
canceling_units: ArrayType<Bool, CpuConfigUnitCount<C>>,
|
||||
config: C,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
enum UnitState {
|
||||
NotYetEnqueued,
|
||||
InputsNotReadySpeculative,
|
||||
InputsReady,
|
||||
OutputReady,
|
||||
FinishedAndOrCausedCancel,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct RunMOpState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
mop_index: UIntInRangeType<ConstUsize<0>, MaxMOpCount>,
|
||||
unit_state: UnitState,
|
||||
config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
enum RunState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
RunningMOp(RunMOpState<C, MaxMOpCount>),
|
||||
CancelingUnits(CancelState<C, MaxMOpCount>),
|
||||
Finished,
|
||||
Error(TraceAsString<Error>),
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
struct DecodeAndRunSingleInsnState<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
mops: ArrayVec<UnrenamedMOpState<C>, MaxMOpCount>,
|
||||
regs: Registers<C>,
|
||||
run_state: RunState<C, MaxMOpCount>,
|
||||
config: C,
|
||||
}
|
||||
|
||||
#[hdl(no_static)]
|
||||
enum StepOutput<C: PhantomConstGet<CpuConfig>, MaxMOpCount: Size> {
|
||||
Finished(DecodeAndRunSingleInsnOutput<C, MaxMOpCount>),
|
||||
Step(DecodeAndRunSingleInsnState<C, MaxMOpCount>),
|
||||
Error(TraceAsString<Error>),
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
fn connect_to_unit_nop<C: Type + PhantomConstGet<CpuConfig>>(
|
||||
to_unit: Expr<ExecuteToUnitInterface<C>>,
|
||||
global_state: impl ToExpr<Type = GlobalState>,
|
||||
) {
|
||||
#[hdl]
|
||||
let ExecuteToUnitInterface::<_> {
|
||||
global_state: to_unit_global_state,
|
||||
enqueue,
|
||||
inputs_ready,
|
||||
is_no_longer_speculative,
|
||||
cant_cause_cancel: _,
|
||||
output_ready: _,
|
||||
finish_cause_cancel: _,
|
||||
unit_outputs_ready,
|
||||
cancel_all,
|
||||
config: _,
|
||||
} = to_unit;
|
||||
connect(to_unit_global_state, global_state);
|
||||
connect(enqueue.data, enqueue.ty().data.HdlNone());
|
||||
connect(inputs_ready, inputs_ready.ty().HdlNone());
|
||||
connect(
|
||||
is_no_longer_speculative,
|
||||
is_no_longer_speculative.ty().HdlNone(),
|
||||
);
|
||||
connect(unit_outputs_ready, false);
|
||||
connect(cancel_all.data, HdlNone());
|
||||
}
|
||||
|
||||
impl<C: PhantomConstCpuConfig, MaxMOpCount: Size> DecodeAndRunSingleInsnState<C, MaxMOpCount> {
|
||||
#[hdl]
|
||||
fn new(
|
||||
input: Expr<DecodeAndRunSingleInsnInput<C, impl Type>>,
|
||||
decoder_output: Expr<DecodeOneInsnOutput<MaxMOpCount>>,
|
||||
config: C,
|
||||
max_mop_count: MaxMOpCount::SizeType,
|
||||
) -> Expr<Self> {
|
||||
#[hdl]
|
||||
let new_state = wire(DecodeAndRunSingleInsnState[config][max_mop_count]);
|
||||
#[hdl]
|
||||
let Self {
|
||||
mops,
|
||||
regs,
|
||||
run_state,
|
||||
config: _,
|
||||
} = new_state;
|
||||
connect(run_state, run_state.ty().Finished());
|
||||
connect(
|
||||
mops,
|
||||
ArrayVec::map(
|
||||
decoder_output.mops,
|
||||
mops.ty().element(),
|
||||
|index, decoded_mop| {
|
||||
if index == 0 {
|
||||
connect(
|
||||
run_state,
|
||||
run_state.ty().RunningMOp(
|
||||
#[hdl]
|
||||
RunMOpState::<_, _> {
|
||||
mop_index: 0usize.cast_to(run_state.ty().RunningMOp.mop_index),
|
||||
unit_state: UnitState.NotYetEnqueued(),
|
||||
config,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
let retval = wire_with_loc(
|
||||
&format!("mops_{index}"),
|
||||
SourceLocation::caller(),
|
||||
UnrenamedMOpState[config],
|
||||
);
|
||||
#[hdl]
|
||||
let UnrenamedMOpState::<_> {
|
||||
unrenamed,
|
||||
renamed,
|
||||
unit_num,
|
||||
} = retval;
|
||||
#[hdl]
|
||||
let MOpInstance::<_> {
|
||||
fetch_block_id,
|
||||
id,
|
||||
pc,
|
||||
predicted_next_pc,
|
||||
size_in_bytes,
|
||||
is_first_mop_in_insn,
|
||||
is_last_mop_in_insn,
|
||||
mop,
|
||||
} = unrenamed;
|
||||
connect(fetch_block_id, input.fetch_block_id);
|
||||
connect(id, (input.first_id + index).cast_to_static::<MOpId>());
|
||||
connect(pc, input.pc);
|
||||
connect(predicted_next_pc, input.predicted_next_pc);
|
||||
connect(size_in_bytes, decoder_output.size_in_bytes);
|
||||
connect(is_first_mop_in_insn, index == 0);
|
||||
connect(
|
||||
is_last_mop_in_insn,
|
||||
ArrayVec::len(decoder_output.mops).cmp_eq(index + 1),
|
||||
);
|
||||
connect(mop, decoded_mop);
|
||||
#[hdl]
|
||||
let renamed_untransformed_move = wire(
|
||||
HdlOption[TraceAsString[UnitMOp[PRegNum[config]][PRegNum[config]]
|
||||
[MoveRegMOp[PRegNum[config]][PRegNum[config]]]]],
|
||||
);
|
||||
#[hdl]
|
||||
if let MOp::TransformedMove(_) = *mop {
|
||||
connect(
|
||||
renamed_untransformed_move,
|
||||
renamed_untransformed_move.ty().HdlNone(),
|
||||
);
|
||||
} else {
|
||||
let unit_kind = MOp::kind(*mop);
|
||||
let available_units = config.get().available_units_for_kind(unit_kind);
|
||||
let chosen_unit = reduce(
|
||||
available_units.into_iter().enumerate().map(
|
||||
|(unit_index, available_unit)| {
|
||||
#[hdl]
|
||||
let chosen_unit = wire(UnitNum[config]);
|
||||
connect(chosen_unit, chosen_unit.ty().const_zero());
|
||||
#[hdl]
|
||||
if available_unit {
|
||||
connect(
|
||||
chosen_unit,
|
||||
chosen_unit.ty().from_index(unit_index),
|
||||
);
|
||||
}
|
||||
chosen_unit
|
||||
},
|
||||
),
|
||||
|a, b| {
|
||||
#[hdl]
|
||||
let chosen_unit = wire(UnitNum[config]);
|
||||
connect(chosen_unit, a);
|
||||
#[hdl]
|
||||
if a.cmp_eq(chosen_unit.ty().const_zero()) {
|
||||
connect(chosen_unit, b);
|
||||
}
|
||||
chosen_unit
|
||||
},
|
||||
)
|
||||
.unwrap_or(UnitNum[config].const_zero());
|
||||
#[hdl]
|
||||
if chosen_unit.cmp_eq(chosen_unit.ty().const_zero()) {
|
||||
connect(
|
||||
run_state,
|
||||
run_state
|
||||
.ty()
|
||||
.Error(Error.NoUnitsOfKind(unit_kind).to_trace_as_string()),
|
||||
);
|
||||
}
|
||||
let unit_out_reg_num_ty = UnitOutRegNum[config];
|
||||
connect(
|
||||
renamed_untransformed_move,
|
||||
HdlSome(
|
||||
MOpTrait::map_regs(
|
||||
*mop,
|
||||
#[hdl]
|
||||
PRegNum::<_> {
|
||||
unit_num: chosen_unit,
|
||||
unit_out_reg: #[hdl]
|
||||
UnitOutRegNum::<_> {
|
||||
value: !unit_out_reg_num_ty.value.zero(),
|
||||
config,
|
||||
},
|
||||
},
|
||||
PRegNum[config],
|
||||
&mut |src_reg, index| {
|
||||
#[hdl]
|
||||
let renamed_src_reg = wire(PRegNum[config]);
|
||||
#[hdl]
|
||||
if src_reg.cmp_eq(MOpRegNum::const_zero()) {
|
||||
connect(
|
||||
renamed_src_reg,
|
||||
renamed_src_reg.ty().const_zero(),
|
||||
);
|
||||
} else {
|
||||
connect(
|
||||
renamed_src_reg,
|
||||
#[hdl]
|
||||
PRegNum::<_> {
|
||||
unit_num: chosen_unit,
|
||||
unit_out_reg: unit_out_reg_num_ty
|
||||
.new_sim(index),
|
||||
},
|
||||
);
|
||||
}
|
||||
renamed_src_reg
|
||||
},
|
||||
)
|
||||
.to_trace_as_string(),
|
||||
),
|
||||
);
|
||||
}
|
||||
connect(renamed, renamed.ty().HdlNone());
|
||||
connect(*unit_num, unit_num.ty().inner_ty().const_zero());
|
||||
#[hdl]
|
||||
if let HdlSome(renamed_untransformed_move) = renamed_untransformed_move {
|
||||
let v = UnitMOp::try_with_transformed_move_op(
|
||||
*renamed_untransformed_move,
|
||||
renamed.ty().HdlSome.inner_ty().TransformedMove,
|
||||
|dest, _src| {
|
||||
connect(dest, dest.ty().HdlNone());
|
||||
},
|
||||
);
|
||||
#[hdl]
|
||||
if let HdlSome(v) = v {
|
||||
connect(renamed, HdlSome(v.to_trace_as_string()));
|
||||
connect(*unit_num, MOpTrait::dest_reg(v).unit_num);
|
||||
}
|
||||
}
|
||||
retval
|
||||
},
|
||||
),
|
||||
);
|
||||
connect(regs, input.regs);
|
||||
new_state
|
||||
}
|
||||
#[hdl]
|
||||
fn step(
|
||||
this: Expr<Self>,
|
||||
to_units: Expr<ExecuteToUnitInterfaces<C>>,
|
||||
global_state: Expr<GlobalState>,
|
||||
) -> Expr<StepOutput<C, MaxMOpCount>> {
|
||||
#[hdl]
|
||||
let Self {
|
||||
mops,
|
||||
regs,
|
||||
run_state,
|
||||
config,
|
||||
} = this;
|
||||
let config = config.ty();
|
||||
let max_mop_count = MaxMOpCount::from_usize(mops.ty().capacity());
|
||||
#[hdl]
|
||||
let stepped = wire(StepOutput[config][max_mop_count]);
|
||||
let to_units_as_array = ExecuteToUnitInterfaces::unit_fields_as_array_wire(
|
||||
to_units,
|
||||
"to_units_as_array",
|
||||
false,
|
||||
);
|
||||
for to_unit in to_units_as_array {
|
||||
connect_to_unit_nop(to_unit, global_state);
|
||||
}
|
||||
#[hdl]
|
||||
match run_state {
|
||||
RunState::<_, _>::RunningMOp(run_mop_state) => {
|
||||
#[hdl]
|
||||
let stepped_step = wire(stepped.ty().Step);
|
||||
connect(stepped, stepped.ty().Step(stepped_step));
|
||||
#[hdl]
|
||||
let RunMOpState::<_, _> {
|
||||
mop_index,
|
||||
unit_state,
|
||||
config: _,
|
||||
} = run_mop_state;
|
||||
let mop_index = mop_index.cast_to(UInt[mop_index.ty().bit_width()]);
|
||||
#[hdl]
|
||||
let mop = wire(mops.ty().element());
|
||||
connect(mop, mops[mop_index]);
|
||||
#[hdl]
|
||||
let UnrenamedMOpState::<_> {
|
||||
unrenamed,
|
||||
renamed,
|
||||
unit_num,
|
||||
} = mop;
|
||||
connect(stepped_step.mops, mops);
|
||||
#[hdl]
|
||||
if let HdlSome(unit_index) = UnitNum::as_index(*unit_num) {
|
||||
#[hdl]
|
||||
let to_unit = wire(to_units_as_array.ty().element());
|
||||
connect(to_units_as_array[unit_index], to_unit);
|
||||
connect_to_unit_nop(to_unit, global_state);
|
||||
#[hdl]
|
||||
let ExecuteToUnitInterface::<_> {
|
||||
global_state: _,
|
||||
enqueue,
|
||||
inputs_ready,
|
||||
is_no_longer_speculative,
|
||||
cant_cause_cancel,
|
||||
output_ready,
|
||||
finish_cause_cancel,
|
||||
unit_outputs_ready,
|
||||
cancel_all,
|
||||
config: _,
|
||||
} = to_unit;
|
||||
#[hdl]
|
||||
match unit_state {
|
||||
UnitState::NotYetEnqueued => {
|
||||
#[hdl]
|
||||
if let HdlSome(renamed) = renamed {
|
||||
let mop = #[hdl]
|
||||
MOpInstance::<_> {
|
||||
fetch_block_id: unrenamed.fetch_block_id,
|
||||
id: unrenamed.id,
|
||||
pc: unrenamed.pc,
|
||||
predicted_next_pc: unrenamed.predicted_next_pc,
|
||||
size_in_bytes: unrenamed.size_in_bytes,
|
||||
is_first_mop_in_insn: unrenamed.is_first_mop_in_insn,
|
||||
is_last_mop_in_insn: unrenamed.is_last_mop_in_insn,
|
||||
mop: renamed,
|
||||
};
|
||||
connect(
|
||||
enqueue.data,
|
||||
HdlSome(
|
||||
#[hdl]
|
||||
UnitEnqueue::<_> { mop, config },
|
||||
),
|
||||
);
|
||||
#[hdl]
|
||||
if enqueue.ready {
|
||||
todo!();
|
||||
}
|
||||
} else {
|
||||
connect(
|
||||
stepped,
|
||||
stepped
|
||||
.ty()
|
||||
.Error(Error.InconsistentState().to_trace_as_string()),
|
||||
);
|
||||
}
|
||||
todo!();
|
||||
}
|
||||
UnitState::InputsNotReadySpeculative => {
|
||||
todo!();
|
||||
}
|
||||
UnitState::InputsReady => {
|
||||
todo!();
|
||||
}
|
||||
UnitState::OutputReady => {
|
||||
todo!();
|
||||
}
|
||||
UnitState::FinishedAndOrCausedCancel => {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
RunState::<_, _>::CancelingUnits(cancel_state) => {
|
||||
todo!();
|
||||
}
|
||||
RunState::<_, _>::Finished => {
|
||||
todo!();
|
||||
}
|
||||
RunState::<_, _>::Error(error) => {
|
||||
connect(stepped, stepped.ty().Error(error));
|
||||
}
|
||||
}
|
||||
stepped
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
pub fn decode_and_run_single_insn<C: Type + PhantomConstCpuConfig, D: Type + DecodeOneInsn>(
|
||||
config: C,
|
||||
decoder: Interned<Module<D>>,
|
||||
) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let input: ReadyValid<DecodeAndRunSingleInsnInput<C, DecodeOneInsnInput<D>>> = m.input(
|
||||
ReadyValid[DecodeAndRunSingleInsnInput[config][DecodeOneInsnInput[decoder.io_ty()]]],
|
||||
);
|
||||
#[hdl]
|
||||
let global_state: GlobalState = m.input();
|
||||
#[hdl]
|
||||
let output: ReadyValid<DecodeAndRunSingleInsnOutput<C, DecodeOneInsnMaxMOpCount<D>>> = m
|
||||
.output(
|
||||
ReadyValid
|
||||
[DecodeAndRunSingleInsnOutput[config][DecodeOneInsnMaxMOpCount[decoder.io_ty()]]],
|
||||
);
|
||||
#[hdl]
|
||||
let to_units: ExecuteToUnitInterfaces<C> = m.output(ExecuteToUnitInterfaces[config]);
|
||||
#[hdl]
|
||||
let error: Bool = m.output();
|
||||
|
||||
connect(error, false);
|
||||
|
||||
#[hdl]
|
||||
let decoder = instance(decoder);
|
||||
#[hdl]
|
||||
let decoder_input = wire(decoder.ty().input_ty());
|
||||
connect(decoder_input, decoder_input.ty().uninit());
|
||||
#[hdl]
|
||||
let decoder_output = wire(DecodeOneInsnOutput[decoder.ty().max_mop_count()]);
|
||||
D::connect_io(decoder, decoder_input, decoder_output);
|
||||
|
||||
#[hdl]
|
||||
let state_reg = reg_builder().clock_domain(cd).reset(
|
||||
HdlOption[DecodeAndRunSingleInsnState[config][decoder.ty().max_mop_count()]].HdlNone(),
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
if let HdlSome(state) = state_reg {
|
||||
connect(input.ready, false);
|
||||
let step = DecodeAndRunSingleInsnState::step(state, to_units, global_state);
|
||||
#[hdl]
|
||||
match step {
|
||||
StepOutput::<_, _>::Finished(v) => {
|
||||
connect(output.data, HdlSome(v));
|
||||
#[hdl]
|
||||
if output.ready {
|
||||
connect(state_reg, state_reg.ty().HdlNone());
|
||||
}
|
||||
}
|
||||
StepOutput::<_, _>::Step(state) => {
|
||||
connect(state_reg, HdlSome(state));
|
||||
}
|
||||
StepOutput::<_, _>::Error(_) => {
|
||||
connect(error, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for to_unit in ExecuteToUnitInterfaces::unit_fields(to_units) {
|
||||
connect_to_unit_nop(to_unit, global_state);
|
||||
}
|
||||
connect(input.ready, true);
|
||||
connect(output.data, output.ty().data.HdlNone());
|
||||
#[hdl]
|
||||
if let HdlSome(input) = input.data {
|
||||
connect(
|
||||
state_reg,
|
||||
HdlSome(DecodeAndRunSingleInsnState::new(
|
||||
input,
|
||||
decoder_output,
|
||||
config,
|
||||
decoder.ty().max_mop_count(),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue