forked from libre-chip/cpu
working on reg_alloc
This commit is contained in:
parent
88eff5952b
commit
7efcd872b5
10 changed files with 112441 additions and 7174 deletions
|
|
@ -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,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue