diff --git a/common.vhdl b/common.vhdl index 91f9ebd..01b9be5 100644 --- a/common.vhdl +++ b/common.vhdl @@ -12,7 +12,6 @@ package common is -- MSR bit numbers constant MSR_SF : integer := (63 - 0); -- Sixty-Four bit mode - constant MSR_HV : integer := (63 - 3); -- Hypervisor mode (always 1) constant MSR_EE : integer := (63 - 48); -- External interrupt Enable constant MSR_PR : integer := (63 - 49); -- PRoblem state constant MSR_FP : integer := (63 - 50); -- Floating Point available @@ -120,6 +119,11 @@ package common is constant SPR_SIER3 : spr_num_t := 753; constant SPR_MMCR3 : spr_num_t := 754; + -- New Sandbox SPR Identifiers + -- Dedicated telemetry/trace-array sandbox SPRs bridging execute1 and the MMU. + constant SPR_704_MMU_INPUT : integer := 704; + constant SPR_705_MMU_OUTPUT : integer := 705; + -- GPR indices in the register file (GPR only) subtype gpr_index_t is std_ulogic_vector(4 downto 0); @@ -180,39 +184,22 @@ package common is end record; constant ram_spr_info_init: ram_spr_info := (index => to_unsigned(0,3), others => '0'); - subtype spr_selector is std_ulogic_vector(3 downto 0); + subtype spr_selector is std_ulogic_vector(2 downto 0); type spr_id is record sel : spr_selector; valid : std_ulogic; ispmu : std_ulogic; - ronly : std_ulogic; - wonly : std_ulogic; - noop : std_ulogic; - end record; - constant spr_id_init : spr_id := (sel => "0000", others => '0'); - - constant SPRSEL_ZERO : spr_selector := 4x"0"; - constant SPRSEL_TB : spr_selector := 4x"1"; - constant SPRSEL_TBU : spr_selector := 4x"2"; - constant SPRSEL_DEC : spr_selector := 4x"3"; - constant SPRSEL_PVR : spr_selector := 4x"4"; - constant SPRSEL_LOGR : spr_selector := 4x"5"; - constant SPRSEL_CFAR : spr_selector := 4x"6"; - constant SPRSEL_FSCR : spr_selector := 4x"7"; - constant SPRSEL_LPCR : spr_selector := 4x"8"; - constant SPRSEL_HEIR : spr_selector := 4x"9"; - constant SPRSEL_CTRL : spr_selector := 4x"a"; - constant SPRSEL_DSCR : spr_selector := 4x"b"; - constant SPRSEL_PIR : spr_selector := 4x"c"; - constant SPRSEL_CIABR : spr_selector := 4x"d"; - constant SPRSEL_DEXCR : spr_selector := 4x"e"; - constant SPRSEL_XER : spr_selector := 4x"f"; - - -- FSCR bit numbers - constant FSCR_PREFIX : integer := 63 - 50; - constant FSCR_SCV : integer := 63 - 51; - constant FSCR_TAR : integer := 63 - 55; - constant FSCR_DSCR : integer := 63 - 61; + end record; + constant spr_id_init : spr_id := (sel => "000", others => '0'); + + constant SPRSEL_TB : spr_selector := 3x"0"; + constant SPRSEL_TBU : spr_selector := 3x"1"; + constant SPRSEL_DEC : spr_selector := 3x"2"; + constant SPRSEL_PVR : spr_selector := 3x"3"; + constant SPRSEL_LOGA : spr_selector := 3x"4"; + constant SPRSEL_LOGD : spr_selector := 3x"5"; + constant SPRSEL_CFAR : spr_selector := 3x"6"; + constant SPRSEL_XER : spr_selector := 3x"7"; -- FPSCR bit numbers constant FPSCR_FX : integer := 63 - 32; @@ -246,16 +233,6 @@ package common is constant FPSCR_NI : integer := 63 - 61; constant FPSCR_RN : integer := 63 - 63; - -- LPCR bit numbers - constant LPCR_HAIL : integer := 63 - 37; - constant LPCR_UPRT : integer := 63 - 41; - constant LPCR_EVIRT : integer := 63 - 42; - constant LPCR_HR : integer := 63 - 43; - constant LPCR_LD : integer := 63 - 46; - constant LPCR_HEIC : integer := 63 - 59; - constant LPCR_LPES : integer := 63 - 60; - constant LPCR_HVICE : integer := 63 - 62; - -- Real addresses -- REAL_ADDR_BITS is the number of real address bits that we store constant REAL_ADDR_BITS : positive := 56; @@ -282,68 +259,24 @@ package common is -- For now, fixed 16 sources, make this either a parametric -- package of some sort or an unconstrainted array. - -- We don't know NCPUS or SRC_NUM here, so make this - -- large enough for 4 cpus and 16 interrupt sources for now. type ics_to_icp_t is record -- Level interrupts only, ICS just keeps prsenting the -- highest priority interrupt. Once handling edge, something -- smarter involving handshake & reject support will be needed - src : std_ulogic_vector(15 downto 0); -- 4 bits each for 4 cpus - pri : std_ulogic_vector(31 downto 0); -- 8 bits each for 4 cpus + src : std_ulogic_vector(3 downto 0); + pri : std_ulogic_vector(7 downto 0); end record; - -- Bits in each half of DEXCR and HDEXCR - subtype aspect_bits_t is std_ulogic_vector(4 downto 0); - constant aspect_bits_init : aspect_bits_t := (others => '1'); - -- Bit numbers in aspect_bits_t - constant DEXCR_SBHE : integer := 4; -- speculative branch hint enable - constant DEXCR_IBRTPD : integer := 3; -- indirect branch recurrent target prediction disable - constant DEXCR_SRAPD : integer := 2; -- subroutine return address prediction disable - constant DEXCR_NPHIE : integer := 1; -- non-privileged hash instruction enable - constant DEXCR_PHIE : integer := 0; -- privileged hash instruction enable - -- This needs to die... type ctrl_t is record - wait_state: std_ulogic; - run: std_ulogic; + tb: std_ulogic_vector(63 downto 0); dec: std_ulogic_vector(63 downto 0); msr: std_ulogic_vector(63 downto 0); cfar: std_ulogic_vector(63 downto 0); xer_low: std_ulogic_vector(17 downto 0); - fscr_ic: std_ulogic_vector(3 downto 0); - fscr_pref: std_ulogic; - fscr_scv: std_ulogic; - fscr_tar: std_ulogic; - fscr_dscr: std_ulogic; - heir: std_ulogic_vector(63 downto 0); - dscr: std_ulogic_vector(24 downto 0); - ciabr: std_ulogic_vector(63 downto 0); - dexcr_pnh: aspect_bits_t; - dexcr_pro: aspect_bits_t; - hdexcr_hyp: aspect_bits_t; - hdexcr_enf: aspect_bits_t; - lpcr_hail: std_ulogic; - lpcr_evirt: std_ulogic; - lpcr_ld: std_ulogic; - lpcr_heic: std_ulogic; - lpcr_lpes: std_ulogic; - lpcr_hvice: std_ulogic; end record; constant ctrl_t_init : ctrl_t := - (wait_state => '0', run => '1', xer_low => 18x"0", - fscr_ic => x"0", fscr_pref => '1', fscr_scv => '1', fscr_tar => '1', fscr_dscr => '1', - dscr => (others => '0'), - dexcr_pnh => aspect_bits_init, dexcr_pro => aspect_bits_init, - hdexcr_hyp => aspect_bits_init, hdexcr_enf => aspect_bits_init, - lpcr_hail => '0', lpcr_evirt => '0', lpcr_ld => '1', lpcr_heic => '0', - lpcr_lpes => '0', lpcr_hvice => '0', - others => (others => '0')); - - type timebase_ctrl is record - reset : std_ulogic; - rd_prot : std_ulogic; -- read-protect => userspace can't read TB - freeze : std_ulogic; - end record; + (xer_low => 18x"0", others => (others => '0')); type Fetch1ToIcacheType is record req: std_ulogic; @@ -382,7 +315,6 @@ package common is type Decode1ToDecode2Type is record valid: std_ulogic; stop_mark : std_ulogic; - second : std_ulogic; nia: std_ulogic_vector(63 downto 0); prefixed: std_ulogic; prefix: std_ulogic_vector(25 downto 0); @@ -399,7 +331,7 @@ package common is reg_c : gspr_index_t; end record; constant Decode1ToDecode2Init : Decode1ToDecode2Type := - (valid => '0', stop_mark => '0', second => '0', nia => (others => '0'), + (valid => '0', stop_mark => '0', nia => (others => '0'), prefixed => '0', prefix => (others => '0'), insn => (others => '0'), illegal_suffix => '0', misaligned_prefix => '0', decode => decode_rom_init, br_pred => '0', big_endian => '0', @@ -422,11 +354,9 @@ package common is type bypass_data_t is record tag : instr_tag_t; - reg : gspr_index_t; data : std_ulogic_vector(63 downto 0); end record; - constant bypass_data_init : bypass_data_t := - (tag => instr_tag_init, reg => (others => '0'), data => (others => '0')); + constant bypass_data_init : bypass_data_t := (tag => instr_tag_init, data => (others => '0')); type cr_bypass_data_t is record tag : instr_tag_t; @@ -474,8 +404,8 @@ package common is update : std_ulogic; -- is this an update instruction? reserve : std_ulogic; -- set for larx/stcx br_pred : std_ulogic; - result_sel : result_sel_t; -- select source of result - sub_select : subresult_sel_t; -- sub-result selection + result_sel : std_ulogic_vector(2 downto 0); -- select source of result + sub_select : std_ulogic_vector(2 downto 0); -- sub-result selection repeat : std_ulogic; -- set if instruction is cracked into two ops second : std_ulogic; -- set if this is the second op spr_select : spr_id; @@ -486,22 +416,11 @@ package common is ramspr_wraddr : ramspr_index; ramspr_write_even : std_ulogic; ramspr_write_odd : std_ulogic; - ramspr_32bit : std_ulogic; dbg_spr_access : std_ulogic; dec_ctr : std_ulogic; - privileged : std_ulogic; prefixed : std_ulogic; - prefix : std_ulogic_vector(25 downto 0); illegal_suffix : std_ulogic; misaligned_prefix : std_ulogic; - illegal_form : std_ulogic; - uses_tar : std_ulogic; - uses_dscr : std_ulogic; - right_shift : std_ulogic; - rot_clear_left : std_ulogic; - rot_clear_right : std_ulogic; - rot_sign_ext : std_ulogic; - do_popcnt : std_ulogic; end record; constant Decode2ToExecute1Init : Decode2ToExecute1Type := (valid => '0', unit => ALU, fac => NONE, insn_type => OP_ILLEGAL, instr_tag => instr_tag_init, @@ -514,18 +433,14 @@ package common is read_data1 => (others => '0'), read_data2 => (others => '0'), read_data3 => (others => '0'), reg_valid1 => '0', reg_valid2 => '0', reg_valid3 => '0', cr => (others => '0'), insn => (others => '0'), data_len => (others => '0'), - result_sel => ADD, sub_select => "000", + result_sel => "000", sub_select => "000", repeat => '0', second => '0', spr_select => spr_id_init, spr_is_ram => '0', ramspr_even_rdaddr => (others => '0'), ramspr_odd_rdaddr => (others => '0'), ramspr_rd_odd => '0', ramspr_wraddr => (others => '0'), ramspr_write_even => '0', ramspr_write_odd => '0', - ramspr_32bit => '0', dbg_spr_access => '0', dec_ctr => '0', - privileged => '0', prefixed => '0', prefix => (others => '0'), illegal_suffix => '0', - misaligned_prefix => '0', illegal_form => '0', uses_tar => '0', uses_dscr => '0', - right_shift => '0', rot_clear_left => '0', rot_clear_right => '0', rot_sign_ext => '0', - do_popcnt => '0', + prefixed => '0', illegal_suffix => '0', misaligned_prefix => '0', others => (others => '0')); type MultiplyInputType is record @@ -598,7 +513,6 @@ package common is nia : std_ulogic_vector(63 downto 0); addr : std_ulogic_vector(63 downto 0); addr_v : std_ulogic; - trace : std_ulogic; occur : PMUEventType; end record; @@ -642,7 +556,6 @@ package common is byte_reverse : std_ulogic; sign_extend : std_ulogic; -- do we need to sign extend? update : std_ulogic; -- is this an update instruction? - hash : std_ulogic; xerc : xer_common_t; reserve : std_ulogic; -- set for larx/stcx. rc : std_ulogic; -- set for stcx. @@ -655,12 +568,10 @@ package common is second : std_ulogic; e2stall : std_ulogic; msr : std_ulogic_vector(63 downto 0); - hashkey : std_ulogic_vector(63 downto 0); - hash_enable : std_ulogic; end record; constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0', - sign_extend => '0', update => '0', hash => '0', xerc => xerc_init, + sign_extend => '0', update => '0', xerc => xerc_init, reserve => '0', rc => '0', virt_mode => '0', priv_mode => '0', insn => (others => '0'), instr_tag => instr_tag_init, @@ -669,13 +580,11 @@ package common is length => (others => '0'), mode_32bit => '0', is_32bit => '0', prefixed => '0', repeat => '0', second => '0', e2stall => '0', - msr => (others => '0'), hashkey => (others => '0'), hash_enable => '0'); + msr => (others => '0')); type Loadstore1ToExecute1Type is record busy : std_ulogic; l2stall : std_ulogic; - ea_for_pmu : std_ulogic_vector(63 downto 0); - ea_valid : std_ulogic; end record; type Loadstore1ToDcacheType is record @@ -683,25 +592,14 @@ package common is hold : std_ulogic; load : std_ulogic; -- is this a load dcbz : std_ulogic; - flush : std_ulogic; - touch : std_ulogic; - sync : std_ulogic; nc : std_ulogic; reserve : std_ulogic; - atomic_qw : std_ulogic; -- part of a quadword atomic op - atomic_first : std_ulogic; - atomic_last : std_ulogic; virt_mode : std_ulogic; priv_mode : std_ulogic; - tlb_probe : std_ulogic; addr : std_ulogic_vector(63 downto 0); data : std_ulogic_vector(63 downto 0); -- valid the cycle after .valid = 1 byte_sel : std_ulogic_vector(7 downto 0); - dawr_match : std_ulogic; -- valid the cycle after .valid = 1 end record; - constant Loadstore1ToDcacheInit : Loadstore1ToDcacheType := - (addr => (others => '0'), data => (others => '0'), byte_sel => x"00", - others => '0'); type DcacheToLoadstore1Type is record valid : std_ulogic; @@ -709,7 +607,6 @@ package common is store_done : std_ulogic; error : std_ulogic; cache_paradox : std_ulogic; - reserve_nc : std_ulogic; end record; type DcacheEventType is record @@ -810,9 +707,6 @@ package common is write_xerc_enable : std_ulogic; xerc : xer_common_t; interrupt : std_ulogic; - alt_intr : std_ulogic; - hv_intr : std_ulogic; - is_scv : std_ulogic; intr_vec : intr_vector_t; redirect: std_ulogic; redir_mode: std_ulogic_vector(3 downto 0); @@ -821,6 +715,7 @@ package common is br_taken: std_ulogic; abs_br: std_ulogic; srr1: std_ulogic_vector(15 downto 0); + msr: std_ulogic_vector(63 downto 0); end record; constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', instr_tag => instr_tag_init, rc => '0', mode_32bit => '0', @@ -828,11 +723,30 @@ package common is write_xerc_enable => '0', xerc => xerc_init, write_data => (others => '0'), write_cr_mask => (others => '0'), write_cr_data => (others => '0'), write_reg => (others => '0'), - interrupt => '0', alt_intr => '0', hv_intr => '0', is_scv => '0', intr_vec => 0, - redirect => '0', redir_mode => "0000", + interrupt => '0', intr_vec => 0, redirect => '0', redir_mode => "0000", last_nia => (others => '0'), br_last => '0', br_taken => '0', abs_br => '0', - srr1 => (others => '0')); + srr1 => (others => '0'), msr => (others => '0')); + + -- MMU sandbox SPR interface (execute1 <-> MMU) + -- Dedicated point-to-point channel used by the telemetry sandbox. + -- Treated as a wire interface (no sprn decoding in the MMU); a write + -- on cycle N becomes visible on e_out.rdata on cycle N+1. + type Execute1ToMmuSprType is record + valid : std_ulogic; + write : std_ulogic; + wdata : std_ulogic_vector(63 downto 0); + end record; + + constant Execute1ToMmuSprInit : Execute1ToMmuSprType := + (valid => '0', write => '0', wdata => (others => '0')); + + type MmuToExecute1SprType is record + rdata : std_ulogic_vector(63 downto 0); + end record; + + constant MmuToExecute1SprInit : MmuToExecute1SprType := + (rdata => (others => '0')); type Execute1ToFPUType is record valid : std_ulogic; @@ -917,14 +831,13 @@ package common is br_last : std_ulogic; br_taken : std_ulogic; interrupt : std_ulogic; - alt_intr : std_ulogic; - intr_vec : std_ulogic_vector(63 downto 0); + intr_vec : std_ulogic_vector(11 downto 0); end record; constant WritebackToFetch1Init : WritebackToFetch1Type := (redirect => '0', virt_mode => '0', priv_mode => '0', big_endian => '0', mode_32bit => '0', redirect_nia => (others => '0'), br_last => '0', br_taken => '0', br_nia => (others => '0'), - interrupt => '0', alt_intr => '0', intr_vec => 64x"0"); + interrupt => '0', intr_vec => x"000"); type WritebackToRegisterFileType is record write_reg : gspr_index_t; @@ -947,11 +860,8 @@ package common is write_cr_data => (others => '0')); type WritebackToExecute1Type is record - intr : std_ulogic; - hv_intr : std_ulogic; - scv_int : std_ulogic; - alt_int : std_ulogic; - srr1 : std_ulogic_vector(15 downto 0); + intr : std_ulogic; + srr1 : std_ulogic_vector(15 downto 0); end record; type WritebackEventType is record diff --git a/mmu.vhdl b/mmu.vhdl index 91429f9..7cbb267 100644 --- a/mmu.vhdl +++ b/mmu.vhdl @@ -20,6 +20,11 @@ entity mmu is d_out : out MmuToDcacheType; d_in : in DcacheToMmuType; + -- Sandbox telemetry SPR interface to execute1 (dedicated wires, + -- not decoded from sprn). Write on cycle N -> rdata valid on N+1. + e_in : in Execute1ToMmuSprType; + e_out : out MmuToExecute1SprType; + i_out : out MmuToITLBType ); end mmu; @@ -70,6 +75,9 @@ architecture behave of mmu is segerror : std_ulogic; perm_err : std_ulogic; rc_error : std_ulogic; + -- Sandbox telemetry placeholder. Will eventually be repurposed as + -- a Trace Array capturing bit-packed FSM state for debugging. + temp_trace_array : std_ulogic_vector(63 downto 0); end record; signal r, rin : reg_stage_t; @@ -94,6 +102,8 @@ begin r.pt3_valid <= '0'; r.ptcr <= (others => '0'); r.pid <= (others => '0'); + -- Sandbox telemetry register reset + r.temp_trace_array <= (others => '0'); else if rin.valid = '1' then report "MMU got tlb miss for " & to_hstring(rin.addr); @@ -500,5 +510,56 @@ begin i_out.addr <= addr; i_out.pte <= tlb_data; + -- ===================================================================== + -- Sandbox telemetry SPR pipeline + -- --------------------------------------------------------------------- + -- Dedicated point-to-point path between execute1 and the MMU. No sprn + -- decoding happens here: e_in is treated as a pre-selected wire + -- interface. The intent is a deterministic one-cycle round trip so we + -- can validate pipeline integrity and confirm no cross-path leakage + -- before repurposing temp_trace_array as a real Trace Array. + -- + -- Write (clocked, via next-state v): cycle N + -- Read (combinational, from r) : cycle N+1 + -- ===================================================================== + + -- Write path: update next-state register when execute1 asserts a + -- valid write on the sandbox channel. This is the only writer of + -- temp_trace_array in the current (non-instrumented) build. + if e_in.valid = '1' and e_in.write = '1' then + v.temp_trace_array := e_in.wdata; + end if; + + -- --------------------------------------------------------------------- + -- FUTURE TRACE ARRAY LOGGING BLOCK + -- --------------------------------------------------------------------- + -- When temp_trace_array is promoted from a sandbox placeholder to a + -- real Trace Array, the following pattern will bit-pack selected + -- MMU FSM internals into the register every cycle (or every cycle + -- that a trace-enable qualifier is asserted). The layout below is a + -- proposed example; the final field widths/positions will be fixed + -- once the trace consumer is defined. + -- + -- Proposed packing (LSB-first example, 64 bits total): + -- [ 3: 0] r.state encoded as a 4-bit value + -- [ 4] r.badtree + -- [ 5] r.segerror + -- [ 6] r.perm_err + -- [63: 7] reserved / future trace fields + -- + -- v.temp_trace_array := (others => '0'); + -- v.temp_trace_array(3 downto 0) := + -- std_ulogic_vector(to_unsigned(state_t'pos(r.state), 4)); + -- v.temp_trace_array(4) := r.badtree; + -- v.temp_trace_array(5) := r.segerror; + -- v.temp_trace_array(6) := r.perm_err; + -- --------------------------------------------------------------------- + + -- Read path: combinational drive from the current-state register. + -- Because temp_trace_array is only updated through v in mmu_0, any + -- write issued on cycle N is visible here no earlier than cycle N+1, + -- giving the required one-cycle pass-through latency. + e_out.rdata <= r.temp_trace_array; + end process; end;