start adding ROB
This commit is contained in:
		
							parent
							
								
									4ff75313e7
								
							
						
					
					
						commit
						6c91d1b0b0
					
				
					 4 changed files with 32643 additions and 30962 deletions
				
			
		| 
						 | 
				
			
			@ -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> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
											
										
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue