forked from libre-chip/cpu
		
	unit_base is basically finished, implemented AddSub[I], didn't check any tests yet
This commit is contained in:
		
							parent
							
								
									3f6e5cc600
								
							
						
					
					
						commit
						3bd5c77a3f
					
				
					 8 changed files with 21311 additions and 23900 deletions
				
			
		|  | @ -509,8 +509,10 @@ common_mop_struct! { | |||
|         #[common] | ||||
|         pub alu_common: AluCommonMOp<DestReg, SrcRegWidth, SrcCount>, | ||||
|         pub invert_src0: Bool, | ||||
|         /// * if this is `true`, use `alu_common.src[1]`'s [`PRegFlagsPowerISA::xer_ca`] as a carry-in/borrow-in
 | ||||
|         /// * else, use `alu_common.src[1]` as a normal addend
 | ||||
|         pub src1_is_carry_in: Bool, | ||||
|         pub invert_carry_in: Bool, | ||||
|         pub invert_carry_out: Bool, | ||||
|         pub add_pc: Bool, | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -6,7 +6,10 @@ use crate::{ | |||
|         MOp, MOpDestReg, MOpRegNum, MOpTrait, PRegNum, RenameTableName, UnitOutRegNum, | ||||
|         COMMON_MOP_SRC_LEN, | ||||
|     }, | ||||
|     unit::{unit_base::UnitForwardingInfo, TrapData, UnitTrait}, | ||||
|     unit::{ | ||||
|         unit_base::UnitInput, GlobalState, TrapData, UnitOutput, UnitOutputWrite, UnitResult, | ||||
|         UnitResultCompleted, UnitTrait, | ||||
|     }, | ||||
|     util::tree_reduce::tree_reduce_with_state, | ||||
| }; | ||||
| use fayalite::{ | ||||
|  | @ -17,7 +20,6 @@ use fayalite::{ | |||
| }; | ||||
| use std::{ | ||||
|     collections::{BTreeMap, VecDeque}, | ||||
|     marker::PhantomData, | ||||
|     num::NonZeroUsize, | ||||
| }; | ||||
| 
 | ||||
|  | @ -54,6 +56,8 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|     #[hdl] | ||||
|     let fetch_decode_interface: FetchDecodeInterface<DynSize> = | ||||
|         m.input(FetchDecodeInterface[config.fetch_width.get()]); | ||||
|     #[hdl] | ||||
|     let global_state: GlobalState = m.input(); | ||||
|     // TODO: propagate traps, branch mis-predictions, and special ops
 | ||||
|     connect( | ||||
|         fetch_decode_interface.fetch_decode_special_op.data, | ||||
|  | @ -85,7 +89,8 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|     let selected_unit_indexes = | ||||
|         wire(Array[HdlOption[UInt[config.unit_num_width()]]][config.fetch_width.get()]); | ||||
|     #[hdl] | ||||
|     let renamed_mops = wire(Array[HdlOption[config.unit_mop_in_unit()]][config.fetch_width.get()]); | ||||
|     let renamed_mops = | ||||
|         wire(Array[HdlOption[UnitInput[config.unit_mop_in_unit()]]][config.fetch_width.get()]); | ||||
|     #[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() { | ||||
|  | @ -196,19 +201,25 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|                 let dest_reg = MOpTrait::dest_reg(decoded_insn.mop); | ||||
|                 connect( | ||||
|                     renamed_mops[fetch_index], | ||||
|                     HdlSome(MOpTrait::map_regs( | ||||
|                         decoded_insn.mop, | ||||
|                         renamed_mop_out_reg.unit_out_reg, | ||||
|                         config.p_reg_num_width(), | ||||
|                         &mut |src_reg, src_index| { | ||||
|                             connect( | ||||
|                                 rename_table_read_ports[src_index].addr, | ||||
|                                 #[hdl] | ||||
|                                 MOpRegNum { value: src_reg }, | ||||
|                             ); | ||||
|                             rename_table_read_ports[src_index].data.cast_to_bits() | ||||
|                     HdlSome( | ||||
|                         #[hdl] | ||||
|                         UnitInput::<_> { | ||||
|                             mop: MOpTrait::map_regs( | ||||
|                                 decoded_insn.mop, | ||||
|                                 renamed_mop_out_reg.unit_out_reg, | ||||
|                                 config.p_reg_num_width(), | ||||
|                                 &mut |src_reg, src_index| { | ||||
|                                     connect( | ||||
|                                         rename_table_read_ports[src_index].addr, | ||||
|                                         #[hdl] | ||||
|                                         MOpRegNum { value: src_reg }, | ||||
|                                     ); | ||||
|                                     rename_table_read_ports[src_index].data.cast_to_bits() | ||||
|                                 }, | ||||
|                             ), | ||||
|                             pc: decoded_insn.pc, | ||||
|                         }, | ||||
|                     )), | ||||
|                     ), | ||||
|                 ); | ||||
|                 for (reg, reg_kind) in MOpDestReg::regs(dest_reg) | ||||
|                     .into_iter() | ||||
|  | @ -303,6 +314,8 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|             config.fetch_width.get(), | ||||
|         ), | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let unit_forwarding_info = wire(config.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( | ||||
|  | @ -311,6 +324,7 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|             SourceLocation::caller(), | ||||
|         ); | ||||
|         connect(dyn_unit.cd(unit), cd); | ||||
|         connect(dyn_unit.global_state(unit), global_state); | ||||
|         let unit_to_reg_alloc = dyn_unit.unit_to_reg_alloc(unit); | ||||
|         // TODO: handle assigning multiple instructions to a unit at a time
 | ||||
|         let assign_to_unit_at_once = NonZeroUsize::new(1).unwrap(); | ||||
|  | @ -333,8 +347,8 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|         ); | ||||
|         connect(unit_free_regs_tracker.alloc_out[0].ready, false); | ||||
|         connect( | ||||
|             unit_to_reg_alloc.input_insn.data, | ||||
|             Expr::ty(unit_to_reg_alloc.input_insn).data.HdlNone(), | ||||
|             unit_to_reg_alloc.input.data, | ||||
|             Expr::ty(unit_to_reg_alloc.input).data.HdlNone(), | ||||
|         ); | ||||
|         for fetch_index in 0..config.fetch_width.get() { | ||||
|             #[hdl] | ||||
|  | @ -343,7 +357,7 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|                 connect(available_units[fetch_index][unit_index], false); | ||||
|             } | ||||
|             #[hdl] | ||||
|             if !unit_to_reg_alloc.input_insn.ready { | ||||
|             if !unit_to_reg_alloc.input.ready { | ||||
|                 // must come after to override connects in loops above
 | ||||
|                 connect(available_units[fetch_index][unit_index], false); | ||||
|             } | ||||
|  | @ -354,13 +368,21 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|                     connect(unit_free_regs_tracker.alloc_out[0].ready, true); | ||||
|                     #[hdl] | ||||
|                     if let HdlSome(renamed_mop) = | ||||
|                         HdlOption::and_then(renamed_mops[fetch_index], |v| dyn_unit.extract_mop(v)) | ||||
|                         HdlOption::and_then(renamed_mops[fetch_index], |v| { | ||||
|                             #[hdl] | ||||
|                             let UnitInput::<_> { mop, pc } = v; | ||||
|                             let mop = dyn_unit.extract_mop(mop); | ||||
|                             HdlOption::map(mop, |mop| { | ||||
|                                 #[hdl] | ||||
|                                 UnitInput::<_> { mop, pc } | ||||
|                             }) | ||||
|                         }) | ||||
|                     { | ||||
|                         connect(unit_to_reg_alloc.input_insn.data, HdlSome(renamed_mop)); | ||||
|                         connect(unit_to_reg_alloc.input.data, HdlSome(renamed_mop)); | ||||
|                     } else { | ||||
|                         connect( | ||||
|                             unit_to_reg_alloc.input_insn.data, | ||||
|                             HdlSome(Expr::ty(unit_to_reg_alloc.input_insn).data.HdlSome.uninit()), | ||||
|                             unit_to_reg_alloc.input.data, | ||||
|                             HdlSome(Expr::ty(unit_to_reg_alloc.input).data.HdlSome.uninit()), | ||||
|                         ); | ||||
|                         // FIXME: add hdl_assert(cd.clk, false.to_expr(), "");
 | ||||
|                     } | ||||
|  | @ -385,18 +407,37 @@ pub fn reg_alloc(config: &CpuConfig) { | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // TODO: connect outputs to other units
 | ||||
|         connect(unit_to_reg_alloc.unit_forwarding_info, unit_forwarding_info); | ||||
|         connect( | ||||
|             unit_to_reg_alloc.unit_forwarding_info, | ||||
|             #[hdl] | ||||
|             UnitForwardingInfo::<_, _, _> { | ||||
|                 unit_output_writes: repeat( | ||||
|                     HdlOption[config.unit_output_write()].HdlNone(), | ||||
|                     config.units.len(), | ||||
|                 ), | ||||
|                 _phantom: PhantomData, | ||||
|             }, | ||||
|             unit_forwarding_info.unit_output_writes[unit_index], | ||||
|             Expr::ty(unit_forwarding_info) | ||||
|                 .unit_output_writes | ||||
|                 .element() | ||||
|                 .HdlNone(), | ||||
|         ); | ||||
|         #[hdl] | ||||
|         if let HdlSome(output) = unit_to_reg_alloc.output { | ||||
|             #[hdl] | ||||
|             let UnitOutput::<_, _> { which, result } = output; | ||||
|             #[hdl] | ||||
|             match result { | ||||
|                 UnitResult::<_>::Completed(completed) => { | ||||
|                     #[hdl] | ||||
|                     let UnitResultCompleted::<_> { value, extra_out } = completed; | ||||
|                     connect( | ||||
|                         unit_forwarding_info.unit_output_writes[unit_index], | ||||
|                         HdlSome( | ||||
|                             #[hdl] | ||||
|                             UnitOutputWrite::<_> { which, value }, | ||||
|                         ), | ||||
|                     ); | ||||
|                     // TODO: handle extra_out
 | ||||
|                 } | ||||
|                 UnitResult::<_>::Trap(trap_data) => { | ||||
|                     // TODO: handle traps
 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // TODO: handle cancellation
 | ||||
|         connect( | ||||
|             unit_to_reg_alloc.cancel_input, | ||||
|  |  | |||
|  | @ -39,20 +39,18 @@ impl PRegFlagsPowerISA { | |||
|     } | ||||
|     #[hdl] | ||||
|     pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) { | ||||
|         // list all flags explicitly so we don't miss handling any new flags
 | ||||
|         #[hdl] | ||||
|         match flags { | ||||
|             // list all flags explicitly so we don't miss handling any new flags
 | ||||
|             PRegFlags { | ||||
|                 pwr_ca_x86_cf: _, | ||||
|                 pwr_ca32_x86_af: _, | ||||
|                 pwr_ov_x86_of: _, | ||||
|                 pwr_ov32_x86_df: _, | ||||
|                 pwr_cr_lt_x86_sf: _, | ||||
|                 pwr_cr_gt_x86_pf: _, | ||||
|                 pwr_cr_eq_x86_zf: _, | ||||
|                 pwr_so: _, | ||||
|             } => {} | ||||
|         } | ||||
|         let PRegFlags { | ||||
|             pwr_ca_x86_cf: _, | ||||
|             pwr_ca32_x86_af: _, | ||||
|             pwr_ov_x86_of: _, | ||||
|             pwr_ov32_x86_df: _, | ||||
|             pwr_cr_lt_x86_sf: _, | ||||
|             pwr_cr_gt_x86_pf: _, | ||||
|             pwr_cr_eq_x86_zf: _, | ||||
|             pwr_so: _, | ||||
|         } = flags; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -83,20 +81,19 @@ impl PRegFlagsX86 { | |||
|     } | ||||
|     #[hdl] | ||||
|     pub fn clear_unused(flags: impl ToExpr<Type = PRegFlags>) { | ||||
|         // list all flags explicitly so we don't miss handling any new flags
 | ||||
|         #[hdl] | ||||
|         match flags { | ||||
|             // list all flags explicitly so we don't miss handling any new flags
 | ||||
|             PRegFlags { | ||||
|                 pwr_ca_x86_cf: _, | ||||
|                 pwr_ca32_x86_af: _, | ||||
|                 pwr_ov_x86_of: _, | ||||
|                 pwr_ov32_x86_df: _, | ||||
|                 pwr_cr_lt_x86_sf: _, | ||||
|                 pwr_cr_gt_x86_pf: _, | ||||
|                 pwr_cr_eq_x86_zf: _, | ||||
|                 pwr_so: unused1, | ||||
|             } => connect(unused1, false), | ||||
|         } | ||||
|         let PRegFlags { | ||||
|             pwr_ca_x86_cf: _, | ||||
|             pwr_ca32_x86_af: _, | ||||
|             pwr_ov_x86_of: _, | ||||
|             pwr_ov32_x86_df: _, | ||||
|             pwr_cr_lt_x86_sf: _, | ||||
|             pwr_cr_gt_x86_pf: _, | ||||
|             pwr_cr_eq_x86_zf: _, | ||||
|             pwr_so: unused1, | ||||
|         } = flags; | ||||
|         connect(unused1, false); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ use crate::{ | |||
|     instruction::{ | ||||
|         mop_enum, AluBranchMOp, L2RegisterFileMOp, LoadStoreMOp, MOpTrait, UnitOutRegNum, | ||||
|     }, | ||||
|     register::PRegValue, | ||||
|     register::{FlagsMode, PRegValue}, | ||||
|     unit::unit_base::UnitToRegAlloc, | ||||
| }; | ||||
| use fayalite::{ | ||||
|  | @ -142,6 +142,11 @@ all_units! { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct GlobalState { | ||||
|     pub flags_mode: FlagsMode, | ||||
| } | ||||
| 
 | ||||
| #[hdl(cmp_eq)] | ||||
| pub struct UnitResultCompleted<ExtraOut> { | ||||
|     pub value: PRegValue, | ||||
|  | @ -215,6 +220,8 @@ pub trait UnitTrait: | |||
| 
 | ||||
|     fn cd(&self, this: Expr<Self::Type>) -> Expr<ClockDomain>; | ||||
| 
 | ||||
|     fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState>; | ||||
| 
 | ||||
|     fn to_dyn(&self) -> DynUnit; | ||||
| } | ||||
| 
 | ||||
|  | @ -279,6 +286,10 @@ impl UnitTrait for DynUnit { | |||
|         self.unit.cd(this) | ||||
|     } | ||||
| 
 | ||||
|     fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> { | ||||
|         self.unit.global_state(this) | ||||
|     } | ||||
| 
 | ||||
|     fn to_dyn(&self) -> DynUnit { | ||||
|         *self | ||||
|     } | ||||
|  | @ -332,6 +343,10 @@ impl<T: UnitTrait + Clone + std::hash::Hash + Eq> UnitTrait for DynUnitWrapper<T | |||
|         self.0.cd(Expr::from_bundle(this)) | ||||
|     } | ||||
| 
 | ||||
|     fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> { | ||||
|         self.0.global_state(Expr::from_bundle(this)) | ||||
|     } | ||||
| 
 | ||||
|     fn to_dyn(&self) -> DynUnit { | ||||
|         let unit = self.intern(); | ||||
|         DynUnit { | ||||
|  |  | |||
|  | @ -3,16 +3,246 @@ | |||
| 
 | ||||
| use crate::{ | ||||
|     config::CpuConfig, | ||||
|     instruction::{AluBranchMOp, UnitOutRegNum}, | ||||
|     instruction::{ | ||||
|         AddSubMOp, AluBranchMOp, AluCommonMOp, CommonMOp, LogicalMOp, MOpTrait, OutputIntegerMode, | ||||
|         UnitOutRegNum, COMMON_MOP_SRC_LEN, | ||||
|     }, | ||||
|     register::{FlagsMode, PRegFlagsPowerISA, PRegFlagsX86, PRegValue}, | ||||
|     unit::{ | ||||
|         unit_base::{unit_base, UnitToRegAlloc}, | ||||
|         DynUnit, DynUnitWrapper, UnitKind, UnitMOp, UnitTrait, | ||||
|         unit_base::{unit_base, ExecuteEnd, ExecuteStart, UnitToRegAlloc}, | ||||
|         DynUnit, DynUnitWrapper, GlobalState, UnitKind, UnitMOp, UnitOutput, UnitResult, | ||||
|         UnitResultCompleted, UnitTrait, | ||||
|     }, | ||||
| }; | ||||
| use fayalite::{ | ||||
|     intern::{Intern, Interned}, | ||||
|     module::wire_with_loc, | ||||
|     prelude::*, | ||||
|     util::ready_valid::ReadyValid, | ||||
| }; | ||||
| use std::{collections::HashMap, ops::RangeTo}; | ||||
| 
 | ||||
| #[hdl] | ||||
| fn add_sub<SrcCount: KnownSize>( | ||||
|     mop: Expr<AddSubMOp<UnitOutRegNum<DynSize>, DynSize, SrcCount>>, | ||||
|     pc: Expr<UInt<64>>, | ||||
|     flags_mode: Expr<FlagsMode>, | ||||
|     src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>, | ||||
| ) -> Expr<UnitResultCompleted<()>> { | ||||
|     #[hdl] | ||||
|     let AddSubMOp::<_, _, _> { | ||||
|         alu_common, | ||||
|         invert_src0, | ||||
|         src1_is_carry_in, | ||||
|         invert_carry_in, | ||||
|         add_pc, | ||||
|     } = mop; | ||||
|     #[hdl] | ||||
|     let AluCommonMOp::<_, _, _> { | ||||
|         common, | ||||
|         output_integer_mode, | ||||
|     } = alu_common; | ||||
|     let imm: Expr<UInt<64>> = CommonMOp::imm(common).cast_to_static(); | ||||
|     #[hdl] | ||||
|     let carry_in_before_inversion = wire(); | ||||
|     connect(carry_in_before_inversion, false); | ||||
|     #[hdl] | ||||
|     let src1 = wire(); | ||||
|     connect(src1, 0u64); | ||||
|     #[hdl] | ||||
|     if src1_is_carry_in { | ||||
|         #[hdl] | ||||
|         match flags_mode { | ||||
|             FlagsMode::PowerISA(_) => { | ||||
|                 connect( | ||||
|                     carry_in_before_inversion, | ||||
|                     PRegFlagsPowerISA::xer_ca(src_values[1].flags), | ||||
|                 ); | ||||
|             } | ||||
|             FlagsMode::X86(_) => { | ||||
|                 connect( | ||||
|                     carry_in_before_inversion, | ||||
|                     PRegFlagsX86::cf(src_values[1].flags), | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         connect(src1, src_values[1].int_fp); | ||||
|     } | ||||
|     #[hdl] | ||||
|     let carry_in = wire(); | ||||
|     connect(carry_in, carry_in_before_inversion ^ invert_carry_in); | ||||
|     #[hdl] | ||||
|     let src0 = wire(); | ||||
|     connect(src0, src_values[0].int_fp); | ||||
|     #[hdl] | ||||
|     if invert_src0 { | ||||
|         connect(src0, !src_values[0].int_fp); | ||||
|     } | ||||
|     #[hdl] | ||||
|     let pc_or_zero = wire(); | ||||
|     connect(pc_or_zero, 0u64); | ||||
|     #[hdl] | ||||
|     if add_pc { | ||||
|         connect(pc_or_zero, pc); | ||||
|     } | ||||
|     let sum_of_sliced = |slice: RangeTo<usize>| { | ||||
|         src0[slice] + src1[slice] + src_values[2].int_fp[slice] + pc_or_zero[slice] + imm[slice] | ||||
|     }; | ||||
|     #[hdl] | ||||
|     let sum: UInt<64> = wire(); | ||||
|     connect(sum, sum_of_sliced(..64).cast_to_static()); | ||||
|     let carries = | ||||
|         HashMap::<usize, _>::from_iter([4, 7, 8, 15, 16, 31, 32, 63, 64].into_iter().map( | ||||
|             |bit_index| { | ||||
|                 let carry_at = wire_with_loc( | ||||
|                     &format!("carry_at_{bit_index}"), | ||||
|                     SourceLocation::caller(), | ||||
|                     Bool, | ||||
|                 ); | ||||
|                 connect(carry_at, sum_of_sliced(..bit_index)[bit_index]); | ||||
|                 (bit_index, carry_at) | ||||
|             }, | ||||
|         )); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let int_fp: UInt<64> = wire(); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let x86_cf = wire(); | ||||
|     #[hdl] | ||||
|     let x86_af = wire(); | ||||
|     connect(x86_af, carries[&4]); | ||||
|     #[hdl] | ||||
|     let x86_of = wire(); | ||||
|     #[hdl] | ||||
|     let x86_sf = wire(); | ||||
|     #[hdl] | ||||
|     let x86_pf = wire(); | ||||
|     connect(x86_pf, sum[..8].parity_even()); | ||||
|     #[hdl] | ||||
|     let x86_zf = wire(); | ||||
|     let set_x86_flags = |width| { | ||||
|         connect(x86_cf, carries[&width]); | ||||
|         connect(x86_of, carries[&width].cmp_ne(carries[&(width - 1)])); | ||||
|         connect(x86_sf, sum[width - 1]); | ||||
|         connect(x86_zf, sum[..width].cmp_eq(0u8)); | ||||
|     }; | ||||
|     #[hdl] | ||||
|     let pwr_ca = wire(); | ||||
|     connect(pwr_ca, carries[&64]); | ||||
|     #[hdl] | ||||
|     let pwr_ca32 = wire(); | ||||
|     connect(pwr_ca32, carries[&32]); | ||||
|     #[hdl] | ||||
|     let pwr_ov = wire(); | ||||
|     connect(pwr_ov, carries[&64] ^ carries[&63]); | ||||
|     #[hdl] | ||||
|     let pwr_ov32 = wire(); | ||||
|     connect(pwr_ov32, carries[&32] ^ carries[&31]); | ||||
|     #[hdl] | ||||
|     let pwr_cr_lt = wire(); | ||||
|     connect(pwr_cr_lt, int_fp[63]); | ||||
|     #[hdl] | ||||
|     let pwr_cr_eq = wire(); | ||||
|     connect(pwr_cr_eq, int_fp.cmp_eq(0u64)); | ||||
|     #[hdl] | ||||
|     let pwr_cr_gt = wire(); | ||||
|     connect(pwr_cr_gt, !pwr_cr_lt & !pwr_cr_eq); | ||||
|     #[hdl] | ||||
|     let pwr_so = wire(); | ||||
|     // TODO: SO needs to OR-in the previous value of SO
 | ||||
|     connect(pwr_so, pwr_ov); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     match output_integer_mode { | ||||
|         OutputIntegerMode::Full64 => { | ||||
|             set_x86_flags(64); | ||||
|             connect(int_fp, sum); | ||||
|         } | ||||
|         OutputIntegerMode::DupLow32 => { | ||||
|             set_x86_flags(32); | ||||
|             connect( | ||||
|                 int_fp, | ||||
|                 [sum.cast_to_static::<UInt<32>>(); 2] | ||||
|                     .cast_to_bits() | ||||
|                     .cast_to_static(), | ||||
|             ); | ||||
|         } | ||||
|         OutputIntegerMode::ZeroExt32 => { | ||||
|             set_x86_flags(32); | ||||
|             connect(int_fp, sum.cast_to_static::<UInt<32>>().cast_to_static()); | ||||
|         } | ||||
|         OutputIntegerMode::SignExt32 => { | ||||
|             set_x86_flags(32); | ||||
|             connect(int_fp, sum.cast_to_static::<SInt<32>>().cast_to_static()); | ||||
|         } | ||||
|         OutputIntegerMode::ZeroExt16 => { | ||||
|             set_x86_flags(16); | ||||
|             connect(int_fp, sum.cast_to_static::<UInt<16>>().cast_to_static()); | ||||
|         } | ||||
|         OutputIntegerMode::SignExt16 => { | ||||
|             set_x86_flags(16); | ||||
|             connect(int_fp, sum.cast_to_static::<SInt<16>>().cast_to_static()); | ||||
|         } | ||||
|         OutputIntegerMode::ZeroExt8 => { | ||||
|             set_x86_flags(8); | ||||
|             connect(int_fp, sum.cast_to_static::<UInt<8>>().cast_to_static()); | ||||
|         } | ||||
|         OutputIntegerMode::SignExt8 => { | ||||
|             set_x86_flags(8); | ||||
|             connect(int_fp, sum.cast_to_static::<SInt<8>>().cast_to_static()); | ||||
|         } | ||||
|     } | ||||
|     #[hdl] | ||||
|     let flags = wire(); | ||||
|     #[hdl] | ||||
|     match flags_mode { | ||||
|         FlagsMode::PowerISA(_) => { | ||||
|             PRegFlagsPowerISA::clear_unused(flags); | ||||
|             connect(PRegFlagsPowerISA::xer_ca(flags), pwr_ca); | ||||
|             connect(PRegFlagsPowerISA::xer_ca32(flags), pwr_ca32); | ||||
|             connect(PRegFlagsPowerISA::xer_ov(flags), pwr_ov); | ||||
|             connect(PRegFlagsPowerISA::xer_ov32(flags), pwr_ov32); | ||||
|             connect(PRegFlagsPowerISA::cr_lt(flags), pwr_cr_lt); | ||||
|             connect(PRegFlagsPowerISA::cr_gt(flags), pwr_cr_gt); | ||||
|             connect(PRegFlagsPowerISA::cr_eq(flags), pwr_cr_eq); | ||||
|             connect(PRegFlagsPowerISA::so(flags), pwr_so); | ||||
|         } | ||||
|         FlagsMode::X86(_) => { | ||||
|             PRegFlagsX86::clear_unused(flags); | ||||
|             connect(PRegFlagsX86::cf(flags), x86_cf); | ||||
|             connect(PRegFlagsX86::af(flags), x86_af); | ||||
|             connect(PRegFlagsX86::of(flags), x86_of); | ||||
|             connect(PRegFlagsX86::sf(flags), x86_sf); | ||||
|             connect(PRegFlagsX86::pf(flags), x86_pf); | ||||
|             connect(PRegFlagsX86::zf(flags), x86_zf); | ||||
| 
 | ||||
|             // this insn doesn't write DF, so it's output isn't used for reading DF
 | ||||
|             connect(PRegFlagsX86::df(flags), false); | ||||
|         } | ||||
|     } | ||||
|     #[hdl] | ||||
|     UnitResultCompleted::<_> { | ||||
|         value: #[hdl] | ||||
|         PRegValue { int_fp, flags }, | ||||
|         extra_out: (), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| fn logical( | ||||
|     mop: Expr<LogicalMOp<UnitOutRegNum<DynSize>, DynSize>>, | ||||
|     flags_mode: Expr<FlagsMode>, | ||||
|     src_values: Expr<Array<PRegValue, { COMMON_MOP_SRC_LEN }>>, | ||||
| ) -> Expr<UnitResultCompleted<()>> { | ||||
|     // TODO: finish
 | ||||
|     #[hdl] | ||||
|     UnitResultCompleted::<_> { | ||||
|         value: PRegValue::zeroed(), | ||||
|         extra_out: (), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[hdl_module] | ||||
| pub fn alu_branch(config: &CpuConfig, unit_index: usize) { | ||||
|  | @ -29,20 +259,88 @@ pub fn alu_branch(config: &CpuConfig, unit_index: usize) { | |||
|         AluBranchMOp[config.unit_out_reg_num()][config.p_reg_num_width()], | ||||
|         (), | ||||
|     )); | ||||
|     #[hdl] | ||||
|     let global_state: GlobalState = m.input(); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let unit_base = instance(unit_base( | ||||
|         config, | ||||
|         unit_index, | ||||
|         Expr::ty(unit_to_reg_alloc).input_insn.data.HdlSome, | ||||
|         Expr::ty(unit_to_reg_alloc).input.data.HdlSome.mop, | ||||
|         (), | ||||
|     )); | ||||
|     connect(unit_to_reg_alloc, unit_base.unit_to_reg_alloc); | ||||
|     connect(unit_base.cd, cd); | ||||
|     connect(unit_base.execute_start.ready, true); // TODO: finish
 | ||||
|     connect(unit_base.execute_start.ready, true); | ||||
|     connect( | ||||
|         unit_base.execute_end, | ||||
|         Expr::ty(unit_base.execute_end).HdlNone(), | ||||
|     ); // TODO: finish
 | ||||
|     ); | ||||
|     #[hdl] | ||||
|     if let HdlSome(execute_start) = ReadyValid::firing_data(unit_base.execute_start) { | ||||
|         #[hdl] | ||||
|         let ExecuteStart::<_> { | ||||
|             mop, | ||||
|             pc, | ||||
|             src_values, | ||||
|         } = execute_start; | ||||
|         #[hdl] | ||||
|         match mop { | ||||
|             AluBranchMOp::<_, _>::AddSub(mop) => connect( | ||||
|                 unit_base.execute_end, | ||||
|                 HdlSome( | ||||
|                     #[hdl] | ||||
|                     ExecuteEnd::<_, _> { | ||||
|                         unit_output: #[hdl] | ||||
|                         UnitOutput::<_, _> { | ||||
|                             which: MOpTrait::dest_reg(mop), | ||||
|                             result: UnitResult[()].Completed(add_sub( | ||||
|                                 mop, | ||||
|                                 pc, | ||||
|                                 global_state.flags_mode, | ||||
|                                 src_values, | ||||
|                             )), | ||||
|                         }, | ||||
|                     }, | ||||
|                 ), | ||||
|             ), | ||||
|             AluBranchMOp::<_, _>::AddSubI(mop) => connect( | ||||
|                 unit_base.execute_end, | ||||
|                 HdlSome( | ||||
|                     #[hdl] | ||||
|                     ExecuteEnd::<_, _> { | ||||
|                         unit_output: #[hdl] | ||||
|                         UnitOutput::<_, _> { | ||||
|                             which: MOpTrait::dest_reg(mop), | ||||
|                             result: UnitResult[()].Completed(add_sub( | ||||
|                                 mop, | ||||
|                                 pc, | ||||
|                                 global_state.flags_mode, | ||||
|                                 src_values, | ||||
|                             )), | ||||
|                         }, | ||||
|                     }, | ||||
|                 ), | ||||
|             ), | ||||
|             AluBranchMOp::<_, _>::Logical(mop) => connect( | ||||
|                 unit_base.execute_end, | ||||
|                 HdlSome( | ||||
|                     #[hdl] | ||||
|                     ExecuteEnd::<_, _> { | ||||
|                         unit_output: #[hdl] | ||||
|                         UnitOutput::<_, _> { | ||||
|                             which: MOpTrait::dest_reg(mop), | ||||
|                             result: UnitResult[()].Completed(logical( | ||||
|                                 mop, | ||||
|                                 global_state.flags_mode, | ||||
|                                 src_values, | ||||
|                             )), | ||||
|                         }, | ||||
|                     }, | ||||
|                 ), | ||||
|             ), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||||
|  | @ -103,6 +401,10 @@ impl UnitTrait for AluBranch { | |||
|         this.cd | ||||
|     } | ||||
| 
 | ||||
|     fn global_state(&self, this: Expr<Self::Type>) -> Expr<GlobalState> { | ||||
|         this.global_state | ||||
|     } | ||||
| 
 | ||||
|     fn to_dyn(&self) -> DynUnit { | ||||
|         DynUnitWrapper(*self).to_dyn() | ||||
|     } | ||||
|  |  | |||
|  | @ -3,12 +3,18 @@ | |||
| 
 | ||||
| use crate::{ | ||||
|     config::CpuConfig, | ||||
|     instruction::{MOpTrait, PRegNum, UnitOutRegNum, COMMON_MOP_SRC_LEN}, | ||||
|     instruction::{MOpTrait, PRegNum, UnitNum, UnitOutRegNum, COMMON_MOP_SRC_LEN}, | ||||
|     register::PRegValue, | ||||
|     unit::{UnitCancelInput, UnitOutput, UnitOutputWrite}, | ||||
|     util::tree_reduce::tree_reduce, | ||||
| }; | ||||
| use fayalite::{module::wire_with_loc, prelude::*, ty::StaticType, util::ready_valid::ReadyValid}; | ||||
| use fayalite::{ | ||||
|     memory::splat_mask, | ||||
|     module::{memory_with_loc, wire_with_loc}, | ||||
|     prelude::*, | ||||
|     ty::StaticType, | ||||
|     util::ready_valid::ReadyValid, | ||||
| }; | ||||
| use std::marker::PhantomData; | ||||
| 
 | ||||
| #[hdl] | ||||
|  | @ -17,6 +23,12 @@ pub struct UnitForwardingInfo<UnitNumWidth: Size, OutRegNumWidth: Size, UnitCoun | |||
|     pub _phantom: PhantomData<UnitNumWidth>, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct UnitInput<MOp: Type> { | ||||
|     pub mop: MOp, | ||||
|     pub pc: UInt<64>, | ||||
| } | ||||
| 
 | ||||
| #[hdl] | ||||
| pub struct UnitToRegAlloc< | ||||
|     MOp: Type, | ||||
|  | @ -28,7 +40,7 @@ pub struct UnitToRegAlloc< | |||
|     #[hdl(flip)] | ||||
|     pub unit_forwarding_info: UnitForwardingInfo<UnitNumWidth, OutRegNumWidth, UnitCount>, | ||||
|     #[hdl(flip)] | ||||
|     pub input_insn: ReadyValid<MOp>, | ||||
|     pub input: ReadyValid<UnitInput<MOp>>, | ||||
|     #[hdl(flip)] | ||||
|     pub cancel_input: HdlOption<UnitCancelInput<OutRegNumWidth>>, | ||||
|     pub output: HdlOption<UnitOutput<OutRegNumWidth, ExtraOut>>, | ||||
|  | @ -38,7 +50,7 @@ impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCo | |||
|     UnitToRegAlloc<MOp, ExtraOut, UnitNumWidth, OutRegNumWidth, UnitCount> | ||||
| { | ||||
|     pub fn mop_ty(self) -> MOp { | ||||
|         self.input_insn.data.HdlSome | ||||
|         self.input.data.HdlSome.mop | ||||
|     } | ||||
|     pub fn extra_out_ty(self) -> ExtraOut { | ||||
|         self.output.HdlSome.extra_out_ty() | ||||
|  | @ -48,6 +60,7 @@ impl<MOp: Type, ExtraOut: Type, UnitNumWidth: Size, OutRegNumWidth: Size, UnitCo | |||
| #[hdl] | ||||
| pub struct ExecuteStart<MOp: Type + MOpTrait<DestReg = UnitOutRegNum<DynSize>>> { | ||||
|     pub mop: MOp, | ||||
|     pub pc: UInt<64>, | ||||
|     pub src_values: Array<PRegValue, { COMMON_MOP_SRC_LEN }>, | ||||
| } | ||||
| 
 | ||||
|  | @ -137,6 +150,7 @@ impl InFlightOpState { | |||
| struct InFlightOp<MOp: Type> { | ||||
|     state: InFlightOpState, | ||||
|     mop: MOp, | ||||
|     pc: UInt<64>, | ||||
|     src_ready_flags: Array<Bool, { COMMON_MOP_SRC_LEN }>, | ||||
| } | ||||
| 
 | ||||
|  | @ -171,6 +185,7 @@ impl<OpIndexWidth: Size> InFlightOpsSummary<OpIndexWidth> { | |||
|             let InFlightOp::<_> { | ||||
|                 state, | ||||
|                 mop: _, | ||||
|                 pc: _, | ||||
|                 src_ready_flags, | ||||
|             } = in_flight_op; | ||||
|             connect(ready_op_index, HdlOption[op_index_ty].HdlNone()); | ||||
|  | @ -258,21 +273,85 @@ pub fn unit_base< | |||
|     connect(in_flight_ops_summary, in_flight_ops_summary_value); | ||||
| 
 | ||||
|     connect( | ||||
|         unit_to_reg_alloc.input_insn.ready, | ||||
|         unit_to_reg_alloc.input.ready, | ||||
|         HdlOption::is_some(in_flight_ops_summary.empty_op_index), | ||||
|     ); | ||||
|     // TODO: connect(execute_start.data, <read_regs>(in_flight_ops_summary.ready_op_index));
 | ||||
| 
 | ||||
|     let unit_output_writes = unit_to_reg_alloc.unit_forwarding_info.unit_output_writes; | ||||
|     #[hdl] | ||||
|     let read_src_regs = wire(mop_ty.src_regs_ty()); | ||||
|     connect( | ||||
|         read_src_regs, | ||||
|         repeat(config.p_reg_num().const_zero().cast_to_bits(), ConstUsize), | ||||
|     ); | ||||
|     #[hdl] | ||||
|     let read_src_values = wire(); | ||||
|     connect(read_src_values, [PRegValue::zeroed(); COMMON_MOP_SRC_LEN]); | ||||
|     for unit_index in 0..Expr::ty(unit_output_writes).len() { | ||||
|         let mut unit_output_regs = memory_with_loc( | ||||
|             &format!("unit_{unit_index}_output_regs"), | ||||
|             PRegValue, | ||||
|             SourceLocation::caller(), | ||||
|         ); | ||||
|         unit_output_regs.depth(1 << config.out_reg_num_width); | ||||
| 
 | ||||
|         for src_index in 0..COMMON_MOP_SRC_LEN { | ||||
|             let read_port = unit_output_regs.new_read_port(); | ||||
|             let p_reg_num = read_src_regs[src_index].cast_bits_to(config.p_reg_num()); | ||||
|             connect_any(read_port.addr, p_reg_num.unit_out_reg.value); | ||||
|             connect(read_port.en, false); | ||||
|             connect(read_port.clk, cd.clk); | ||||
|             #[hdl] | ||||
|             if UnitNum::is_index(p_reg_num.unit_num, unit_index) { | ||||
|                 connect(read_port.en, true); | ||||
|                 connect(read_src_values[src_index], read_port.data); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let write_port = unit_output_regs.new_write_port(); | ||||
|         connect_any(write_port.addr, 0u8); | ||||
|         connect(write_port.en, false); | ||||
|         connect(write_port.clk, cd.clk); | ||||
|         connect(write_port.data, PRegValue::zeroed()); | ||||
|         connect(write_port.mask, splat_mask(PRegValue, true.to_expr())); | ||||
|         #[hdl] | ||||
|         if let HdlSome(unit_output_write) = unit_output_writes[unit_index] { | ||||
|             connect_any(write_port.addr, unit_output_write.which.value); | ||||
|             connect(write_port.data, unit_output_write.value); | ||||
|             connect(write_port.en, true); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[hdl] | ||||
|     if let HdlSome(ready_op_index) = in_flight_ops_summary.ready_op_index { | ||||
|         #[hdl] | ||||
|         if let HdlSome(in_flight_op) = in_flight_ops[ready_op_index] { | ||||
|             connect( | ||||
|                 execute_start.data, | ||||
|                 HdlSome( | ||||
|                     #[hdl] | ||||
|                     ExecuteStart::<_> { | ||||
|                         mop: in_flight_op.mop, | ||||
|                         pc: in_flight_op.pc, | ||||
|                         src_values: read_src_values, | ||||
|                     }, | ||||
|                 ), | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     connect( | ||||
|         unit_to_reg_alloc.output, | ||||
|         Expr::ty(unit_to_reg_alloc.output).HdlNone(), | ||||
|     ); // TODO: finish
 | ||||
|     ); | ||||
| 
 | ||||
|     #[hdl] | ||||
|     let input_in_flight_op = wire(HdlOption[in_flight_op_ty]); | ||||
|     connect(input_in_flight_op, HdlOption[in_flight_op_ty].HdlNone()); | ||||
|     #[hdl] | ||||
|     if let HdlSome(mop) = ReadyValid::firing_data(unit_to_reg_alloc.input_insn) { | ||||
|     if let HdlSome(input) = ReadyValid::firing_data(unit_to_reg_alloc.input) { | ||||
|         #[hdl] | ||||
|         let UnitInput::<_> { mop, pc } = input; | ||||
|         #[hdl] | ||||
|         let input_mop_src_regs = wire(mop_ty.src_regs_ty()); | ||||
|         connect( | ||||
|  | @ -309,6 +388,7 @@ pub fn unit_base< | |||
|                     InFlightOp::<_> { | ||||
|                         state: InFlightOpState.Ready(), | ||||
|                         mop, | ||||
|                         pc, | ||||
|                         src_ready_flags, | ||||
|                     }, | ||||
|                 ), | ||||
|  | @ -345,6 +425,7 @@ pub fn unit_base< | |||
|             let InFlightOp::<_> { | ||||
|                 state, | ||||
|                 mop, | ||||
|                 pc, | ||||
|                 src_ready_flags, | ||||
|             } = in_flight_op; | ||||
|             let which = MOp::dest_reg(mop); | ||||
|  | @ -359,11 +440,17 @@ pub fn unit_base< | |||
|             ); | ||||
|             MOp::connect_src_regs(mop, src_regs); | ||||
| 
 | ||||
|             #[hdl] | ||||
|             if in_flight_ops_summary.ready_op_index.cmp_eq(HdlSome( | ||||
|                 in_flight_op_index.cast_to(Expr::ty(in_flight_ops_summary).ready_op_index.HdlSome), | ||||
|             )) { | ||||
|                 connect(read_src_regs, src_regs); | ||||
|             } | ||||
| 
 | ||||
|             connect( | ||||
|                 in_flight_op_next_src_ready_flags[in_flight_op_index], | ||||
|                 src_ready_flags, | ||||
|             ); | ||||
|             let unit_output_writes = unit_to_reg_alloc.unit_forwarding_info.unit_output_writes; | ||||
|             for unit_index in 0..Expr::ty(unit_output_writes).len() { | ||||
|                 #[hdl] | ||||
|                 if let HdlSome(unit_output_write) = unit_output_writes[unit_index] { | ||||
|  | @ -404,6 +491,13 @@ pub fn unit_base< | |||
|                 #[hdl] | ||||
|                 if which.cmp_eq(unit_output.which) { | ||||
|                     connect(in_flight_op_execute_ending[in_flight_op_index], true); | ||||
|                     #[hdl] | ||||
|                     if !in_flight_op_canceling[in_flight_op_index] { | ||||
|                         #[hdl] | ||||
|                         if let InFlightOpState::Running = state { | ||||
|                             connect(unit_to_reg_alloc.output, HdlSome(unit_output)); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             #[hdl] | ||||
|  | @ -439,7 +533,8 @@ pub fn unit_base< | |||
|                         InFlightOp::<_> { | ||||
|                             state, | ||||
|                             mop, | ||||
|                             src_ready_flags, | ||||
|                             pc, | ||||
|                             src_ready_flags: in_flight_op_next_src_ready_flags[in_flight_op_index], | ||||
|                         }, | ||||
|                     ), | ||||
|                 ); | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue