This fixes a bug which causes a trace interrupt to store the wrong
value in SRR0 in the case where the instruction that has just
completed is followed by a sc (system call) instruction. What happens
is that first the traced instruction sets ex1.trace_next. Then, when
the sc instruction following it comes in, the execute1_actions process
sets v.e.last_nia to next_nia because it is an sc instruction, even
though it is not going to be executed -- we are going to take the
trace interrupt instead. Then when the trace interrupt is taken, we
incorrectly set SRR0 to the incremented address (the address of the
instruction following the sc).
To fix this, we have execute1_actions set a new flag if the current
instruction is sc, and only set v.e.last_nia to next_nia if we
actually execute the sc (in the "if go = '1'" case).
Fixes: 813e2317bf1f ("execute1: Restructure to separate out execution of side effects", 2022-06-18)
Reported-by: Anton Blanchard <anton@linux.ibm.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
complete : std_ulogic;
exception : std_ulogic;
trap : std_ulogic;
+ advance_nia : std_ulogic;
new_msr : std_ulogic_vector(63 downto 0);
take_branch : std_ulogic;
direct_branch : std_ulogic;
-- 0 would mean scv, so generate an illegal instruction interrupt
if e_in.insn(1) = '1' then
v.trap := '1';
+ v.advance_nia := '1';
v.e.intr_vec := 16#C00#;
- v.e.last_nia := next_nia;
if e_in.valid = '1' then
report "sc";
end if;
v.div_in_progress := actions.start_div;
v.br_mispredict := v.e.redirect and actions.direct_branch;
exception := actions.trap;
+ if actions.advance_nia = '1' then
+ v.e.last_nia := next_nia;
+ end if;
-- Go busy while division is happening because the
-- divider is not pipelined. Also go busy while a