diff --git a/common.vhdl b/common.vhdl index 64fb755..6759f8f 100644 --- a/common.vhdl +++ b/common.vhdl @@ -55,6 +55,8 @@ package common is constant SPR_PID : spr_num_t := 48; constant SPR_PTCR : spr_num_t := 464; constant SPR_PVR : spr_num_t := 287; + constant SPR_FSCR : spr_num_t := 153; + constant SPR_HFSCR : spr_num_t := 190; -- PMU registers constant SPR_UPMC1 : spr_num_t := 771; @@ -140,22 +142,36 @@ 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(2 downto 0); + subtype spr_selector is std_ulogic_vector(3 downto 0); type spr_id is record sel : spr_selector; valid : std_ulogic; ispmu : std_ulogic; 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"; + constant spr_id_init : spr_id := (sel => "0000", others => '0'); + + constant SPRSEL_TB : spr_selector := 4x"0"; + constant SPRSEL_TBU : spr_selector := 4x"1"; + constant SPRSEL_DEC : spr_selector := 4x"2"; + constant SPRSEL_PVR : spr_selector := 4x"3"; + constant SPRSEL_LOGA : spr_selector := 4x"4"; + constant SPRSEL_LOGD : spr_selector := 4x"5"; + constant SPRSEL_CFAR : spr_selector := 4x"6"; + constant SPRSEL_FSCR : spr_selector := 4x"7"; + constant SPRSEL_HFSCR : spr_selector := 4x"8"; + constant SPRSEL_XER : spr_selector := 4x"f"; + + -- FSCR and HFSCR bit numbers + constant FSCR_PREFIX : integer := 63 - 50; + constant FSCR_SCV : integer := 63 - 51; + constant FSCR_TAR : integer := 63 - 55; + constant FSCR_DSCR3 : integer := 63 - 61; + constant HFSCR_PREFIX : integer := 63 - 50; + constant HFSCR_MSG : integer := 63 - 53; + constant HFSCR_TAR : integer := 63 - 55; + constant HFSCR_PMUSPR : integer := 63 - 60; + constant HFSCR_DSCR : integer := 63 - 61; + constant HFSCR_FP : integer := 63 - 63; -- FPSCR bit numbers constant FPSCR_FX : integer := 63 - 32; @@ -230,9 +246,19 @@ package common is 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_tar: std_ulogic; + hfscr_ic: std_ulogic_vector(3 downto 0); + hfscr_pref: std_ulogic; + hfscr_tar: std_ulogic; + hfscr_fp: std_ulogic; end record; constant ctrl_t_init : ctrl_t := - (xer_low => 18x"0", others => (others => '0')); + (xer_low => 18x"0", + fscr_ic => x"0", fscr_pref => '1', fscr_tar => '1', + hfscr_ic => x"0", hfscr_pref => '1', hfscr_tar => '1', hfscr_fp => '1', + others => (others => '0')); type Fetch1ToIcacheType is record req: std_ulogic; @@ -377,6 +403,7 @@ package common is prefixed : std_ulogic; illegal_suffix : std_ulogic; misaligned_prefix : std_ulogic; + uses_tar : std_ulogic; end record; constant Decode2ToExecute1Init : Decode2ToExecute1Type := (valid => '0', unit => ALU, fac => NONE, insn_type => OP_ILLEGAL, instr_tag => instr_tag_init, @@ -396,7 +423,7 @@ package common is ramspr_wraddr => (others => '0'), ramspr_write_even => '0', ramspr_write_odd => '0', dbg_spr_access => '0', dec_ctr => '0', - prefixed => '0', illegal_suffix => '0', misaligned_prefix => '0', + prefixed => '0', illegal_suffix => '0', misaligned_prefix => '0', uses_tar => '0', others => (others => '0')); type MultiplyInputType is record diff --git a/core_debug.vhdl b/core_debug.vhdl index c7215ff..8e06127 100644 --- a/core_debug.vhdl +++ b/core_debug.vhdl @@ -294,7 +294,7 @@ begin -- For SPRs, use the same mapping as when the fast SPRs were in the GPR file valid := '1'; - sel := "000"; + sel := "0000"; isram := '1'; raddr := (others => '0'); odd := '0'; @@ -324,10 +324,20 @@ begin sel := SPRSEL_XER; when 5x"0d" => raddr := RAMSPR_TAR; + when 5x"0e" => + isram := '0'; + sel := SPRSEL_FSCR; + when 5x"0f" => + isram := '0'; + sel := SPRSEL_HFSCR; when others => valid := '0'; end case; - dbg_spr_addr <= isram & sel & std_ulogic_vector(raddr) & odd; + if isram = '1' then + dbg_spr_addr <= "1000" & std_ulogic_vector(raddr) & odd; + else + dbg_spr_addr <= "0000" & sel; + end if; spr_index_valid <= valid; end if; end process; diff --git a/decode1.vhdl b/decode1.vhdl index 151977d..fd20810 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -427,7 +427,7 @@ architecture behaviour of decode1 is function map_spr(sprn : spr_num_t) return spr_id is variable i : spr_id; begin - i.sel := "000"; + i.sel := "0000"; i.valid := '1'; i.ispmu := '0'; case sprn is @@ -452,6 +452,10 @@ architecture behaviour of decode1 is i.sel := SPRSEL_CFAR; when SPR_XER => i.sel := SPRSEL_XER; + when SPR_FSCR => + i.sel := SPRSEL_FSCR; + when SPR_HFSCR => + i.sel := SPRSEL_HFSCR; when others => i.valid := '0'; end case; @@ -521,7 +525,7 @@ begin v.big_endian := f_in.big_endian; if is_X(f_in.insn) then - v.spr_info := (sel => "XXX", others => 'X'); + v.spr_info := (sel => "XXXX", others => 'X'); v.ram_spr := (index => (others => 'X'), others => 'X'); else sprn := decode_spr_num(f_in.insn); diff --git a/decode2.vhdl b/decode2.vhdl index 74809f5..31a4909 100644 --- a/decode2.vhdl +++ b/decode2.vhdl @@ -450,6 +450,8 @@ begin v.input_ov := '1'; when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR => unit := LDST; + when SPR_TAR => + v.e.uses_tar := '1'; when others => end case; end if; @@ -468,6 +470,8 @@ begin if d_in.valid = '1' then v.sgl_pipe := '1'; end if; + when SPR_TAR => + v.e.uses_tar := '1'; when others => end case; if d_in.spr_info.valid = '1' and d_in.valid = '1' then @@ -525,6 +529,7 @@ begin v.e.ramspr_rd_odd := '1'; else v.e.ramspr_even_rdaddr := RAMSPR_TAR; + v.e.uses_tar := '1'; end if; sprs_busy := '1'; when OP_MFSPR => diff --git a/execute1.vhdl b/execute1.vhdl index 34be583..c6c0960 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -85,6 +85,10 @@ architecture behaviour of execute1 is ramspr_write_even : std_ulogic; ramspr_write_odd : std_ulogic; mult_32s : std_ulogic; + write_fscr : std_ulogic; + write_ic : std_ulogic; + write_hfscr : std_ulogic; + write_hic : std_ulogic; end record; constant side_effect_init : side_effect_type := (others => '0'); @@ -106,11 +110,12 @@ architecture behaviour of execute1 is res2_sel : std_ulogic_vector(1 downto 0); bypass_valid : std_ulogic; ramspr_odd_data : std_ulogic_vector(63 downto 0); + ic : std_ulogic_vector(3 downto 0); end record; constant actions_type_init : actions_type := (e => Execute1ToWritebackInit, se => side_effect_init, new_msr => (others => '0'), res2_sel => "00", - ramspr_odd_data => 64x"0", others => '0'); + ramspr_odd_data => 64x"0", ic => x"0", others => '0'); type reg_stage1_type is record e : Execute1ToWritebackType; @@ -141,6 +146,7 @@ architecture behaviour of execute1 is xerc_valid : std_ulogic; ramspr_wraddr : ramspr_index; ramspr_odd_data : std_ulogic_vector(63 downto 0); + ic : std_ulogic_vector(3 downto 0); end record; constant reg_stage1_type_init : reg_stage1_type := (e => Execute1ToWritebackInit, se => side_effect_init, @@ -155,7 +161,8 @@ architecture behaviour of execute1 is taken_branch_event => '0', br_mispredict => '0', msr => 64x"0", xerc => xerc_init, xerc_valid => '0', - ramspr_wraddr => (others => '0'), ramspr_odd_data => 64x"0"); + ramspr_wraddr => (others => '0'), ramspr_odd_data => 64x"0", + ic => x"0"); type reg_stage2_type is record e : Execute1ToWritebackType; @@ -369,6 +376,27 @@ architecture behaviour of execute1 is xerc.ov32 & xerc.ca32 & xer_low(17 downto 0); end; + function assemble_fscr(c: ctrl_t) return std_ulogic_vector is + variable ret : std_ulogic_vector(63 downto 0); + begin + ret := (others => '0'); + ret(59 downto 56) := c.fscr_ic; + ret(FSCR_PREFIX) := c.fscr_pref; + ret(FSCR_TAR) := c.fscr_tar; + return ret; + end; + + function assemble_hfscr(c: ctrl_t) return std_ulogic_vector is + variable ret : std_ulogic_vector(63 downto 0); + begin + ret := (others => '0'); + ret(59 downto 56) := c.hfscr_ic; + ret(HFSCR_PREFIX) := c.hfscr_pref; + ret(HFSCR_TAR) := c.hfscr_tar; + ret(HFSCR_FP) := c.hfscr_fp; + return ret; + end; + -- Tell vivado to keep the hierarchy for the random module so that the -- net names in the xdc file match. attribute keep_hierarchy : string; @@ -646,7 +674,14 @@ begin if dbg_spr_addr(7) = '1' then dbg_spr_data <= ramspr_result; else - dbg_spr_data <= assemble_xer(xerc_in, ctrl.xer_low); + case dbg_spr_addr(3 downto 0) is + when SPRSEL_FSCR => + dbg_spr_data <= assemble_fscr(ctrl); + when SPRSEL_HFSCR => + dbg_spr_data <= assemble_hfscr(ctrl); + when others => + dbg_spr_data <= assemble_xer(xerc_in, ctrl.xer_low); + end case; end if; dbg_spr_ack <= '1'; end if; @@ -1280,6 +1315,10 @@ begin v.se.write_dec := '1'; when SPRSEL_LOGA => v.se.write_loga := '1'; + when SPRSEL_FSCR => + v.se.write_fscr := '1'; + when SPRSEL_HFSCR => + v.se.write_hfscr := '1'; when others => end case; end if; @@ -1341,7 +1380,25 @@ begin end if; end case; - if misaligned = '1' then + if ex1.msr(MSR_PR) = '1' and e_in.prefixed = '1' and + (ctrl.hfscr_pref = '0' or ctrl.fscr_pref = '0') then + -- [Hypervisor] facility unavailable for prefixed instructions, + -- which has higher priority than the alignment interrupt for + -- misaligned prefixed instructions, which has higher priority than + -- other [hypervisor] facility unavailable interrupts (e.g. for + -- plfs with HFSCR[FP] = 0). + v.exception := '1'; + v.ic := x"b"; + if ctrl.hfscr_pref = '0' then + v.e.hv_intr := '1'; + v.e.intr_vec := 16#f80#; + v.se.write_hic := '1'; + else + v.e.intr_vec := 16#f60#; + v.se.write_ic := '1'; + end if; + + elsif misaligned = '1' then -- generate an alignment interrupt -- This is higher priority than illegal because a misaligned -- prefix will come down as an OP_ILLEGAL instruction. @@ -1373,6 +1430,29 @@ begin report "illegal instruction"; end if; + elsif ex1.msr(MSR_PR) = '1' and e_in.uses_tar = '1' and + (ctrl.hfscr_tar = '0' or ctrl.fscr_tar = '0') then + -- [Hypervisor] facility unavailable for TAR access + v.exception := '1'; + v.ic := x"8"; + if ctrl.hfscr_tar = '0' then + v.e.hv_intr := '1'; + v.e.intr_vec := 16#f80#; + v.se.write_hic := '1'; + else + v.e.intr_vec := 16#f60#; + v.se.write_ic := '1'; + end if; + + elsif HAS_FPU and ex1.msr(MSR_PR) = '1' and e_in.fac = FPU and + ctrl.hfscr_fp = '0' then + -- Hypervisor facility unavailable for FP instructions + v.exception := '1'; + v.ic := x"0"; + v.e.hv_intr := '1'; + v.e.intr_vec := 16#f80#; + v.se.write_hic := '1'; + elsif HAS_FPU and ex1.msr(MSR_FP) = '0' and e_in.fac = FPU then -- generate a floating-point unavailable interrupt v.exception := '1'; @@ -1414,6 +1494,7 @@ begin v.ramspr_wraddr := e_in.ramspr_wraddr; v.lr_from_next := e_in.lr; v.ramspr_odd_data := actions.ramspr_odd_data; + v.ic := actions.ic; end if; lv := Execute1ToLoadstore1Init; @@ -1669,6 +1750,8 @@ begin log_wr_addr & ex2.log_addr_spr when SPRSEL_LOGA, log_rd_data when SPRSEL_LOGD, ctrl.cfar when SPRSEL_CFAR, + assemble_fscr(ctrl) when SPRSEL_FSCR, + assemble_hfscr(ctrl) when SPRSEL_HFSCR, assemble_xer(ex1.e.xerc, ctrl.xer_low) when others; stage2_stall <= l_in.l2stall or fp_in.f2stall; @@ -1811,6 +1894,21 @@ begin v.log_addr_spr := std_ulogic_vector(unsigned(ex2.log_addr_spr) + 1); end if; x_to_pmu.mtspr <= ex1.se.write_pmuspr; + if ex1.se.write_hfscr = '1' then + ctrl_tmp.hfscr_ic <= ex1.e.write_data(59 downto 56); + ctrl_tmp.hfscr_pref <= ex1.e.write_data(HFSCR_PREFIX); + ctrl_tmp.hfscr_tar <= ex1.e.write_data(HFSCR_TAR); + ctrl_tmp.hfscr_fp <= ex1.e.write_data(HFSCR_FP); + elsif ex1.se.write_hic = '1' then + ctrl_tmp.hfscr_ic <= ex1.ic; + end if; + if ex1.se.write_fscr = '1' then + ctrl_tmp.fscr_ic <= ex1.e.write_data(59 downto 56); + ctrl_tmp.fscr_pref <= ex1.e.write_data(FSCR_PREFIX); + ctrl_tmp.fscr_tar <= ex1.e.write_data(FSCR_TAR); + elsif ex1.se.write_ic = '1' then + ctrl_tmp.fscr_ic <= ex1.ic; + end if; end if; if interrupt_in.intr = '1' then diff --git a/scripts/mw_debug/mw_debug.c b/scripts/mw_debug/mw_debug.c index 07c1056..4cb2beb 100644 --- a/scripts/mw_debug/mw_debug.c +++ b/scripts/mw_debug/mw_debug.c @@ -550,6 +550,7 @@ static const char *fast_spr_names[] = "lr", "ctr", "srr0", "srr1", "hsrr0", "hsrr1", "sprg0", "sprg1", "sprg2", "sprg3", "hsprg0", "hsprg1", "xer", "tar", + "fscr", "hfscr", }; static const char *ldst_spr_names[] = {