From 29221315e90120cd5bb134d8035803fa2d829e32 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 23 Dec 2020 12:27:22 +1100 Subject: [PATCH] core: Send loadstore1 interrupts to writeback rather than execute1 Signed-off-by: Paul Mackerras --- common.vhdl | 29 ++++++++++++++----------- execute1.vhdl | 29 +++---------------------- loadstore1.vhdl | 57 +++++++++++++++++++++++++++++++++++-------------- writeback.vhdl | 26 +++++++++++++++++----- 4 files changed, 81 insertions(+), 60 deletions(-) diff --git a/common.vhdl b/common.vhdl index b2d6b13..48ba46f 100644 --- a/common.vhdl +++ b/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; diff --git a/execute1.vhdl b/execute1.vhdl index 875e22c..f8507bb 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -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; diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 935ce5f..f4f4f4a 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -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 & diff --git a/writeback.vhdl b/writeback.vhdl index c7632ea..40cd5b4 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -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