From e3f4ccedecca091086ef3328c04d76ff4ee0ed6b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 21 Aug 2023 21:43:35 +1000 Subject: [PATCH] Implement facility unavailable and hypervisor facility unavailable interrupts This adds the FSCR and HFSCR registers and implements the associated behaviours of taking a facility unavailable or hypervisor facility unavailable interrupt if certain actions are attempted while the relevant [H]FSCR bit is zero. At present, two FSCR enable bits and three HFSCR enable bits are implemented. FSCR has bits for prefixed instructions and accesses to the TAR register, and HFSCR has those plus a bit that enables access to floating-point registers and instructions. FSCR and HFSCR can be accessed through the debug interface using register addresses 0x2e and 0x2f. Signed-off-by: Paul Mackerras --- common.vhdl | 53 +++++++++++++----- core_debug.vhdl | 14 ++++- decode1.vhdl | 8 ++- decode2.vhdl | 5 ++ execute1.vhdl | 106 ++++++++++++++++++++++++++++++++++-- scripts/mw_debug/mw_debug.c | 1 + 6 files changed, 166 insertions(+), 21 deletions(-) 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[] = {