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 <paulus@ozlabs.org>
pull/434/head
Paul Mackerras 1 year ago
parent 12a3d76217
commit e3f4ccedec

@ -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

@ -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;

@ -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);

@ -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 =>

@ -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

@ -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[] = {

Loading…
Cancel
Save