From fb8f3da1289b676b3e3401922ada439c1009702f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 3 Apr 2020 17:02:14 +1100 Subject: [PATCH] Give exceptions a separate path to writeback This adds separate fields in Execute1ToWritebackType for use in writing SRR0/1 (and in future other SPRs) on an interrupt. With this, we make timing once again on the Arty A7-100 -- previously we were missing by 0.2ns, presumably due to the result mux being wider than before. Signed-off-by: Paul Mackerras --- common.vhdl | 5 ++++- execute1.vhdl | 22 ++++++++++++++-------- writeback.vhdl | 8 ++++++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/common.vhdl b/common.vhdl index 9e4ef99..9f6e96d 100644 --- a/common.vhdl +++ b/common.vhdl @@ -263,9 +263,12 @@ package common is write_cr_data : std_ulogic_vector(31 downto 0); write_xerc_enable : std_ulogic; xerc : xer_common_t; + exc_write_enable : std_ulogic; + exc_write_reg : gspr_index_t; + exc_write_data : std_ulogic_vector(63 downto 0); end record; constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', rc => '0', write_enable => '0', - write_cr_enable => '0', + write_cr_enable => '0', exc_write_enable => '0', write_xerc_enable => '0', xerc => xerc_init, others => (others => '0')); diff --git a/execute1.vhdl b/execute1.vhdl index d006002..2668364 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -237,6 +237,7 @@ begin variable lv : Execute1ToLoadstore1Type; variable irq_valid : std_ulogic; variable exception : std_ulogic; + variable exception_nextpc : std_ulogic; begin result := (others => '0'); result_with_carry := (others => '0'); @@ -386,11 +387,15 @@ begin ctrl_tmp.irq_state <= WRITE_SRR0; exception := '0'; + exception_nextpc := '0'; + v.e.exc_write_enable := '0'; + v.e.exc_write_reg := fast_spr_num(SPR_SRR0); + v.e.exc_write_data := e_in.nia; if ctrl.irq_state = WRITE_SRR1 then - v.e.write_reg := fast_spr_num(SPR_SRR1); - result := ctrl.srr1; - result_en := '1'; + v.e.exc_write_reg := fast_spr_num(SPR_SRR1); + v.e.exc_write_data := ctrl.srr1; + v.e.exc_write_enable := '1'; ctrl_tmp.msr(63 - 48) <= '0'; -- clear EE f_out.redirect <= '1'; f_out.redirect_nia <= ctrl.irq_nia; @@ -403,7 +408,6 @@ begin exception := '1'; ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#900#, 64)); ctrl_tmp.srr1 <= msr_copy(ctrl.msr); - result := e_in.nia; elsif e_in.valid = '1' then @@ -425,16 +429,15 @@ begin -- Since we aren't doing Hypervisor emulation assist (0xe40) we -- set bit 44 to indicate we have an illegal ctrl_tmp.srr1(63 - 44) <= '1'; - result := e_in.nia; report "illegal"; when OP_SC => -- FIXME Assume everything is SC (not SCV) for now -- we need two cycles to write srr0 and 1 -- will need more when we have to write DSISR, DAR and HIER exception := '1'; + exception_nextpc := '1'; ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#C00#, 64)); ctrl_tmp.srr1 <= msr_copy(ctrl.msr); - result := std_logic_vector(unsigned(e_in.nia) + 4); report "sc"; when OP_ATTN => terminate_out <= '1'; @@ -818,12 +821,15 @@ begin end if; if exception = '1' then - v.e.write_reg := fast_spr_num(SPR_SRR0); if e_in.valid = '1' then - result_en := '1'; + 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; end if; diff --git a/writeback.vhdl b/writeback.vhdl index d1a7faf..71870c2 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -35,7 +35,7 @@ begin y(0) := l_in.valid; assert (to_integer(unsigned(x)) + to_integer(unsigned(y))) <= 1 severity failure; - x(0) := e_in.write_enable; + x(0) := e_in.write_enable or e_in.exc_write_enable; y(0) := l_in.write_enable; assert (to_integer(unsigned(x)) + to_integer(unsigned(y))) <= 1 severity failure; @@ -51,7 +51,11 @@ begin complete_out <= '1'; end if; - if e_in.write_enable = '1' then + if e_in.exc_write_enable = '1' then + 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'; -- 2.30.2