mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-02-27 00:59:41 +00:00
core: Send loadstore1 interrupts to writeback rather than execute1
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
29
common.vhdl
29
common.vhdl
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user