core: Send FPU interrupts to writeback rather than execute1

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/269/head
Paul Mackerras 4 years ago
parent 29221315e9
commit acb3d2d745

@ -139,6 +139,8 @@ package common is
constant instr_tag_init : instr_tag_t := (tag => 0, valid => '0');
function tag_match(tag1 : instr_tag_t; tag2 : instr_tag_t) return boolean;

subtype intr_vector_t is integer range 0 to 16#fff#;

-- For now, fixed 16 sources, make this either a parametric
-- package of some sort or an unconstrainted array.
type ics_to_icp_t is record
@ -449,9 +451,9 @@ package common is
rc : std_ulogic;
store_done : std_ulogic;
interrupt : std_ulogic;
intr_vec : integer range 0 to 16#fff#;
intr_vec : intr_vector_t;
srr0: std_ulogic_vector(63 downto 0);
srr1: std_ulogic_vector(31 downto 0);
srr1: std_ulogic_vector(15 downto 0);
end record;
constant Loadstore1ToWritebackInit : Loadstore1ToWritebackType :=
(valid => '0', instr_tag => instr_tag_init, write_enable => '0',
@ -474,7 +476,7 @@ package common is
write_xerc_enable : std_ulogic;
xerc : xer_common_t;
interrupt : std_ulogic;
intr_vec : integer range 0 to 16#fff#;
intr_vec : intr_vector_t;
redirect: std_ulogic;
redir_mode: std_ulogic_vector(3 downto 0);
last_nia: std_ulogic_vector(63 downto 0);
@ -482,7 +484,7 @@ package common is
br_last: std_ulogic;
br_taken: std_ulogic;
abs_br: std_ulogic;
srr1: std_ulogic_vector(31 downto 0);
srr1: std_ulogic_vector(15 downto 0);
msr: std_ulogic_vector(63 downto 0);
end record;
constant Execute1ToWritebackInit : Execute1ToWritebackType :=
@ -521,13 +523,12 @@ package common is
type FPUToExecute1Type is record
busy : std_ulogic;
exception : std_ulogic;
interrupt : std_ulogic;
illegal : std_ulogic;
end record;
constant FPUToExecute1Init : FPUToExecute1Type := (others => '0');

type FPUToWritebackType is record
valid : std_ulogic;
interrupt : std_ulogic;
instr_tag : instr_tag_t;
write_enable : std_ulogic;
write_reg : gspr_index_t;
@ -535,10 +536,17 @@ package common is
write_cr_enable : std_ulogic;
write_cr_mask : std_ulogic_vector(7 downto 0);
write_cr_data : std_ulogic_vector(31 downto 0);
end record;
constant FPUToWritebackInit : FPUToWritebackType := (valid => '0', instr_tag => instr_tag_init,
write_enable => '0', write_cr_enable => '0',
others => (others => '0'));
intr_vec : intr_vector_t;
srr0 : std_ulogic_vector(63 downto 0);
srr1 : std_ulogic_vector(15 downto 0);
end record;
constant FPUToWritebackInit : FPUToWritebackType :=
(valid => '0', interrupt => '0', instr_tag => instr_tag_init,
write_enable => '0', write_reg => (others => '0'),
write_cr_enable => '0', write_cr_mask => (others => '0'),
write_cr_data => (others => '0'),
intr_vec => 0, srr1 => (others => '0'),
others => (others => '0'));

type DividerToExecute1Type is record
valid: std_ulogic;

@ -750,19 +750,19 @@ begin
-- become pending due to MSR[FE0,FE1] changing from 00 to non-zero.
exception := '1';
v.e.intr_vec := 16#700#;
v.e.srr1(63 - 43) := '1';
v.e.srr1(63 - 47) := '1';
v.e.srr1(47 - 43) := '1';
v.e.srr1(47 - 47) := '1';
elsif r.trace_next = '1' then
-- Generate a trace interrupt rather than executing the next instruction
-- or taking any asynchronous interrupt
exception := '1';
v.e.intr_vec := 16#d00#;
v.e.srr1(63 - 33) := '1';
v.e.srr1(47 - 33) := '1';
if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or
r.prev_op = OP_DCBT or r.prev_op = OP_DCBST or r.prev_op = OP_DCBF then
v.e.srr1(63 - 35) := '1';
v.e.srr1(47 - 35) := '1';
elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then
v.e.srr1(63 - 36) := '1';
v.e.srr1(47 - 36) := '1';
end if;

elsif irq_valid = '1' then
@ -775,7 +775,7 @@ begin
exception := '1';
v.e.intr_vec := 16#700#;
-- set bit 45 to indicate privileged instruction type interrupt
v.e.srr1(63 - 45) := '1';
v.e.srr1(47 - 45) := '1';
report "privileged instruction";

elsif not HAS_FPU and e_in.fac = FPU then
@ -840,7 +840,7 @@ begin
-- trap instructions (tw, twi, td, tdi)
v.e.intr_vec := 16#700#;
-- set bit 46 to say trap occurred
v.e.srr1(63 - 46) := '1';
v.e.srr1(47 - 46) := '1';
if or (trapval and insn_to(e_in.insn)) = '1' then
-- generate trap-type program interrupt
exception := '1';
@ -1124,22 +1124,12 @@ begin
v.e.valid := '1';
end if;

-- Generate FP-type program interrupt. fp_in.interrupt will only
-- be set during the execution of a FP instruction.
-- The case where MSR[FE0,FE1] goes from zero to non-zero is
-- handled above by mtmsrd and rfid setting v.fp_exception_next.
if HAS_FPU and fp_in.interrupt = '1' then
v.e.intr_vec := 16#700#;
v.e.srr1(63 - 43) := '1';
exception := '1';
end if;

if illegal = '1' or (HAS_FPU and fp_in.illegal = '1') then
if illegal = '1' then
exception := '1';
v.e.intr_vec := 16#700#;
-- Since we aren't doing Hypervisor emulation assist (0xe40) we
-- set bit 44 to indicate we have an illegal
v.e.srr1(63 - 44) := '1';
v.e.srr1(47 - 44) := '1';
report "illegal";
end if;


@ -73,8 +73,10 @@ architecture behaviour of fpu is
busy : std_ulogic;
instr_done : std_ulogic;
do_intr : std_ulogic;
illegal : std_ulogic;
op : insn_type_t;
insn : std_ulogic_vector(31 downto 0);
nia : std_ulogic_vector(63 downto 0);
instr_tag : instr_tag_t;
dest_fpr : gspr_index_t;
fe_mode : std_ulogic;
@ -572,7 +574,6 @@ begin

e_out.busy <= r.busy;
e_out.exception <= r.fpscr(FPSCR_FEX);
e_out.interrupt <= r.do_intr;

w_out.valid <= r.instr_done and not r.do_intr;
w_out.instr_tag <= r.instr_tag;
@ -583,6 +584,10 @@ begin
w_out.write_cr_mask <= r.cr_mask;
w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result &
r.cr_result & r.cr_result & r.cr_result & r.cr_result;
w_out.interrupt <= r.do_intr;
w_out.intr_vec <= 16#700#;
w_out.srr0 <= r.nia;
w_out.srr1 <= (47-44 => r.illegal, 47-43 => not r.illegal, others => '0');

fpu_1: process(all)
variable v : reg_type;
@ -644,6 +649,7 @@ begin
-- capture incoming instruction
if e_in.valid = '1' then
v.insn := e_in.insn;
v.nia := e_in.nia;
v.op := e_in.op;
v.instr_tag := e_in.itag;
v.fe_mode := or (e_in.fe_mode);
@ -2543,9 +2549,10 @@ begin
v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
end if;

v.illegal := illegal;
if illegal = '1' then
v.instr_done := '0';
v.do_intr := '0';
v.do_intr := '1';
v.writing_back := '0';
v.busy := '0';
v.state := IDLE;
@ -2557,7 +2564,6 @@ begin
end if;

rin <= v;
e_out.illegal <= illegal;
end process;

end architecture behaviour;

@ -108,7 +108,7 @@ architecture behave of loadstore1 is
interrupt : std_ulogic;
intr_vec : integer range 0 to 16#fff#;
nia : std_ulogic_vector(63 downto 0);
srr1 : std_ulogic_vector(31 downto 0);
srr1 : std_ulogic_vector(15 downto 0);
end record;

signal r, rin : reg_stage_t;
@ -721,10 +721,10 @@ begin
end if;
else
if m_in.segerr = '0' then
v.srr1(63 - 33) := m_in.invalid;
v.srr1(63 - 35) := m_in.perm_error; -- noexec fault
v.srr1(63 - 44) := m_in.badtree;
v.srr1(63 - 45) := m_in.rc_error;
v.srr1(47 - 33) := m_in.invalid;
v.srr1(47 - 35) := m_in.perm_error; -- noexec fault
v.srr1(47 - 44) := m_in.badtree;
v.srr1(47 - 45) := m_in.rc_error;
v.intr_vec := 16#400#;
else
v.intr_vec := 16#480#;

@ -82,6 +82,8 @@ begin
variable sign : std_ulogic;
variable scf : std_ulogic_vector(3 downto 0);
variable vec : integer range 0 to 16#fff#;
variable srr1 : std_ulogic_vector(15 downto 0);
variable intr : std_ulogic;
begin
w_out <= WritebackToRegisterFileInit;
c_out <= WritebackToCrFileInit;
@ -99,6 +101,8 @@ begin
complete_out <= fp_in.instr_tag;
end if;

intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;

if r.state = WRITE_SRR1 then
w_out.write_reg <= fast_spr_num(SPR_SRR1);
w_out.write_data <= r.srr1;
@ -106,23 +110,29 @@ begin
interrupt_out <= '1';
v.state := WRITE_SRR0;

elsif e_in.interrupt = '1' then
w_out.write_reg <= fast_spr_num(SPR_SRR0);
w_out.write_data <= e_in.last_nia;
w_out.write_enable <= '1';
v.state := WRITE_SRR1;
v.srr1(63 downto 32) := e_in.msr(63 downto 32);
v.srr1(31 downto 0) := e_in.msr(31 downto 0) or e_in.srr1;
vec := e_in.intr_vec;

elsif l_in.interrupt = '1' then
elsif intr = '1' then
w_out.write_reg <= fast_spr_num(SPR_SRR0);
w_out.write_data <= l_in.srr0;
w_out.write_enable <= '1';
v.state := WRITE_SRR1;
v.srr1(63 downto 32) := e_in.msr(63 downto 32);
v.srr1(31 downto 0) := e_in.msr(31 downto 0) or l_in.srr1;
vec := l_in.intr_vec;
srr1 := (others => '0');
if e_in.interrupt = '1' then
vec := e_in.intr_vec;
w_out.write_data <= e_in.last_nia;
srr1 := e_in.srr1;
elsif l_in.interrupt = '1' then
vec := l_in.intr_vec;
w_out.write_data <= l_in.srr0;
srr1 := l_in.srr1;
elsif fp_in.interrupt = '1' then
vec := fp_in.intr_vec;
w_out.write_data <= fp_in.srr0;
srr1 := fp_in.srr1;
end if;
v.srr1(63 downto 31) := e_in.msr(63 downto 31);
v.srr1(30 downto 27) := srr1(14 downto 11);
v.srr1(26 downto 22) := e_in.msr(26 downto 22);
v.srr1(21 downto 16) := srr1(5 downto 0);
v.srr1(15 downto 0) := e_in.msr(15 downto 0);

else
if e_in.write_enable = '1' then
@ -196,7 +206,7 @@ begin
f.br_nia := e_in.last_nia;
f.br_last := e_in.br_last;
f.br_taken := e_in.br_taken;
if e_in.interrupt = '1' or l_in.interrupt = '1' then
if intr = '1' then
f.redirect := '1';
f.br_last := '0';
f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));

Loading…
Cancel
Save