start adding ROB

This commit is contained in:
Jacob Lifshay 2025-02-27 18:22:01 -08:00
parent 4ff75313e7
commit 6c91d1b0b0
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
4 changed files with 32643 additions and 30962 deletions

View file

@ -35,6 +35,7 @@ pub struct CpuConfig {
pub fetch_width: NonZeroUsize,
/// default value for [`UnitConfig::max_in_flight`]
pub default_unit_max_in_flight: NonZeroUsize,
pub rob_size: NonZeroUsize,
}
impl CpuConfig {
@ -51,12 +52,13 @@ impl CpuConfig {
};
v
};
pub fn new(units: Vec<UnitConfig>) -> Self {
pub fn new(units: Vec<UnitConfig>, rob_size: NonZeroUsize) -> Self {
Self {
units,
out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH,
fetch_width: Self::DEFAULT_FETCH_WIDTH,
default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT,
rob_size,
}
}
pub fn non_const_unit_nums(&self) -> std::ops::Range<usize> {

View file

@ -7,8 +7,9 @@ use crate::{
COMMON_MOP_SRC_LEN,
},
unit::{
unit_base::UnitInput, GlobalState, TrapData, UnitOutput, UnitOutputWrite, UnitResult,
UnitResultCompleted, UnitTrait,
unit_base::{UnitForwardingInfo, UnitInput},
GlobalState, TrapData, UnitOutput, UnitOutputWrite, UnitResult, UnitResultCompleted,
UnitTrait,
},
util::tree_reduce::tree_reduce_with_state,
};
@ -48,6 +49,145 @@ pub struct FetchDecodeInterface<FetchWidth: Size> {
pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>,
}
#[hdl]
struct ROBRenamedInsn<UnitNumWidth: Size, OutRegNumWidth: Size> {
mop_dest: MOpDestReg,
p_dest: PRegNum<UnitNumWidth, OutRegNumWidth>,
}
#[hdl]
struct ROBEntry<UnitNumWidth: Size, OutRegNumWidth: Size> {
renamed_insn: ROBRenamedInsn<UnitNumWidth, OutRegNumWidth>,
dest_written: Bool,
}
#[hdl_module]
fn rob(config: &CpuConfig) {
#[hdl]
let cd: ClockDomain = m.input();
#[hdl]
let renamed_insns_in: Array<ReadyValid<ROBRenamedInsn<DynSize, DynSize>>> = m.input(
Array[ReadyValid[ROBRenamedInsn[config.unit_num_width()][config.out_reg_num_width]]]
[config.fetch_width.get()],
);
#[hdl]
let unit_forwarding_info: UnitForwardingInfo<DynSize, DynSize, DynSize> =
m.input(config.unit_forwarding_info());
let rob_entry_ty = ROBEntry[config.unit_num_width()][config.out_reg_num_width];
#[hdl]
let rob = reg_builder()
.clock_domain(cd)
.no_reset(Array[rob_entry_ty][config.rob_size.get()]);
#[hdl]
let rob_valid_start = reg_builder()
.clock_domain(cd)
.reset(UInt::range(0..config.rob_size.get()).zero());
#[hdl]
let rob_valid_end = reg_builder()
.clock_domain(cd)
.reset(UInt::range(0..config.rob_size.get()).zero());
#[hdl]
let free_space = wire(UInt::range_inclusive(0..=config.rob_size.get()));
#[hdl]
if rob_valid_end.cmp_lt(rob_valid_start) {
// rob_valid_end wrapped around but start didn't
connect_any(
free_space,
rob_valid_end + config.rob_size.get() - rob_valid_start,
);
} else {
connect_any(free_space, rob_valid_end - rob_valid_start);
}
struct IndexAndRange {
index: Expr<UInt>,
range: std::ops::Range<usize>,
}
let mut next_write_index = IndexAndRange {
index: rob_valid_end,
range: 0..config.rob_size.get(),
};
for fetch_index in 0..config.fetch_width.get() {
let write_index = next_write_index;
let next_write_index_range = write_index.range.start..write_index.range.end + 1;
next_write_index = IndexAndRange {
index: wire_with_loc(
&format!("next_write_index_{fetch_index}"),
SourceLocation::caller(),
UInt::range(next_write_index_range.clone()),
),
range: next_write_index_range,
};
connect(
renamed_insns_in[fetch_index].ready,
fetch_index.cmp_lt(free_space),
);
#[hdl]
if let HdlSome(renamed_insn) = ReadyValid::firing_data(renamed_insns_in[fetch_index]) {
for i in write_index.range.clone() {
#[hdl]
if write_index.index.cmp_eq(i) {
connect(
rob[i % config.rob_size.get()],
#[hdl]
ROBEntry {
renamed_insn,
dest_written: false,
},
);
}
}
}
// TODO: optimize write_index chain better
connect_any(
next_write_index.index,
write_index.index
+ ReadyValid::firing(renamed_insns_in[fetch_index]).cast_to_static::<UInt<1>>(),
);
}
assert!(
config.rob_size >= config.fetch_width,
"rob_size ({}) is too small for fetch_width = {} -- next_write_index would overflow",
config.rob_size,
config.fetch_width,
);
#[hdl]
if next_write_index.index.cmp_lt(config.rob_size.get()) {
connect_any(rob_valid_end, next_write_index.index);
} else {
connect_any(
rob_valid_end,
next_write_index.index - config.rob_size.get(),
);
}
// TODO: optimize better, O(rob_size * unit_count) is too big here
for rob_index in 0..config.rob_size.get() {
for unit_index in 0..config.non_const_unit_nums().len() {
#[hdl]
if let HdlSome(unit_output_write) = unit_forwarding_info.unit_output_writes[unit_index]
{
#[hdl]
let UnitOutputWrite::<_> {
which: unit_out_reg,
value: _,
} = unit_output_write;
let p_reg_num = #[hdl]
PRegNum::<_, _> {
unit_num: config.unit_num().from_index(unit_index),
unit_out_reg,
};
#[hdl]
if rob[rob_index].renamed_insn.p_dest.cmp_eq(p_reg_num) {
connect(rob[rob_index].dest_written, true);
}
}
}
}
}
#[hdl_module]
/// combination register allocator, register renaming, unit selection, and retire handling
pub fn reg_alloc(config: &CpuConfig) {
@ -65,6 +205,10 @@ pub fn reg_alloc(config: &CpuConfig) {
);
// TODO: finish
#[hdl]
let rob = instance(rob(config));
connect(rob.cd, cd);
let mut rename_table_mems = BTreeMap::<RenameTableName, MemBuilder<_>>::new();
for reg_kind in MOpDestReg::REG_KINDS {
@ -94,10 +238,25 @@ pub fn reg_alloc(config: &CpuConfig) {
#[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() {
// TODO: finish
connect(
rob.renamed_insns_in[fetch_index].data,
Expr::ty(rob).renamed_insns_in.element().data.HdlNone(),
);
// TODO: finish
connect(
fetch_decode_interface.decoded_insns[fetch_index].ready,
true,
);
for prev_fetch_index in 0..fetch_index {
#[hdl]
if !fetch_decode_interface.decoded_insns[prev_fetch_index].ready {
connect(
fetch_decode_interface.decoded_insns[fetch_index].ready,
false,
);
}
}
connect(
available_units[fetch_index],
repeat(false, config.units.len()),
@ -316,6 +475,7 @@ pub fn reg_alloc(config: &CpuConfig) {
);
#[hdl]
let unit_forwarding_info = wire(config.unit_forwarding_info());
connect(rob.unit_forwarding_info, unit_forwarding_info);
for (unit_index, unit_config) in config.units.iter().enumerate() {
let dyn_unit = unit_config.kind.unit(config, unit_index);
let unit = instance_with_loc(

File diff suppressed because it is too large Load diff

View file

@ -21,10 +21,13 @@ use std::num::NonZeroUsize;
#[test]
fn test_reg_alloc() {
let _n = SourceLocation::normalize_files_for_tests();
let mut config = CpuConfig::new(vec![
UnitConfig::new(UnitKind::AluBranch),
UnitConfig::new(UnitKind::AluBranch),
]);
let mut config = CpuConfig::new(
vec![
UnitConfig::new(UnitKind::AluBranch),
UnitConfig::new(UnitKind::AluBranch),
],
NonZeroUsize::new(20).unwrap(),
);
config.fetch_width = NonZeroUsize::new(2).unwrap();
let m = reg_alloc(&config);
let mut sim = Simulation::new(m);