core: Send loadstore1 interrupts to writeback rather than execute1

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

@ -349,6 +349,7 @@ package common is
is_32bit : std_ulogic;
repeat : std_ulogic;
second : std_ulogic;
msr : std_ulogic_vector(63 downto 0);
end record;
constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type :=
(valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0',
@ -360,18 +361,11 @@ package common is
write_reg => (others => '0'),
length => (others => '0'),
mode_32bit => '0', is_32bit => '0',
repeat => '0', second => '0');
repeat => '0', second => '0',
msr => (others => '0'));

type Loadstore1ToExecute1Type is record
busy : std_ulogic;
exception : std_ulogic;
alignment : std_ulogic;
invalid : std_ulogic;
perm_error : std_ulogic;
rc_error : std_ulogic;
badtree : std_ulogic;
segment_fault : std_ulogic;
instr_fault : std_ulogic;
end record;

type Loadstore1ToDcacheType is record
@ -454,10 +448,17 @@ package common is
xerc : xer_common_t;
rc : std_ulogic;
store_done : std_ulogic;
interrupt : std_ulogic;
intr_vec : integer range 0 to 16#fff#;
srr0: std_ulogic_vector(63 downto 0);
srr1: std_ulogic_vector(31 downto 0);
end record;
constant Loadstore1ToWritebackInit : Loadstore1ToWritebackType :=
(valid => '0', instr_tag => instr_tag_init, write_enable => '0', xerc => xerc_init,
rc => '0', store_done => '0', write_data => (others => '0'), others => (others => '0'));
(valid => '0', instr_tag => instr_tag_init, write_enable => '0',
write_reg => (others => '0'), write_data => (others => '0'),
xerc => xerc_init, rc => '0', store_done => '0',
interrupt => '0', intr_vec => 0,
srr0 => (others => '0'), srr1 => (others => '0'));

type Execute1ToWritebackType is record
valid: std_ulogic;
@ -481,7 +482,8 @@ package common is
br_last: std_ulogic;
br_taken: std_ulogic;
abs_br: std_ulogic;
srr1: std_ulogic_vector(63 downto 0);
srr1: std_ulogic_vector(31 downto 0);
msr: std_ulogic_vector(63 downto 0);
end record;
constant Execute1ToWritebackInit : Execute1ToWritebackType :=
(valid => '0', instr_tag => instr_tag_init, rc => '0', mode_32bit => '0',
@ -491,7 +493,8 @@ package common is
write_cr_data => (others => '0'), write_reg => (others => '0'),
interrupt => '0', intr_vec => 0, redirect => '0', redir_mode => "0000",
last_nia => (others => '0'), br_offset => (others => '0'),
br_last => '0', br_taken => '0', abs_br => '0', srr1 => (others => '0'));
br_last => '0', br_taken => '0', abs_br => '0',
srr1 => (others => '0'), msr => (others => '0'));

type Execute1ToFPUType is record
valid : std_ulogic;

@ -725,7 +725,7 @@ begin
rot_clear_right <= '1' when e_in.insn_type = OP_RLC or e_in.insn_type = OP_RLCR else '0';
rot_sign_ext <= '1' when e_in.insn_type = OP_EXTSWSLI else '0';

v.e.srr1 := msr_copy(ctrl.msr);
v.e.srr1 := (others => '0');
exception := '0';
illegal := '0';
if valid_in = '1' then
@ -1143,31 +1143,7 @@ begin
report "illegal";
end if;

-- generate DSI or DSegI for load/store exceptions
-- or ISI or ISegI for instruction fetch exceptions
if l_in.exception = '1' then
if l_in.alignment = '1' then
v.e.intr_vec := 16#600#;
elsif l_in.instr_fault = '0' then
if l_in.segment_fault = '0' then
v.e.intr_vec := 16#300#;
else
v.e.intr_vec := 16#380#;
end if;
else
if l_in.segment_fault = '0' then
v.e.srr1(63 - 33) := l_in.invalid;
v.e.srr1(63 - 35) := l_in.perm_error; -- noexec fault
v.e.srr1(63 - 44) := l_in.badtree;
v.e.srr1(63 - 45) := l_in.rc_error;
v.e.intr_vec := 16#400#;
else
v.e.intr_vec := 16#480#;
end if;
end if;
end if;

v.e.interrupt := exception or l_in.exception;
v.e.interrupt := exception;

if do_trace = '1' then
v.trace_next := '1';
@ -1265,6 +1241,7 @@ begin
-- update outputs
l_out <= lv;
e_out <= r.e;
e_out.msr <= msr_copy(ctrl.msr);
fp_out <= fv;

exception_log <= exception;

@ -105,6 +105,10 @@ architecture behave of loadstore1 is
ld_sp_nz : std_ulogic;
ld_sp_lz : std_ulogic_vector(5 downto 0);
wr_sel : std_ulogic_vector(1 downto 0);
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);
end record;

signal r, rin : reg_stage_t;
@ -220,6 +224,7 @@ begin
r.state <= IDLE;
r.busy <= '0';
r.do_update <= '0';
r.interrupt <= '0';
else
r <= rin;
end if;
@ -520,6 +525,8 @@ begin
v.wait_dcache := '0';
v.wait_mmu := '0';
v.extra_cycle := '0';
v.nia := l_in.nia;
v.srr1 := (others => '0');

if HAS_FPU and l_in.is_32bit = '1' then
v.store_data := x"00000000" & store_sp_data;
@ -697,6 +704,34 @@ begin
end if;
end loop;

-- generate DSI or DSegI for load/store exceptions
-- or ISI or ISegI for instruction fetch exceptions
v.interrupt := exception;
if exception = '1' then
if r.align_intr = '1' then
v.intr_vec := 16#600#;
v.dar := addr;
elsif r.instr_fault = '0' then
v.dar := addr;
if m_in.segerr = '0' then
v.intr_vec := 16#300#;
v.dsisr := dsisr;
else
v.intr_vec := 16#380#;
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.intr_vec := 16#400#;
else
v.intr_vec := 16#480#;
end if;
end if;
end if;

-- Update outputs to dcache
d_out.valid <= req and not v.align_intr;
d_out.load <= v.load;
@ -746,23 +781,13 @@ begin
l_out.xerc <= r.xerc;
l_out.rc <= r.rc and done;
l_out.store_done <= d_in.store_done;
l_out.interrupt <= r.interrupt;
l_out.intr_vec <= r.intr_vec;
l_out.srr0 <= r.nia;
l_out.srr1 <= r.srr1;

-- update exception info back to execute1
-- update busy signal back to execute1
e_out.busy <= busy;
e_out.exception <= exception;
e_out.alignment <= r.align_intr;
e_out.instr_fault <= r.instr_fault;
e_out.invalid <= m_in.invalid;
e_out.badtree <= m_in.badtree;
e_out.perm_error <= m_in.perm_error;
e_out.rc_error <= m_in.rc_error;
e_out.segment_fault <= m_in.segerr;
if exception = '1' and r.instr_fault = '0' then
v.dar := addr;
if m_in.segerr = '0' and r.align_intr = '0' then
v.dsisr := dsisr;
end if;
end if;

-- Update registers
rin <= v;
@ -776,7 +801,7 @@ begin
begin
if rising_edge(clk) then
log_data <= e_out.busy &
e_out.exception &
l_out.interrupt &
l_out.valid &
m_out.valid &
d_out.valid &

@ -81,11 +81,13 @@ begin
variable zero : std_ulogic;
variable sign : std_ulogic;
variable scf : std_ulogic_vector(3 downto 0);
variable vec : integer range 0 to 16#fff#;
begin
w_out <= WritebackToRegisterFileInit;
c_out <= WritebackToCrFileInit;
f := WritebackToFetch1Init;
interrupt_out <= '0';
vec := 0;
v := r;

complete_out <= instr_tag_init;
@ -109,7 +111,19 @@ begin
w_out.write_data <= e_in.last_nia;
w_out.write_enable <= '1';
v.state := WRITE_SRR1;
v.srr1 := e_in.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
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;

else
if e_in.write_enable = '1' then
w_out.write_reg <= e_in.write_reg;
@ -178,12 +192,14 @@ begin
end if;

-- Outputs to fetch1
f.redirect := e_in.redirect or e_in.interrupt;
f.redirect := e_in.redirect;
f.br_nia := e_in.last_nia;
f.br_last := e_in.br_last and not e_in.interrupt;
f.br_last := e_in.br_last;
f.br_taken := e_in.br_taken;
if e_in.interrupt = '1' then
f.redirect_nia := std_ulogic_vector(to_unsigned(e_in.intr_vec, 64));
if e_in.interrupt = '1' or l_in.interrupt = '1' then
f.redirect := '1';
f.br_last := '0';
f.redirect_nia := std_ulogic_vector(to_unsigned(vec, 64));
f.virt_mode := '0';
f.priv_mode := '1';
-- XXX need an interrupt LE bit here, e.g. from LPCR

Loading…
Cancel
Save