working on reg_alloc

This commit is contained in:
Jacob Lifshay 2025-02-06 21:28:30 -08:00
parent 88eff5952b
commit 7efcd872b5
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
10 changed files with 112441 additions and 7174 deletions

View file

@ -2,7 +2,9 @@
// See Notices.txt for copyright information
use crate::{
config::CpuConfig,
instruction::MOp,
instruction::{
MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN,
},
unit::{TrapData, UnitTrait},
util::tree_reduce::tree_reduce_with_state,
};
@ -17,7 +19,7 @@ pub mod unit_free_regs_tracker;
#[hdl]
pub struct FetchedDecodedMOp {
pub uop: MOp,
pub mop: 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)
@ -52,11 +54,27 @@ pub fn reg_alloc(config: &CpuConfig) {
HdlNone(),
);
// TODO: finish
// the large rename table for normal registers (has less read/write ports)
#[hdl]
let mut rename_table_normal_mem = memory(config.p_reg_num());
rename_table_normal_mem.depth(MOpRegNum::NORMAL_REG_NUMS.len());
// a special small rename table (for flags and stuff, since it has more read/write ports)
#[hdl]
let mut rename_table_special_mem = memory(config.p_reg_num());
rename_table_special_mem.depth(MOpRegNum::SPECIAL_REG_NUMS.len());
#[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()]);
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()]);
#[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() {
connect(
fetch_decode_interface.decoded_insns[fetch_index].ready,
@ -66,50 +84,160 @@ pub fn reg_alloc(config: &CpuConfig) {
available_units[fetch_index],
repeat(false, config.unit_kinds.len()),
);
connect(
renamed_mops[fetch_index],
Expr::ty(renamed_mops).element().HdlNone(),
);
#[hdl]
struct RenameTableReadPort<T> {
addr: MOpRegNum,
#[hdl(flip)]
data: HdlOption<T>,
}
let make_rename_table_read_port =
|mem: &mut MemBuilder<_>,
reg_range: std::ops::Range<u32>,
src_index: usize,
table_name: &str| {
let read_port = mem.new_read_port();
connect(read_port.clk, cd.clk);
connect_any(read_port.addr, 0u8);
connect(read_port.en, false);
let wire = wire_with_loc(
&format!("{table_name}_{fetch_index}_src_{src_index}"),
SourceLocation::caller(),
RenameTableReadPort[config.p_reg_num()],
);
connect(wire.addr, MOpRegNum::const_zero());
connect(wire.data, Expr::ty(wire.data).HdlNone());
#[hdl]
if wire.addr.value.cmp_ge(reg_range.start) & wire.addr.value.cmp_lt(reg_range.end) {
connect_any(read_port.addr, wire.addr.value - reg_range.start);
connect(read_port.en, true);
connect(wire.data, HdlSome(read_port.data));
for prev_fetch_index in 0..fetch_index {
#[hdl]
if let HdlSome(decoded_insn) =
fetch_decode_interface.decoded_insns[prev_fetch_index].data
{
#[hdl]
if let HdlSome(renamed_mop_out_reg) =
renamed_mops_out_reg[prev_fetch_index]
{
let dest_reg = MOpTrait::dest_reg(decoded_insn.mop);
for dest_reg in MOpDestReg::regs(dest_reg) {
#[hdl]
if dest_reg.value.cmp_eq(wire.addr.value) {
connect(wire.data, HdlSome(renamed_mop_out_reg));
}
}
}
}
}
}
wire
};
let rename_table_normal_read_ports: [_; COMMON_MOP_SRC_LEN] =
std::array::from_fn(|src_index| {
make_rename_table_read_port(
&mut rename_table_normal_mem,
MOpRegNum::NORMAL_REG_NUMS,
src_index,
"rename_table_normal",
)
});
let rename_table_special_read_ports: [_; COMMON_MOP_SRC_LEN] =
std::array::from_fn(|src_index| {
make_rename_table_read_port(
&mut rename_table_special_mem,
MOpRegNum::FLAG_REG_NUMS,
src_index,
"rename_table_special",
)
});
#[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)),
config.available_units_for_kind(MOp::kind(decoded_insn.mop)),
);
#[hdl]
if let HdlSome(renamed_mop_out_reg) = renamed_mops_out_reg[fetch_index] {
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| {
let src_reg = #[hdl]
MOpRegNum { value: src_reg };
let renamed_src_reg = wire_with_loc(
&format!("renamed_src_reg_{fetch_index}_{src_index}"),
SourceLocation::caller(),
config.p_reg_num(),
);
connect(rename_table_normal_read_ports[src_index].addr, src_reg);
connect(rename_table_special_read_ports[src_index].addr, src_reg);
#[hdl]
if let HdlSome(v) = rename_table_normal_read_ports[src_index].data {
connect(renamed_src_reg, v);
} else if let HdlSome(v) =
rename_table_special_read_ports[src_index].data
{
connect(renamed_src_reg, v);
} else {
connect(renamed_src_reg, config.p_reg_num().const_zero());
}
renamed_src_reg.cast_to_bits()
},
)),
);
// TODO: write dest_reg to rename table
// rename_table_mem.new_write_port()
}
}
connect(
selected_unit_nums[fetch_index],
selected_unit_indexes[fetch_index],
tree_reduce_with_state(
0..config.unit_kinds.len(),
&mut 0usize,
|_state, unit_index| {
let selected_unit_leaf = wire_with_loc(
&format!("selected_unit_leaf_{fetch_index}_{unit_index}"),
let selected_unit_index_leaf = wire_with_loc(
&format!("selected_unit_index_leaf_{fetch_index}_{unit_index}"),
SourceLocation::caller(),
HdlOption[config.unit_num()],
HdlOption[UInt[config.unit_num_width()]],
);
connect(selected_unit_leaf, HdlOption[config.unit_num()].HdlNone());
let unit_num = wire_with_loc(
&format!("unit_num_{fetch_index}_{unit_index}"),
connect(
selected_unit_index_leaf,
Expr::ty(selected_unit_index_leaf).HdlNone(),
);
let unit_index_wire = wire_with_loc(
&format!("unit_index_{fetch_index}_{unit_index}"),
SourceLocation::caller(),
config.unit_num(),
UInt[config.unit_num_width()],
);
connect_any(unit_num.value, unit_index);
connect_any(unit_index_wire, unit_index);
#[hdl]
if available_units[fetch_index][unit_index] {
connect(selected_unit_leaf, HdlSome(unit_num))
connect(selected_unit_index_leaf, HdlSome(unit_index_wire))
}
selected_unit_leaf
selected_unit_index_leaf
},
|state, l, r| {
let selected_unit_node = wire_with_loc(
&format!("selected_unit_node_{fetch_index}_{state}"),
let selected_unit_index_node = wire_with_loc(
&format!("selected_unit_index_node_{fetch_index}_{state}"),
SourceLocation::caller(),
Expr::ty(l),
);
*state += 1;
connect(selected_unit_node, l);
connect(selected_unit_index_node, l);
#[hdl]
if let HdlNone = l {
connect(selected_unit_node, r);
connect(selected_unit_index_node, r);
}
selected_unit_node
selected_unit_index_node
},
)
.expect("expected at least one unit"),
@ -120,14 +248,21 @@ pub fn reg_alloc(config: &CpuConfig) {
// TODO: handle assigning multiple instructions to a unit at a time
for later_fetch_index in fetch_index + 1..config.fetch_width.get() {
#[hdl]
if let HdlSome(selected_unit_num) = selected_unit_nums[fetch_index] {
if let HdlSome(selected_unit_index) = selected_unit_indexes[fetch_index] {
connect(
available_units[later_fetch_index][selected_unit_num.value],
available_units[later_fetch_index][selected_unit_index],
false,
);
}
}
}
connect(
renamed_mops_out_reg,
repeat(
HdlOption[config.p_reg_num()].HdlNone(),
config.fetch_width.get(),
),
);
for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() {
let dyn_unit = unit_kind.unit(config);
let unit = instance_with_loc(
@ -136,6 +271,7 @@ pub fn reg_alloc(config: &CpuConfig) {
SourceLocation::caller(),
);
connect(dyn_unit.cd(unit), cd);
let unit_input = dyn_unit.input(unit);
// 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
@ -156,6 +292,7 @@ pub fn reg_alloc(config: &CpuConfig) {
HdlOption[UInt[config.out_reg_num_width]].uninit(), // FIXME: just for debugging
);
connect(unit_free_regs_tracker.alloc_out[0].ready, false);
connect(unit_input.data, Expr::ty(unit_input).data.HdlNone());
for fetch_index in 0..config.fetch_width.get() {
#[hdl]
if let HdlNone = unit_free_regs_tracker.alloc_out[0].data {
@ -163,10 +300,45 @@ pub fn reg_alloc(config: &CpuConfig) {
connect(available_units[fetch_index][unit_index], false);
}
#[hdl]
if let HdlSome(unit_num) = selected_unit_nums[fetch_index] {
if !unit_input.ready {
// must come after to override connects in loops above
connect(available_units[fetch_index][unit_index], false);
}
#[hdl]
if let HdlSome(selected_unit_index) = selected_unit_indexes[fetch_index] {
#[hdl]
if unit_num.value.cmp_eq(unit_index) {
if selected_unit_index.cmp_eq(unit_index) {
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))
{
connect(unit_input.data, HdlSome(renamed_mop));
} else {
connect(
unit_input.data,
HdlSome(Expr::ty(unit_input).data.HdlSome.uninit()),
);
// FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
}
#[hdl]
if let HdlSome(unit_out_reg) = unit_free_regs_tracker.alloc_out[0].data {
let unit_num = config.unit_num().from_index(unit_index);
let unit_out_reg = #[hdl]
UnitOutRegNum {
value: unit_out_reg,
};
connect(
renamed_mops_out_reg[fetch_index],
HdlSome(
#[hdl]
PRegNum {
unit_num,
unit_out_reg,
},
),
);
}
}
}
}