mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-03-10 04:24:30 +00:00
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>
This commit is contained in:
51
common.vhdl
51
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 spr_id_init : spr_id := (sel => "0000", 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 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 =>
|
||||
|
||||
106
execute1.vhdl
106
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
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
Reference in New Issue
Block a user