forked from libre-chip/cpu
		
	WIP implementing reg_alloc
This commit is contained in:
		
							parent
							
								
									1a72425156
								
							
						
					
					
						commit
						b51109f4f6
					
				
					 4 changed files with 146 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -5,12 +5,14 @@ use crate::{
 | 
			
		|||
    unit::UnitKind,
 | 
			
		||||
};
 | 
			
		||||
use fayalite::prelude::*;
 | 
			
		||||
use std::num::NonZeroUsize;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
 | 
			
		||||
#[non_exhaustive]
 | 
			
		||||
pub struct CpuConfig {
 | 
			
		||||
    pub unit_kinds: Vec<UnitKind>,
 | 
			
		||||
    pub out_reg_num_width: usize,
 | 
			
		||||
    pub fetch_width: NonZeroUsize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CpuConfig {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -183,4 +183,5 @@ impl MOpRegNum {
 | 
			
		|||
    pub const CONST_ZERO_REG_NUM: u32 = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[hdl]
 | 
			
		||||
pub type MOp = UnitMOp<ConstUsize<{ MOpRegNum::WIDTH }>>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,128 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
use crate::config::CpuConfig;
 | 
			
		||||
use fayalite::prelude::*;
 | 
			
		||||
use crate::{
 | 
			
		||||
    config::CpuConfig,
 | 
			
		||||
    instruction::{MOp, UnitNum},
 | 
			
		||||
    unit::{TrapData, UnitTrait},
 | 
			
		||||
    util::tree_reduce::{tree_reduce, tree_reduce_with_state},
 | 
			
		||||
};
 | 
			
		||||
use fayalite::{module::instance_with_loc, prelude::*, util::ready_valid::ReadyValid};
 | 
			
		||||
use std::num::NonZeroUsize;
 | 
			
		||||
 | 
			
		||||
pub mod unit_free_regs_tracker;
 | 
			
		||||
 | 
			
		||||
#[hdl_module]
 | 
			
		||||
pub fn reg_alloc(config: CpuConfig) {
 | 
			
		||||
    todo!()
 | 
			
		||||
#[hdl]
 | 
			
		||||
pub struct FetchedDecodedMOp {
 | 
			
		||||
    pub uop: 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)
 | 
			
		||||
    pub is_unrelated_pc: Bool,
 | 
			
		||||
    pub pc: UInt<64>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[hdl]
 | 
			
		||||
pub enum FetchDecodeSpecialOp {
 | 
			
		||||
    Trap(TrapData),
 | 
			
		||||
    ICacheFlush,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[hdl]
 | 
			
		||||
pub struct FetchDecodeInterface<FetchWidth: Size> {
 | 
			
		||||
    pub decoded_insns: ArrayType<ReadyValid<FetchedDecodedMOp>, FetchWidth>,
 | 
			
		||||
    #[hdl(flip)]
 | 
			
		||||
    pub fetch_decode_special_op: ReadyValid<FetchDecodeSpecialOp>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[hdl_module]
 | 
			
		||||
/// combination register allocator, register renaming, unit selection, and retire handling
 | 
			
		||||
pub fn reg_alloc(config: &CpuConfig) {
 | 
			
		||||
    #[hdl]
 | 
			
		||||
    let cd: ClockDomain = m.input();
 | 
			
		||||
    #[hdl]
 | 
			
		||||
    let fetch_decode_interface: FetchDecodeInterface<DynSize> =
 | 
			
		||||
        m.input(FetchDecodeInterface[config.fetch_width.get()]);
 | 
			
		||||
    // TODO: propagate traps, branch mis-predictions, and special ops
 | 
			
		||||
    connect(
 | 
			
		||||
        fetch_decode_interface.fetch_decode_special_op.data,
 | 
			
		||||
        HdlNone(),
 | 
			
		||||
    );
 | 
			
		||||
    // TODO: finish
 | 
			
		||||
    #[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()]);
 | 
			
		||||
    for fetch_index in 0..config.fetch_width.get() {
 | 
			
		||||
        connect(
 | 
			
		||||
            fetch_decode_interface.decoded_insns[fetch_index].ready,
 | 
			
		||||
            true,
 | 
			
		||||
        );
 | 
			
		||||
        connect(
 | 
			
		||||
            available_units[fetch_index],
 | 
			
		||||
            repeat(false, config.unit_kinds.len()),
 | 
			
		||||
        );
 | 
			
		||||
        #[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)),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        connect(
 | 
			
		||||
            selected_unit_nums[fetch_index],
 | 
			
		||||
            tree_reduce_with_state(
 | 
			
		||||
                0..config.unit_kinds.len(),
 | 
			
		||||
                &mut (),
 | 
			
		||||
                |_state, unit_index| {
 | 
			
		||||
                    #[hdl]
 | 
			
		||||
                    let selected_unit_leaf = wire(HdlOption[config.unit_num()]);
 | 
			
		||||
                    connect(selected_unit_leaf, HdlOption[config.unit_num()].HdlNone());
 | 
			
		||||
                    #[hdl]
 | 
			
		||||
                    let unit_num = wire(config.unit_num());
 | 
			
		||||
                    connect_any(unit_num.value, unit_index);
 | 
			
		||||
                    #[hdl]
 | 
			
		||||
                    if available_units[fetch_index][unit_index] {
 | 
			
		||||
                        connect(selected_unit_leaf, HdlSome(unit_num))
 | 
			
		||||
                    }
 | 
			
		||||
                    selected_unit_leaf
 | 
			
		||||
                },
 | 
			
		||||
                |_state, l, r| {
 | 
			
		||||
                    #[hdl]
 | 
			
		||||
                    let selected_unit_node = wire(Expr::ty(l));
 | 
			
		||||
                    connect(selected_unit_node, l);
 | 
			
		||||
                    #[hdl]
 | 
			
		||||
                    if let HdlNone = l {
 | 
			
		||||
                        connect(selected_unit_node, r);
 | 
			
		||||
                    }
 | 
			
		||||
                    selected_unit_node
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
            .expect("expected at least one unit"),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    for (unit_index, &unit_kind) in config.unit_kinds.iter().enumerate() {
 | 
			
		||||
        let dyn_unit = unit_kind.unit(config);
 | 
			
		||||
        let unit = instance_with_loc(
 | 
			
		||||
            &format!("unit_{unit_index}"),
 | 
			
		||||
            dyn_unit.make_module(),
 | 
			
		||||
            SourceLocation::caller(),
 | 
			
		||||
        );
 | 
			
		||||
        connect(dyn_unit.cd(unit), cd);
 | 
			
		||||
        // 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
 | 
			
		||||
        let retire_from_unit_at_once = NonZeroUsize::new(1).unwrap();
 | 
			
		||||
        let unit_free_regs_tracker = instance_with_loc(
 | 
			
		||||
            &format!("unit_{unit_index}_free_regs_tracker"),
 | 
			
		||||
            unit_free_regs_tracker::unit_free_regs_tracker(
 | 
			
		||||
                retire_from_unit_at_once,
 | 
			
		||||
                assign_to_unit_at_once,
 | 
			
		||||
                config.out_reg_num_width,
 | 
			
		||||
            ),
 | 
			
		||||
            SourceLocation::caller(),
 | 
			
		||||
        );
 | 
			
		||||
        connect(unit_free_regs_tracker.cd, cd);
 | 
			
		||||
        // TODO: finish
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@ macro_rules! all_units {
 | 
			
		|||
        $(#[$enum_meta:meta])*
 | 
			
		||||
        $vis:vis enum $UnitMOpEnum:ident<$RegWidth:ident: Size> {
 | 
			
		||||
            $(
 | 
			
		||||
                #[create_dyn_unit_fn = $create_dyn_unit_fn:expr]
 | 
			
		||||
                $(#[$variant_meta:meta])*
 | 
			
		||||
                $Unit:ident($Op:ty),
 | 
			
		||||
            )*
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +36,14 @@ macro_rules! all_units {
 | 
			
		|||
            )*
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl $UnitKind {
 | 
			
		||||
            pub fn unit(self, config: &CpuConfig) -> DynUnit {
 | 
			
		||||
                match self {
 | 
			
		||||
                    $($UnitKind::$Unit => $create_dyn_unit_fn(config),)*
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl ToExpr for $UnitKind {
 | 
			
		||||
            type Type = $HdlUnitKind;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -98,8 +107,11 @@ all_units! {
 | 
			
		|||
    #[unit_kind = UnitKind]
 | 
			
		||||
    #[hdl]
 | 
			
		||||
    pub enum UnitMOp<RegWidth: Size> {
 | 
			
		||||
        #[create_dyn_unit_fn = |config| todo!()]
 | 
			
		||||
        AluBranch(AluBranchMOp<RegWidth>),
 | 
			
		||||
        #[create_dyn_unit_fn = |config| todo!()]
 | 
			
		||||
        L2RegisterFile(L2RegisterFileMOp<RegWidth>),
 | 
			
		||||
        #[create_dyn_unit_fn = |config| todo!()]
 | 
			
		||||
        LoadStore(LoadStoreMOp<RegWidth>),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -156,6 +168,7 @@ pub trait UnitTrait:
 | 
			
		|||
        &self,
 | 
			
		||||
        this: Expr<Self::Type>,
 | 
			
		||||
    ) -> Expr<ReadyValid<UnitOutput<DynSize, DynSize, Self::ExtraOut>>>;
 | 
			
		||||
    fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>;
 | 
			
		||||
 | 
			
		||||
    fn to_dyn(&self) -> DynUnit;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -217,6 +230,10 @@ impl UnitTrait for DynUnit {
 | 
			
		|||
        self.unit.output(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
 | 
			
		||||
        self.unit.cd(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_dyn(&self) -> DynUnit {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -264,6 +281,10 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T
 | 
			
		|||
        Expr::from_bundle(Expr::as_bundle(self.0.output(Expr::from_bundle(this))))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain> {
 | 
			
		||||
        self.0.cd(Expr::from_bundle(this))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_dyn(&self) -> DynUnit {
 | 
			
		||||
        let unit = self.intern();
 | 
			
		||||
        DynUnit {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue