forked from libre-chip/cpu
WIP implementing reg_alloc
This commit is contained in:
parent
1a72425156
commit
b51109f4f6
4 changed files with 146 additions and 5 deletions
|
|
@ -1,11 +1,128 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
// See Notices.txt for copyright information
|
||||
use crate::config::CpuConfig;
|
||||
use fayalite::prelude::*;
|
||||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{MOp, UnitNum},
|
||||
unit::{TrapData, UnitTrait},
|
||||
util::tree_reduce::{tree_reduce, tree_reduce_with_state},
|
||||
};
|
||||
use fayalite::{module::instance_with_loc, prelude::*, util::ready_valid::ReadyValid};
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
pub mod unit_free_regs_tracker;
|
||||
|
||||
#[hdl_module]
|
||||
pub fn reg_alloc(config: CpuConfig) {
|
||||
todo!()
|
||||
#[hdl]
|
||||
pub struct FetchedDecodedMOp {
|
||||
pub uop: MOp,
|
||||
/// true if pc doesn't have to be related to the previous instruction.
|
||||
/// (enable to stop detecting when the current instruction isn't
|
||||
/// supposed to be run next, e.g. on branch mis-prediction)
|
||||
pub is_unrelated_pc: Bool,
|
||||
pub pc: UInt<64>,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub enum FetchDecodeSpecialOp {
|
||||
Trap(TrapData),
|
||||
ICacheFlush,
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
pub struct FetchDecodeInterface<FetchWidth: Size> {
|
||||
pub decoded_insns: ArrayType<ReadyValid<FetchedDecodedMOp>, FetchWidth>,
|
||||
#[hdl(flip)]
|
||||
pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>,
|
||||
}
|
||||
|
||||
#[hdl_module]
|
||||
/// combination register allocator, register renaming, unit selection, and retire handling
|
||||
pub fn reg_alloc(config: &CpuConfig) {
|
||||
#[hdl]
|
||||
let cd: ClockDomain = m.input();
|
||||
#[hdl]
|
||||
let fetch_decode_interface: FetchDecodeInterface<DynSize> =
|
||||
m.input(FetchDecodeInterface[config.fetch_width.get()]);
|
||||
// TODO: propagate traps, branch mis-predictions, and special ops
|
||||
connect(
|
||||
fetch_decode_interface.fetch_decode_special_op.data,
|
||||
HdlNone(),
|
||||
);
|
||||
// TODO: finish
|
||||
#[hdl]
|
||||
let available_units =
|
||||
wire(Array[Array[Bool][config.unit_kinds.len()]][config.fetch_width.get()]);
|
||||
#[hdl]
|
||||
let selected_unit_nums = wire(Array[HdlOption[config.unit_num()]][config.fetch_width.get()]);
|
||||
for fetch_index in 0..config.fetch_width.get() {
|
||||
connect(
|
||||
fetch_decode_interface.decoded_insns[fetch_index].ready,
|
||||
true,
|
||||
);
|
||||
connect(
|
||||
available_units[fetch_index],
|
||||
repeat(false, config.unit_kinds.len()),
|
||||
);
|
||||
#[hdl]
|
||||
if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data {
|
||||
connect(
|
||||
available_units[fetch_index],
|
||||
config.available_units_for_kind(MOp::kind(decoded_insn.uop)),
|
||||
);
|
||||
}
|
||||
connect(
|
||||
selected_unit_nums[fetch_index],
|
||||
tree_reduce_with_state(
|
||||
0..config.unit_kinds.len(),
|
||||
&mut (),
|
||||
|_state, unit_index| {
|
||||
#[hdl]
|
||||
let selected_unit_leaf = wire(HdlOption[config.unit_num()]);
|
||||
connect(selected_unit_leaf, HdlOption[config.unit_num()].HdlNone());
|
||||
#[hdl]
|
||||
let unit_num = wire(config.unit_num());
|
||||
connect_any(unit_num.value, unit_index);
|
||||
#[hdl]
|
||||
if available_units[fetch_index][unit_index] {
|
||||
connect(selected_unit_leaf, HdlSome(unit_num))
|
||||
}
|
||||
selected_unit_leaf
|
||||
},
|
||||
|_state, l, r| {
|
||||
#[hdl]
|
||||
let selected_unit_node = wire(Expr::ty(l));
|
||||
connect(selected_unit_node, l);
|
||||
#[hdl]
|
||||
if let HdlNone = l {
|
||||
connect(selected_unit_node, r);
|
||||
}
|
||||
selected_unit_node
|
||||
},
|
||||
)
|
||||
.expect("expected at least one unit"),
|
||||
);
|
||||
}
|
||||
for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() {
|
||||
let dyn_unit = unit_kind.unit(config);
|
||||
let unit = instance_with_loc(
|
||||
&format!("unit_{unit_index}"),
|
||||
dyn_unit.make_module(),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
connect(dyn_unit.cd(unit), cd);
|
||||
// TODO: handle assigning multiple instructions to a unit at a time
|
||||
let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap();
|
||||
// TODO: handle retiring multiple instructions from a unit at a time
|
||||
let retire_from_unit_at_once = NonZeroUsize::new(1).unwrap();
|
||||
let unit_free_regs_tracker = instance_with_loc(
|
||||
&format!("unit_{unit_index}_free_regs_tracker"),
|
||||
unit_free_regs_tracker::unit_free_regs_tracker(
|
||||
retire_from_unit_at_once,
|
||||
assign_to_unit_at_once,
|
||||
config.out_reg_num_width,
|
||||
),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
connect(unit_free_regs_tracker.cd, cd);
|
||||
// TODO: finish
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue