reg_alloc: add writes to rename table
This commit is contained in:
parent
64566f718f
commit
1084278f34
|
@ -2,7 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
use crate::{unit::UnitMOp, util::range_u32_len};
|
||||
use fayalite::{expr::ops::ArrayLiteral, intern::Interned, prelude::*};
|
||||
use std::{marker::PhantomData, ops::Range};
|
||||
use std::{fmt, marker::PhantomData, ops::Range};
|
||||
|
||||
pub mod power_isa;
|
||||
|
||||
|
@ -668,6 +668,29 @@ pub struct MOpDestReg {
|
|||
pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
pub enum RenameTableName {
|
||||
/// the large rename table for normal registers (has less read/write ports)
|
||||
Normal,
|
||||
/// a special small rename table (for flags and stuff, since it has more read/write ports)
|
||||
Special,
|
||||
}
|
||||
|
||||
impl RenameTableName {
|
||||
pub const fn reg_range(self) -> std::ops::Range<u32> {
|
||||
match self {
|
||||
Self::Normal => MOpRegNum::NORMAL_REG_NUMS,
|
||||
Self::Special => MOpRegNum::SPECIAL_REG_NUMS,
|
||||
}
|
||||
}
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Normal => "rename_table_normal",
|
||||
Self::Special => "rename_table_special",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub enum MOpDestRegKind {
|
||||
NormalReg {
|
||||
|
@ -682,6 +705,69 @@ pub enum MOpDestRegKind {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MOpDestRegName {
|
||||
base_name: &'static str,
|
||||
index: usize,
|
||||
reg_num: Option<u32>,
|
||||
}
|
||||
|
||||
impl fmt::Display for MOpDestRegName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
base_name,
|
||||
index,
|
||||
reg_num,
|
||||
} = self;
|
||||
write!(f, "{base_name}{index}")?;
|
||||
if let Some(reg_num) = reg_num {
|
||||
write!(f, "_r{reg_num:02X}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl MOpDestRegKind {
|
||||
pub const fn reg_range(self) -> std::ops::Range<u32> {
|
||||
match self {
|
||||
Self::NormalReg { .. } => MOpRegNum::NORMAL_REG_NUMS,
|
||||
Self::FlagReg { .. } => MOpRegNum::FLAG_REG_NUMS,
|
||||
}
|
||||
}
|
||||
pub const fn rename_table_names(self) -> &'static [RenameTableName] {
|
||||
match self {
|
||||
Self::NormalReg { .. } => &[RenameTableName::Normal, RenameTableName::Special],
|
||||
Self::FlagReg { .. } => &[RenameTableName::Special],
|
||||
}
|
||||
}
|
||||
pub fn fixed_reg_num(self) -> Option<u32> {
|
||||
match self {
|
||||
Self::NormalReg { dest_reg_index: _ } => None,
|
||||
Self::FlagReg {
|
||||
flag_reg_index: _,
|
||||
reg_num,
|
||||
} => Some(reg_num),
|
||||
}
|
||||
}
|
||||
pub fn reg_name(self) -> MOpDestRegName {
|
||||
match self {
|
||||
Self::NormalReg { dest_reg_index } => MOpDestRegName {
|
||||
base_name: "dest",
|
||||
index: dest_reg_index,
|
||||
reg_num: None,
|
||||
},
|
||||
Self::FlagReg {
|
||||
flag_reg_index,
|
||||
reg_num,
|
||||
} => MOpDestRegName {
|
||||
base_name: "flag",
|
||||
index: flag_reg_index,
|
||||
reg_num: Some(reg_num),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MOpDestReg {
|
||||
pub const NORMAL_REG_COUNT: usize = 2;
|
||||
pub const REG_COUNT: usize = Self::NORMAL_REG_COUNT + range_u32_len(&MOpRegNum::FLAG_REG_NUMS);
|
||||
|
|
|
@ -3,17 +3,22 @@
|
|||
use crate::{
|
||||
config::CpuConfig,
|
||||
instruction::{
|
||||
MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN,
|
||||
MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum,
|
||||
COMMON_MOP_SRC_LEN,
|
||||
},
|
||||
unit::{TrapData, UnitTrait},
|
||||
util::tree_reduce::tree_reduce_with_state,
|
||||
};
|
||||
use fayalite::{
|
||||
module::{instance_with_loc, wire_with_loc},
|
||||
memory::{splat_mask, WriteStruct},
|
||||
module::{instance_with_loc, memory_with_loc, wire_with_loc},
|
||||
prelude::*,
|
||||
util::ready_valid::ReadyValid,
|
||||
};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::{
|
||||
collections::{BTreeMap, VecDeque},
|
||||
num::NonZeroUsize,
|
||||
};
|
||||
|
||||
pub mod unit_free_regs_tracker;
|
||||
|
||||
|
@ -55,15 +60,23 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
);
|
||||
// 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());
|
||||
let mut rename_table_mems = BTreeMap::<RenameTableName, MemBuilder<_>>::new();
|
||||
|
||||
// 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());
|
||||
for reg_kind in MOpDestReg::REG_KINDS {
|
||||
for &rename_table_name in reg_kind.rename_table_names() {
|
||||
rename_table_mems
|
||||
.entry(rename_table_name)
|
||||
.or_insert_with(|| {
|
||||
let mut mem = memory_with_loc(
|
||||
&format!("{}_mem", rename_table_name.as_str()),
|
||||
config.p_reg_num(),
|
||||
SourceLocation::caller(),
|
||||
);
|
||||
mem.depth(rename_table_name.reg_range().len());
|
||||
mem
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
let available_units =
|
||||
|
@ -92,29 +105,28 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
struct RenameTableReadPort<T> {
|
||||
addr: MOpRegNum,
|
||||
#[hdl(flip)]
|
||||
data: HdlOption<T>,
|
||||
data: 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 rename_table_read_ports: [_; COMMON_MOP_SRC_LEN] = std::array::from_fn(|src_index| {
|
||||
let wire = wire_with_loc(
|
||||
&format!("{table_name}_{fetch_index}_src_{src_index}"),
|
||||
&format!("rename_{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());
|
||||
connect(wire.data, config.p_reg_num().const_zero());
|
||||
for (&rename_table_name, mem) in &mut rename_table_mems {
|
||||
let table_name = rename_table_name.as_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 reg_range = rename_table_name.reg_range();
|
||||
#[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));
|
||||
connect(wire.data, read_port.data);
|
||||
for prev_fetch_index in 0..fetch_index {
|
||||
#[hdl]
|
||||
if let HdlSome(decoded_insn) =
|
||||
|
@ -125,10 +137,16 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
renamed_mops_out_reg[prev_fetch_index]
|
||||
{
|
||||
let dest_reg = MOpTrait::dest_reg(decoded_insn.mop);
|
||||
for dest_reg in MOpDestReg::regs(dest_reg) {
|
||||
for (dest_reg, reg_kind) in MOpDestReg::regs(dest_reg)
|
||||
.into_iter()
|
||||
.zip(MOpDestReg::REG_KINDS)
|
||||
{
|
||||
if reg_kind.rename_table_names().contains(&rename_table_name) {
|
||||
#[hdl]
|
||||
if dest_reg.value.cmp_eq(wire.addr.value) {
|
||||
connect(wire.data, HdlSome(renamed_mop_out_reg));
|
||||
connect(wire.data, renamed_mop_out_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,25 +154,38 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
}
|
||||
}
|
||||
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",
|
||||
)
|
||||
});
|
||||
let mut rename_table_write_ports = BTreeMap::<RenameTableName, VecDeque<_>>::new();
|
||||
for reg_kind in MOpDestReg::REG_KINDS {
|
||||
for &rename_table_name in reg_kind.rename_table_names() {
|
||||
let mem = rename_table_mems
|
||||
.get_mut(&rename_table_name)
|
||||
.expect("already added all RenameTableName values");
|
||||
let write_ports = rename_table_write_ports
|
||||
.entry(rename_table_name)
|
||||
.or_default();
|
||||
let write_port_ = mem.new_write_port();
|
||||
let table_name = rename_table_name.as_str();
|
||||
let write_port = wire_with_loc(
|
||||
&format!("{table_name}_{fetch_index}_{}", reg_kind.reg_name()),
|
||||
SourceLocation::caller(),
|
||||
Expr::ty(write_port_),
|
||||
);
|
||||
connect(write_port_, write_port);
|
||||
write_ports.push_back(write_port);
|
||||
connect_any(
|
||||
write_port,
|
||||
#[hdl]
|
||||
WriteStruct::<_, _> {
|
||||
addr: 0_hdl_u0,
|
||||
en: false,
|
||||
clk: cd.clk,
|
||||
data: Expr::ty(write_port.data).uninit(),
|
||||
mask: splat_mask(config.p_reg_num(), true.to_expr()),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
#[hdl]
|
||||
if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data {
|
||||
connect(
|
||||
|
@ -171,31 +202,41 @@ pub fn reg_alloc(config: &CpuConfig) {
|
|||
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);
|
||||
connect(
|
||||
rename_table_read_ports[src_index].addr,
|
||||
#[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()
|
||||
MOpRegNum { value: src_reg },
|
||||
);
|
||||
rename_table_read_ports[src_index].data.cast_to_bits()
|
||||
},
|
||||
)),
|
||||
);
|
||||
// TODO: write dest_reg to rename table
|
||||
// rename_table_mem.new_write_port()
|
||||
for (reg, reg_kind) in MOpDestReg::regs(dest_reg)
|
||||
.into_iter()
|
||||
.zip(MOpDestReg::REG_KINDS)
|
||||
{
|
||||
for &rename_table_name in reg_kind.rename_table_names() {
|
||||
let Some(write_ports) =
|
||||
rename_table_write_ports.get_mut(&rename_table_name)
|
||||
else {
|
||||
unreachable!();
|
||||
};
|
||||
let Some(write_port) = write_ports.pop_front() else {
|
||||
unreachable!();
|
||||
};
|
||||
let reg_range = rename_table_name.reg_range();
|
||||
#[hdl]
|
||||
if reg.value.cmp_ge(reg_range.start) & reg.value.cmp_lt(reg_range.end) {
|
||||
connect(write_port.data, renamed_mop_out_reg);
|
||||
if let Some(fixed_reg_num) = reg_kind.fixed_reg_num() {
|
||||
connect_any(write_port.addr, fixed_reg_num - reg_range.start);
|
||||
} else {
|
||||
connect_any(write_port.addr, reg.value - reg_range.start);
|
||||
}
|
||||
connect(write_port.en, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
connect(
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue