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
|
// See Notices.txt for copyright information
|
||||||
use crate::{unit::UnitMOp, util::range_u32_len};
|
use crate::{unit::UnitMOp, util::range_u32_len};
|
||||||
use fayalite::{expr::ops::ArrayLiteral, intern::Interned, prelude::*};
|
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;
|
pub mod power_isa;
|
||||||
|
|
||||||
|
@ -668,6 +668,29 @@ pub struct MOpDestReg {
|
||||||
pub flag_regs: Array<HdlOption<()>, { range_u32_len(&MOpRegNum::FLAG_REG_NUMS) }>,
|
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)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub enum MOpDestRegKind {
|
pub enum MOpDestRegKind {
|
||||||
NormalReg {
|
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 {
|
impl MOpDestReg {
|
||||||
pub const NORMAL_REG_COUNT: usize = 2;
|
pub const NORMAL_REG_COUNT: usize = 2;
|
||||||
pub const REG_COUNT: usize = Self::NORMAL_REG_COUNT + range_u32_len(&MOpRegNum::FLAG_REG_NUMS);
|
pub const REG_COUNT: usize = Self::NORMAL_REG_COUNT + range_u32_len(&MOpRegNum::FLAG_REG_NUMS);
|
||||||
|
|
|
@ -3,17 +3,22 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
config::CpuConfig,
|
config::CpuConfig,
|
||||||
instruction::{
|
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},
|
unit::{TrapData, UnitTrait},
|
||||||
util::tree_reduce::tree_reduce_with_state,
|
util::tree_reduce::tree_reduce_with_state,
|
||||||
};
|
};
|
||||||
use fayalite::{
|
use fayalite::{
|
||||||
module::{instance_with_loc, wire_with_loc},
|
memory::{splat_mask, WriteStruct},
|
||||||
|
module::{instance_with_loc, memory_with_loc, wire_with_loc},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
util::ready_valid::ReadyValid,
|
util::ready_valid::ReadyValid,
|
||||||
};
|
};
|
||||||
use std::num::NonZeroUsize;
|
use std::{
|
||||||
|
collections::{BTreeMap, VecDeque},
|
||||||
|
num::NonZeroUsize,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod unit_free_regs_tracker;
|
pub mod unit_free_regs_tracker;
|
||||||
|
|
||||||
|
@ -55,15 +60,23 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
);
|
);
|
||||||
// TODO: finish
|
// TODO: finish
|
||||||
|
|
||||||
// the large rename table for normal registers (has less read/write ports)
|
let mut rename_table_mems = BTreeMap::<RenameTableName, MemBuilder<_>>::new();
|
||||||
#[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)
|
for reg_kind in MOpDestReg::REG_KINDS {
|
||||||
#[hdl]
|
for &rename_table_name in reg_kind.rename_table_names() {
|
||||||
let mut rename_table_special_mem = memory(config.p_reg_num());
|
rename_table_mems
|
||||||
rename_table_special_mem.depth(MOpRegNum::SPECIAL_REG_NUMS.len());
|
.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]
|
#[hdl]
|
||||||
let available_units =
|
let available_units =
|
||||||
|
@ -92,29 +105,28 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
struct RenameTableReadPort<T> {
|
struct RenameTableReadPort<T> {
|
||||||
addr: MOpRegNum,
|
addr: MOpRegNum,
|
||||||
#[hdl(flip)]
|
#[hdl(flip)]
|
||||||
data: HdlOption<T>,
|
data: T,
|
||||||
}
|
}
|
||||||
let make_rename_table_read_port =
|
let rename_table_read_ports: [_; COMMON_MOP_SRC_LEN] = std::array::from_fn(|src_index| {
|
||||||
|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(
|
let wire = wire_with_loc(
|
||||||
&format!("{table_name}_{fetch_index}_src_{src_index}"),
|
&format!("rename_{fetch_index}_src_{src_index}"),
|
||||||
SourceLocation::caller(),
|
SourceLocation::caller(),
|
||||||
RenameTableReadPort[config.p_reg_num()],
|
RenameTableReadPort[config.p_reg_num()],
|
||||||
);
|
);
|
||||||
connect(wire.addr, MOpRegNum::const_zero());
|
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]
|
#[hdl]
|
||||||
if wire.addr.value.cmp_ge(reg_range.start) & wire.addr.value.cmp_lt(reg_range.end) {
|
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_any(read_port.addr, wire.addr.value - reg_range.start);
|
||||||
connect(read_port.en, true);
|
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 {
|
for prev_fetch_index in 0..fetch_index {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
if let HdlSome(decoded_insn) =
|
if let HdlSome(decoded_insn) =
|
||||||
|
@ -125,10 +137,16 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
renamed_mops_out_reg[prev_fetch_index]
|
renamed_mops_out_reg[prev_fetch_index]
|
||||||
{
|
{
|
||||||
let dest_reg = MOpTrait::dest_reg(decoded_insn.mop);
|
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]
|
#[hdl]
|
||||||
if dest_reg.value.cmp_eq(wire.addr.value) {
|
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
|
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]
|
#[hdl]
|
||||||
if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data {
|
if let HdlSome(decoded_insn) = fetch_decode_interface.decoded_insns[fetch_index].data {
|
||||||
connect(
|
connect(
|
||||||
|
@ -171,31 +202,41 @@ pub fn reg_alloc(config: &CpuConfig) {
|
||||||
renamed_mop_out_reg.unit_out_reg,
|
renamed_mop_out_reg.unit_out_reg,
|
||||||
config.p_reg_num_width(),
|
config.p_reg_num_width(),
|
||||||
&mut |src_reg, src_index| {
|
&mut |src_reg, src_index| {
|
||||||
let src_reg = #[hdl]
|
connect(
|
||||||
MOpRegNum { value: src_reg };
|
rename_table_read_ports[src_index].addr,
|
||||||
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]
|
#[hdl]
|
||||||
if let HdlSome(v) = rename_table_normal_read_ports[src_index].data {
|
MOpRegNum { value: src_reg },
|
||||||
connect(renamed_src_reg, v);
|
);
|
||||||
} else if let HdlSome(v) =
|
rename_table_read_ports[src_index].data.cast_to_bits()
|
||||||
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
|
for (reg, reg_kind) in MOpDestReg::regs(dest_reg)
|
||||||
// rename_table_mem.new_write_port()
|
.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(
|
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