forked from libre-chip/cpu
610 lines
22 KiB
Rust
610 lines
22 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
|
|
use crate::{
|
|
config::{CpuConfig, CpuConfigUnitCount, PhantomConstCpuConfig},
|
|
instruction::{COMMON_MOP_SRC_LEN, MOpTrait, PRegNum, UnitNum, UnitOutRegNum},
|
|
register::PRegValue,
|
|
unit::{UnitCancelInput, UnitOutput, UnitOutputWrite},
|
|
util::tree_reduce::tree_reduce,
|
|
};
|
|
use fayalite::{
|
|
memory::splat_mask,
|
|
module::{memory_with_loc, wire_with_loc},
|
|
prelude::*,
|
|
ty::StaticType,
|
|
util::ready_valid::ReadyValid,
|
|
};
|
|
|
|
#[hdl(no_static)]
|
|
pub struct UnitForwardingInfo<C: PhantomConstGet<CpuConfig>> {
|
|
pub unit_output_writes: ArrayType<HdlOption<UnitOutputWrite<C>>, CpuConfigUnitCount<C>>,
|
|
pub unit_reg_frees: ArrayType<HdlOption<UnitOutRegNum<C>>, CpuConfigUnitCount<C>>,
|
|
}
|
|
|
|
#[hdl]
|
|
pub struct UnitInput<MOp: Type> {
|
|
pub mop: MOp,
|
|
pub pc: UInt<64>,
|
|
}
|
|
|
|
#[hdl(no_static)]
|
|
pub struct UnitToRegAlloc<C: PhantomConstGet<CpuConfig>, MOp: Type, ExtraOut: Type> {
|
|
#[hdl(flip)]
|
|
pub unit_forwarding_info: UnitForwardingInfo<C>,
|
|
#[hdl(flip)]
|
|
pub input: ReadyValid<UnitInput<MOp>>,
|
|
#[hdl(flip)]
|
|
pub cancel_input: HdlOption<UnitCancelInput<C>>,
|
|
pub output: HdlOption<UnitOutput<C, ExtraOut>>,
|
|
}
|
|
|
|
impl<C: PhantomConstCpuConfig, MOp: Type, ExtraOut: Type> UnitToRegAlloc<C, MOp, ExtraOut> {
|
|
pub fn mop_ty(self) -> MOp {
|
|
self.input.data.HdlSome.mop
|
|
}
|
|
pub fn extra_out_ty(self) -> ExtraOut {
|
|
self.output.HdlSome.extra_out_ty()
|
|
}
|
|
}
|
|
|
|
#[hdl(no_static)]
|
|
pub struct ExecuteStart<
|
|
C: PhantomConstGet<CpuConfig>,
|
|
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<C>>,
|
|
> {
|
|
pub mop: MOp,
|
|
pub pc: UInt<64>,
|
|
pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>,
|
|
pub config: C,
|
|
}
|
|
|
|
#[hdl(no_static)]
|
|
pub struct ExecuteEnd<C: PhantomConstGet<CpuConfig>, ExtraOut> {
|
|
pub unit_output: UnitOutput<C, ExtraOut>,
|
|
}
|
|
|
|
#[hdl]
|
|
enum InFlightOpState {
|
|
Ready,
|
|
Running,
|
|
CanceledAndRunning,
|
|
}
|
|
|
|
impl InFlightOpState {
|
|
fn ready_next_state(canceling: bool, starting: bool, ending: bool) -> Expr<HdlOption<Self>> {
|
|
match (canceling, starting, ending) {
|
|
(false, false, _) => HdlSome(InFlightOpState.Ready()),
|
|
(false, true, false) => HdlSome(InFlightOpState.Running()),
|
|
(false, true, true) => HdlNone(),
|
|
(true, false, _) => HdlNone(),
|
|
(true, true, false) => HdlSome(InFlightOpState.CanceledAndRunning()),
|
|
(true, true, true) => HdlNone(),
|
|
}
|
|
}
|
|
fn running_next_state(canceling: bool, _starting: bool, ending: bool) -> Expr<HdlOption<Self>> {
|
|
match (canceling, ending) {
|
|
(false, false) => HdlSome(InFlightOpState.Running()),
|
|
(false, true) => HdlNone(),
|
|
(true, false) => HdlSome(InFlightOpState.CanceledAndRunning()),
|
|
(true, true) => HdlNone(),
|
|
}
|
|
}
|
|
fn canceled_and_running_next_state(
|
|
_canceling: bool,
|
|
_starting: bool,
|
|
ending: bool,
|
|
) -> Expr<HdlOption<Self>> {
|
|
if ending {
|
|
HdlNone()
|
|
} else {
|
|
HdlSome(InFlightOpState.CanceledAndRunning())
|
|
}
|
|
}
|
|
/// FIXME: this is working around #[hdl] match not supporting matching values inside structs yet
|
|
#[hdl]
|
|
fn connect_next_state(
|
|
canceling: Expr<Bool>,
|
|
starting: Expr<Bool>,
|
|
ending: Expr<Bool>,
|
|
next_state_fn: fn(canceling: bool, starting: bool, ending: bool) -> Expr<HdlOption<Self>>,
|
|
next_state: Expr<HdlOption<Self>>,
|
|
) {
|
|
#[hdl]
|
|
fn recurse<const N: usize>(
|
|
exprs: &[Expr<Bool>; N],
|
|
bools: &mut [bool; N],
|
|
f: &mut impl FnMut(&[bool; N]),
|
|
arg_index: usize,
|
|
) {
|
|
if arg_index < N {
|
|
#[hdl]
|
|
if exprs[arg_index] {
|
|
bools[arg_index] = true;
|
|
recurse(exprs, bools, f, arg_index + 1);
|
|
} else {
|
|
bools[arg_index] = false;
|
|
recurse(exprs, bools, f, arg_index + 1);
|
|
}
|
|
} else {
|
|
f(bools);
|
|
}
|
|
}
|
|
recurse(
|
|
&[canceling, starting, ending],
|
|
&mut [false; 3],
|
|
&mut |&[canceling, starting, ending]| {
|
|
connect(next_state, next_state_fn(canceling, starting, ending))
|
|
},
|
|
0,
|
|
);
|
|
}
|
|
}
|
|
|
|
#[hdl]
|
|
struct InFlightOp<MOp: Type> {
|
|
state: InFlightOpState,
|
|
mop: MOp,
|
|
pc: UInt<64>,
|
|
src_ready_flags: Array<Bool, { COMMON_MOP_SRC_LEN }>,
|
|
}
|
|
|
|
#[hdl]
|
|
struct InFlightOpsSummary<OpIndexWidth: Size> {
|
|
empty_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
|
ready_op_index: HdlOption<UIntType<OpIndexWidth>>,
|
|
}
|
|
|
|
impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> {
|
|
#[hdl]
|
|
fn new<MOp: Type>(
|
|
op_index: usize,
|
|
op_index_ty: UIntType<OpIndexWidth>,
|
|
in_flight_op: impl ToExpr<Type = HdlOption<InFlightOp<MOp>>>,
|
|
) -> Expr<Self> {
|
|
let empty_op_index = wire_with_loc(
|
|
&format!("empty_op_index_{op_index}"),
|
|
SourceLocation::caller(),
|
|
HdlOption[op_index_ty],
|
|
);
|
|
connect(empty_op_index, HdlOption[op_index_ty].HdlNone());
|
|
let ready_op_index = wire_with_loc(
|
|
&format!("ready_op_index_{op_index}"),
|
|
SourceLocation::caller(),
|
|
HdlOption[op_index_ty],
|
|
);
|
|
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
|
#[hdl]
|
|
if let HdlSome(in_flight_op) = in_flight_op {
|
|
#[hdl]
|
|
let InFlightOp::<_> {
|
|
state,
|
|
mop: _,
|
|
pc: _,
|
|
src_ready_flags,
|
|
} = in_flight_op;
|
|
connect(ready_op_index, HdlOption[op_index_ty].HdlNone());
|
|
#[hdl]
|
|
match state {
|
|
InFlightOpState::Ready =>
|
|
{
|
|
#[hdl]
|
|
if src_ready_flags.cmp_eq([true; COMMON_MOP_SRC_LEN]) {
|
|
connect(ready_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
|
}
|
|
}
|
|
InFlightOpState::CanceledAndRunning | InFlightOpState::Running => {}
|
|
}
|
|
} else {
|
|
connect(empty_op_index, HdlSome(op_index.cast_to(op_index_ty)));
|
|
}
|
|
#[hdl]
|
|
InFlightOpsSummary::<_> {
|
|
empty_op_index,
|
|
ready_op_index,
|
|
}
|
|
}
|
|
#[hdl]
|
|
fn combine(l: impl ToExpr<Type = Self>, r: impl ToExpr<Type = Self>) -> Expr<Self> {
|
|
let l = l.to_expr();
|
|
let r = r.to_expr();
|
|
#[hdl]
|
|
InFlightOpsSummary::<_> {
|
|
empty_op_index: HdlOption::or(l.empty_op_index, r.empty_op_index),
|
|
ready_op_index: HdlOption::or(l.ready_op_index, r.ready_op_index),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl InFlightOpsSummary<DynSize> {
|
|
fn summarize<MOp: Type, MaxInFlight: Size>(
|
|
in_flight_ops: impl ToExpr<Type = ArrayType<HdlOption<InFlightOp<MOp>>, MaxInFlight>>,
|
|
) -> Expr<Self> {
|
|
let in_flight_ops = in_flight_ops.to_expr();
|
|
let max_in_flight = in_flight_ops.ty().len();
|
|
let index_range = 0..max_in_flight;
|
|
let index_ty = UInt::range(index_range.clone());
|
|
tree_reduce(
|
|
index_range.map(|i| Self::new(i, index_ty, in_flight_ops[i])),
|
|
Self::combine,
|
|
)
|
|
.expect("in_flight_ops is known to have len > 0")
|
|
}
|
|
}
|
|
|
|
#[hdl_module]
|
|
pub fn unit_base<
|
|
MOp: Type + MOpTrait<DestReg = UnitOutRegNum<PhantomConst<CpuConfig>>, SrcRegWidth = DynSize>,
|
|
ExtraOut: Type,
|
|
>(
|
|
config: PhantomConst<CpuConfig>,
|
|
unit_index: usize,
|
|
mop_ty: MOp,
|
|
extra_out_ty: ExtraOut,
|
|
) {
|
|
#[hdl]
|
|
let cd: ClockDomain = m.input();
|
|
#[hdl]
|
|
let unit_to_reg_alloc: UnitToRegAlloc<PhantomConst<CpuConfig>, MOp, ExtraOut> =
|
|
m.output(UnitToRegAlloc[config][mop_ty][extra_out_ty]);
|
|
#[hdl]
|
|
let execute_start: ReadyValid<ExecuteStart<PhantomConst<CpuConfig>, MOp>> =
|
|
m.output(ReadyValid[ExecuteStart[config][mop_ty]]);
|
|
#[hdl]
|
|
let execute_end: HdlOption<ExecuteEnd<PhantomConst<CpuConfig>, ExtraOut>> =
|
|
m.input(HdlOption[ExecuteEnd[config][extra_out_ty]]);
|
|
|
|
connect(execute_start.data, execute_start.ty().data.HdlNone());
|
|
|
|
let max_in_flight = config.get().unit_max_in_flight(unit_index).get();
|
|
let in_flight_op_ty = InFlightOp[mop_ty];
|
|
#[hdl]
|
|
let in_flight_ops = reg_builder()
|
|
.clock_domain(cd)
|
|
.reset(repeat(HdlOption[in_flight_op_ty].HdlNone(), max_in_flight));
|
|
|
|
let in_flight_ops_summary_value = InFlightOpsSummary::summarize(in_flight_ops);
|
|
#[hdl]
|
|
let in_flight_ops_summary = wire(in_flight_ops_summary_value.ty());
|
|
connect(in_flight_ops_summary, in_flight_ops_summary_value);
|
|
|
|
connect(
|
|
unit_to_reg_alloc.input.ready,
|
|
HdlOption::is_some(in_flight_ops_summary.empty_op_index),
|
|
);
|
|
|
|
#[hdl]
|
|
let UnitForwardingInfo::<_> {
|
|
unit_output_writes,
|
|
unit_reg_frees,
|
|
} = unit_to_reg_alloc.unit_forwarding_info;
|
|
#[hdl]
|
|
let read_src_regs = wire(mop_ty.src_regs_ty());
|
|
connect(
|
|
read_src_regs,
|
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
|
);
|
|
#[hdl]
|
|
let read_src_values = wire();
|
|
connect(read_src_values, [PRegValue::zeroed(); COMMON_MOP_SRC_LEN]);
|
|
#[hdl]
|
|
let input_src_regs = wire(mop_ty.src_regs_ty());
|
|
connect(
|
|
input_src_regs,
|
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
|
);
|
|
#[hdl]
|
|
let input_src_regs_valid = wire();
|
|
connect(input_src_regs_valid, [true; COMMON_MOP_SRC_LEN]);
|
|
let mut unit_output_regs_valid: Vec<MemBuilder<Bool>> = (0..unit_output_writes.ty().len())
|
|
.map(|unit_index| {
|
|
let mut mem = memory_with_loc(
|
|
&format!("unit_{unit_index}_output_regs_valid"),
|
|
Bool,
|
|
SourceLocation::caller(),
|
|
);
|
|
mem.depth(1 << config.get().out_reg_num_width);
|
|
mem
|
|
})
|
|
.collect();
|
|
for unit_index in 0..unit_output_writes.ty().len() {
|
|
let mut unit_output_regs = memory_with_loc(
|
|
&format!("unit_{unit_index}_output_regs"),
|
|
PRegValue,
|
|
SourceLocation::caller(),
|
|
);
|
|
unit_output_regs.depth(1 << config.get().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(PRegNum[config]);
|
|
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);
|
|
}
|
|
}
|
|
|
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
|
let read_port = unit_output_regs_valid[unit_index].new_read_port();
|
|
let p_reg_num = input_src_regs[src_index].cast_bits_to(PRegNum[config]);
|
|
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(input_src_regs_valid[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()));
|
|
let ready_write_port = unit_output_regs_valid[unit_index].new_write_port();
|
|
connect_any(ready_write_port.addr, 0u8);
|
|
connect(ready_write_port.en, false);
|
|
connect(ready_write_port.clk, cd.clk);
|
|
connect(ready_write_port.data, true);
|
|
connect(ready_write_port.mask, true);
|
|
#[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);
|
|
connect_any(ready_write_port.addr, unit_output_write.which.value);
|
|
connect(ready_write_port.en, true);
|
|
let p_reg_num = #[hdl]
|
|
PRegNum::<_> {
|
|
unit_num: UnitNum[config].from_index(unit_index),
|
|
unit_out_reg: unit_output_write.which,
|
|
};
|
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
|
#[hdl]
|
|
if input_src_regs[src_index].cmp_eq(p_reg_num.cast_to_bits()) {
|
|
connect(input_src_regs_valid[src_index], true);
|
|
}
|
|
}
|
|
}
|
|
let free_write_port = unit_output_regs_valid[unit_index].new_write_port();
|
|
connect_any(free_write_port.addr, 0u8);
|
|
connect(free_write_port.en, false);
|
|
connect(free_write_port.clk, cd.clk);
|
|
connect(free_write_port.data, false);
|
|
connect(free_write_port.mask, true);
|
|
#[hdl]
|
|
if let HdlSome(unit_reg_free) = unit_reg_frees[unit_index] {
|
|
connect_any(free_write_port.addr, unit_reg_free.value);
|
|
connect(free_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,
|
|
config,
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
connect(
|
|
unit_to_reg_alloc.output,
|
|
unit_to_reg_alloc.output.ty().HdlNone(),
|
|
);
|
|
|
|
#[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(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(
|
|
input_mop_src_regs,
|
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
|
);
|
|
MOp::connect_src_regs(mop, input_mop_src_regs);
|
|
let src_ready_flags = wire_with_loc(
|
|
"input_in_flight_op_src_ready_flags",
|
|
SourceLocation::caller(),
|
|
StaticType::TYPE,
|
|
);
|
|
connect(src_ready_flags, input_src_regs_valid);
|
|
connect(input_src_regs, input_mop_src_regs);
|
|
#[hdl]
|
|
if unit_to_reg_alloc.cancel_input.cmp_ne(HdlSome(
|
|
#[hdl]
|
|
UnitCancelInput::<_> {
|
|
which: MOp::dest_reg(mop),
|
|
},
|
|
)) {
|
|
connect(
|
|
input_in_flight_op,
|
|
HdlSome(
|
|
#[hdl]
|
|
InFlightOp::<_> {
|
|
state: InFlightOpState.Ready(),
|
|
mop,
|
|
pc,
|
|
src_ready_flags,
|
|
},
|
|
),
|
|
);
|
|
}
|
|
#[hdl]
|
|
if let HdlSome(empty_op_index) = in_flight_ops_summary.empty_op_index {
|
|
connect(in_flight_ops[empty_op_index], input_in_flight_op);
|
|
}
|
|
}
|
|
|
|
#[hdl]
|
|
let in_flight_op_next_state = wire(Array[HdlOption[InFlightOpState]][max_in_flight]);
|
|
#[hdl]
|
|
let in_flight_op_next_src_ready_flags =
|
|
wire(Array[in_flight_op_ty.src_ready_flags][max_in_flight]);
|
|
#[hdl]
|
|
let in_flight_op_canceling = wire(Array[Bool][max_in_flight]);
|
|
#[hdl]
|
|
let in_flight_op_execute_starting = wire(Array[Bool][max_in_flight]);
|
|
#[hdl]
|
|
let in_flight_op_execute_ending = wire(Array[Bool][max_in_flight]);
|
|
for in_flight_op_index in 0..max_in_flight {
|
|
connect(
|
|
in_flight_op_next_src_ready_flags[in_flight_op_index],
|
|
[false; COMMON_MOP_SRC_LEN],
|
|
);
|
|
connect(in_flight_op_canceling[in_flight_op_index], false);
|
|
connect(in_flight_op_execute_starting[in_flight_op_index], false);
|
|
connect(in_flight_op_execute_ending[in_flight_op_index], false);
|
|
#[hdl]
|
|
if let HdlSome(in_flight_op) = in_flight_ops[in_flight_op_index] {
|
|
#[hdl]
|
|
let InFlightOp::<_> {
|
|
state,
|
|
mop,
|
|
pc,
|
|
src_ready_flags,
|
|
} = in_flight_op;
|
|
let which = MOp::dest_reg(mop);
|
|
let src_regs = wire_with_loc(
|
|
&format!("in_flight_op_src_regs_{in_flight_op_index}"),
|
|
SourceLocation::caller(),
|
|
mop_ty.src_regs_ty(),
|
|
);
|
|
connect(
|
|
src_regs,
|
|
repeat(PRegNum[config].const_zero().cast_to_bits(), ConstUsize),
|
|
);
|
|
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(in_flight_ops_summary.ty().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,
|
|
);
|
|
for unit_index in 0..unit_output_writes.ty().len() {
|
|
#[hdl]
|
|
if let HdlSome(unit_output_write) = unit_output_writes[unit_index] {
|
|
#[hdl]
|
|
let UnitOutputWrite::<_> {
|
|
which: unit_out_reg,
|
|
value: _,
|
|
} = unit_output_write;
|
|
let p_reg_num = #[hdl]
|
|
PRegNum::<_> {
|
|
unit_num: UnitNum[config].from_index(unit_index),
|
|
unit_out_reg,
|
|
};
|
|
for src_index in 0..COMMON_MOP_SRC_LEN {
|
|
#[hdl]
|
|
if p_reg_num.cast_to_bits().cmp_eq(src_regs[src_index]) {
|
|
connect(
|
|
in_flight_op_next_src_ready_flags[in_flight_op_index][src_index],
|
|
true,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
connect(
|
|
in_flight_op_canceling[in_flight_op_index],
|
|
unit_to_reg_alloc.cancel_input.cmp_eq(HdlSome(
|
|
#[hdl]
|
|
UnitCancelInput::<_> { which },
|
|
)),
|
|
);
|
|
|
|
#[hdl]
|
|
if let HdlSome(execute_end) = execute_end {
|
|
#[hdl]
|
|
let ExecuteEnd::<_, _> { unit_output } = execute_end;
|
|
#[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]
|
|
match state {
|
|
InFlightOpState::Running | InFlightOpState::Ready => {
|
|
connect(unit_to_reg_alloc.output, HdlSome(unit_output))
|
|
}
|
|
InFlightOpState::CanceledAndRunning => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#[hdl]
|
|
if let HdlSome(execute_start) = ReadyValid::firing_data(execute_start) {
|
|
#[hdl]
|
|
if which.cmp_eq(MOp::dest_reg(execute_start.mop)) {
|
|
connect(in_flight_op_execute_starting[in_flight_op_index], true);
|
|
}
|
|
}
|
|
let connect_next_state = |f| {
|
|
InFlightOpState::connect_next_state(
|
|
in_flight_op_canceling[in_flight_op_index],
|
|
in_flight_op_execute_starting[in_flight_op_index],
|
|
in_flight_op_execute_ending[in_flight_op_index],
|
|
f,
|
|
in_flight_op_next_state[in_flight_op_index],
|
|
);
|
|
};
|
|
#[hdl]
|
|
match state {
|
|
InFlightOpState::Ready => connect_next_state(InFlightOpState::ready_next_state),
|
|
InFlightOpState::Running => connect_next_state(InFlightOpState::running_next_state),
|
|
InFlightOpState::CanceledAndRunning => {
|
|
connect_next_state(InFlightOpState::canceled_and_running_next_state);
|
|
}
|
|
}
|
|
#[hdl]
|
|
if let HdlSome(state) = in_flight_op_next_state[in_flight_op_index] {
|
|
connect(
|
|
in_flight_ops[in_flight_op_index],
|
|
HdlSome(
|
|
#[hdl]
|
|
InFlightOp::<_> {
|
|
state,
|
|
mop,
|
|
pc,
|
|
src_ready_flags: in_flight_op_next_src_ready_flags[in_flight_op_index],
|
|
},
|
|
),
|
|
);
|
|
} else {
|
|
connect(
|
|
in_flight_ops[in_flight_op_index],
|
|
HdlOption[in_flight_op_ty].HdlNone(),
|
|
);
|
|
}
|
|
} else {
|
|
connect(in_flight_op_next_state[in_flight_op_index], HdlNone());
|
|
}
|
|
}
|
|
}
|