From d77033aa92b372e52e96b6d8d3f5aa990d5e412c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 7 Apr 2020 18:38:18 +1000 Subject: [PATCH] execute1: Simplify the interrupt logic a little This makes some simplifications to the interrupt logic which will help with later commits. - When irq_valid is set, don't set exception to 1 until we have a valid instruction. That means we can remove the if e_in.valid = '1' test from the exception = '1' block. - Don't assert stall_out on the first cycle of delivering an interrupt. If we do get another instruction in the next cycle, nothing will happen because we have ctrl.irq_state set and we will just continue writing the interrupt registers. - Make sure we deliver as many completions as we got instructions, otherwise the outstanding instruction count in control.vhdl gets out of sync. - In writeback, make sure all of the other write enables are ignored when e_in.exc_write_enable is set. Signed-off-by: Paul Mackerras --- execute1.vhdl | 22 ++++++------ writeback.vhdl | 94 ++++++++++++++++++++++++++------------------------ 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/execute1.vhdl b/execute1.vhdl index ffa9048..6c19559 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -399,13 +399,15 @@ begin ctrl_tmp.msr(63 - 48) <= '0'; -- clear EE f_out.redirect <= '1'; f_out.redirect_nia <= ctrl.irq_nia; - v.e.valid := '1'; + v.e.valid := e_in.valid; report "Writing SRR1: " & to_hstring(ctrl.srr1); elsif irq_valid = '1' then -- we need two cycles to write srr0 and 1 -- will need more when we have to write DSISR, DAR and HIER - exception := '1'; + -- Don't deliver the interrupt until we have a valid instruction + -- coming in, so we have a valid NIA to put in SRR0. + exception := e_in.valid; ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#900#, 64)); ctrl_tmp.srr1 <= msr_copy(ctrl.msr); @@ -821,16 +823,12 @@ begin end if; if exception = '1' then - if e_in.valid = '1' then - v.e.exc_write_enable := '1'; - if exception_nextpc = '1' then - v.e.exc_write_data := std_logic_vector(unsigned(e_in.nia) + 4); - end if; - ctrl_tmp.irq_state <= WRITE_SRR1; - stall_out <= '1'; - v.e.valid := '0'; - result_en := '0'; - end if; + v.e.exc_write_enable := '1'; + if exception_nextpc = '1' then + v.e.exc_write_data := next_nia; + end if; + ctrl_tmp.irq_state <= WRITE_SRR1; + v.e.valid := '1'; end if; v.e.write_data := result; diff --git a/writeback.vhdl b/writeback.vhdl index 71870c2..60afebb 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -55,52 +55,54 @@ begin w_out.write_reg <= e_in.exc_write_reg; w_out.write_data <= e_in.exc_write_data; w_out.write_enable <= '1'; - elsif e_in.write_enable = '1' then - w_out.write_reg <= e_in.write_reg; - w_out.write_data <= e_in.write_data; - w_out.write_enable <= '1'; - end if; - - if e_in.write_cr_enable = '1' then - c_out.write_cr_enable <= '1'; - c_out.write_cr_mask <= e_in.write_cr_mask; - c_out.write_cr_data <= e_in.write_cr_data; - end if; - - if e_in.write_xerc_enable = '1' then - c_out.write_xerc_enable <= '1'; - c_out.write_xerc_data <= e_in.xerc; - end if; - - if l_in.write_enable = '1' then - w_out.write_reg <= gpr_to_gspr(l_in.write_reg); - w_out.write_data <= l_in.write_data; - w_out.write_enable <= '1'; - end if; - - if l_in.rc = '1' then - -- st*cx. instructions - scf(3) := '0'; - scf(2) := '0'; - scf(1) := l_in.store_done; - scf(0) := l_in.xerc.so; - c_out.write_cr_enable <= '1'; - c_out.write_cr_mask <= num_to_fxm(0); - c_out.write_cr_data(31 downto 28) <= scf; - end if; - - -- Perform CR0 update for RC forms - -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data - if e_in.rc = '1' and e_in.write_enable = '1' then - sign := e_in.write_data(63); - zero := not (or e_in.write_data); - c_out.write_cr_enable <= '1'; - c_out.write_cr_mask <= num_to_fxm(0); - cf(3) := sign; - cf(2) := not sign and not zero; - cf(1) := zero; - cf(0) := e_in.xerc.so; - c_out.write_cr_data(31 downto 28) <= cf; + else + if e_in.write_enable = '1' then + w_out.write_reg <= e_in.write_reg; + w_out.write_data <= e_in.write_data; + w_out.write_enable <= '1'; + end if; + + if e_in.write_cr_enable = '1' then + c_out.write_cr_enable <= '1'; + c_out.write_cr_mask <= e_in.write_cr_mask; + c_out.write_cr_data <= e_in.write_cr_data; + end if; + + if e_in.write_xerc_enable = '1' then + c_out.write_xerc_enable <= '1'; + c_out.write_xerc_data <= e_in.xerc; + end if; + + if l_in.write_enable = '1' then + w_out.write_reg <= gpr_to_gspr(l_in.write_reg); + w_out.write_data <= l_in.write_data; + w_out.write_enable <= '1'; + end if; + + if l_in.rc = '1' then + -- st*cx. instructions + scf(3) := '0'; + scf(2) := '0'; + scf(1) := l_in.store_done; + scf(0) := l_in.xerc.so; + c_out.write_cr_enable <= '1'; + c_out.write_cr_mask <= num_to_fxm(0); + c_out.write_cr_data(31 downto 28) <= scf; + end if; + + -- Perform CR0 update for RC forms + -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data + if e_in.rc = '1' and e_in.write_enable = '1' then + sign := e_in.write_data(63); + zero := not (or e_in.write_data); + c_out.write_cr_enable <= '1'; + c_out.write_cr_mask <= num_to_fxm(0); + cf(3) := sign; + cf(2) := not sign and not zero; + cf(1) := zero; + cf(0) := e_in.xerc.so; + c_out.write_cr_data(31 downto 28) <= cf; + end if; end if; end process; end;