From ff00dc1505efa4258dc456e3d5109bbee7d5f7ea Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 15 Jan 2025 21:47:51 +1100 Subject: [PATCH] PMU: Fix setting of SIAR and SDAR on trace interrupt This arranges for SIAR and SDAR to be set when a trace interrupt is triggered by a non-zero setting of the MSR[TE] field. According to the ISA, SIAR should be set to the address of the instruction and SDAR should be set to the effective address of its storage operand if any. This also fixes setting of SDAR by the PMU when an alert occurs; previously it was always just set to zero. Signed-off-by: Paul Mackerras --- common.vhdl | 3 +++ execute1.vhdl | 10 ++++++---- loadstore1.vhdl | 12 ++++++++++-- pmu.vhdl | 4 ++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/common.vhdl b/common.vhdl index d182a32..dc5348a 100644 --- a/common.vhdl +++ b/common.vhdl @@ -529,6 +529,7 @@ package common is nia : std_ulogic_vector(63 downto 0); addr : std_ulogic_vector(63 downto 0); addr_v : std_ulogic; + trace : std_ulogic; occur : PMUEventType; end record; @@ -601,6 +602,8 @@ package common is type Loadstore1ToExecute1Type is record busy : std_ulogic; l2stall : std_ulogic; + ea_for_pmu : std_ulogic_vector(63 downto 0); + ea_valid : std_ulogic; end record; type Loadstore1ToDcacheType is record diff --git a/execute1.vhdl b/execute1.vhdl index 5240063..a3b9522 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -254,6 +254,7 @@ architecture behaviour of execute1 is -- PMU signals signal x_to_pmu : Execute1ToPMUType; signal pmu_to_x : PMUToExecute1Type; + signal pmu_trace : std_ulogic; -- signals for logging signal exception_log : std_ulogic; @@ -560,11 +561,12 @@ begin br_mispredict => ex2.br_mispredict, others => '0'); x_to_pmu.nia <= e_in.nia; - x_to_pmu.addr <= (others => '0'); - x_to_pmu.addr_v <= '0'; + x_to_pmu.addr <= l_in.ea_for_pmu; + x_to_pmu.addr_v <= l_in.ea_valid; x_to_pmu.spr_num <= ex1.pmu_spr_num; x_to_pmu.spr_val <= ex1.e.write_data; x_to_pmu.run <= ctrl.run; + x_to_pmu.trace <= pmu_trace; -- XER forwarding. The CA and CA32 bits are only modified by instructions -- that are handled here, so for them we can just use the result most @@ -1163,7 +1165,6 @@ begin -- see if we have a CIABR map if ctrl.ciabr(0) = '1' and ctrl.ciabr(1) = not ex1.msr(MSR_PR) and ctrl.ciabr(63 downto 2) = e_in.nia(63 downto 2) then - v.do_trace := '1'; v.ciabr_trace := '1'; end if; @@ -1707,7 +1708,7 @@ begin v.e.valid := actions.complete; bypass_valid := actions.bypass_valid; v.taken_branch_event := actions.take_branch; - v.trace_next := actions.do_trace; + v.trace_next := actions.do_trace or actions.ciabr_trace; v.trace_ciabr := actions.ciabr_trace; v.fp_exception_next := actions.fp_intr; v.res2_sel := actions.res2_sel; @@ -1740,6 +1741,7 @@ begin end if; is_scv := go and actions.se.scv_trap; bsort_start <= go and actions.start_bsort; + pmu_trace <= go and actions.do_trace; if not HAS_FPU and ex1.div_in_progress = '1' then v.div_in_progress := not divider_to_x.valid; diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 77b7060..85fb129 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -102,6 +102,7 @@ architecture behave of loadstore1 is dword_index : std_ulogic; two_dwords : std_ulogic; incomplete : std_ulogic; + ea_valid : std_ulogic; end record; constant request_init : request_t := (valid => '0', dc_req => '0', load => '0', store => '0', flush => '0', touch => '0', sync => '0', tlbie => '0', @@ -119,7 +120,8 @@ architecture behave of loadstore1 is rc => '0', nc => '0', virt_mode => '0', priv_mode => '0', load_sp => '0', sprsel => "00", ric => "00", is_slbia => '0', align_intr => '0', - dword_index => '0', two_dwords => '0', incomplete => '0'); + dword_index => '0', two_dwords => '0', incomplete => '0', + ea_valid => '0'); type reg_stage1_t is record req : request_t; @@ -464,6 +466,7 @@ begin addr(63 downto 32) := (others => '0'); end if; v.addr := addr; + v.ea_valid := l_in.valid; -- XXX Temporary hack. Mark the op as non-cachable if the address -- is the form 0xc------- for a real-mode access. @@ -509,6 +512,7 @@ begin case l_in.op is when OP_SYNC => v.sync := '1'; + v.ea_valid := '0'; when OP_STORE => v.store := '1'; if l_in.length = "0000" then @@ -536,14 +540,15 @@ begin v.align_intr := v.nc; when OP_TLBIE => v.tlbie := '1'; - v.addr := l_in.addr2; -- address from RB for tlbie v.is_slbia := l_in.insn(7); v.mmu_op := '1'; when OP_MFSPR => v.read_spr := '1'; + v.ea_valid := '0'; when OP_MTSPR => v.write_spr := '1'; v.mmu_op := not sprn(1); + v.ea_valid := '0'; when OP_FETCH_FAILED => -- send it to the MMU to do the radix walk v.instr_fault := '1'; @@ -1067,6 +1072,9 @@ begin e_out.busy <= busy; e_out.l2stall <= dc_stall or d_in.error or r2.busy; + e_out.ea_for_pmu <= req_in.addr; + e_out.ea_valid <= req_in.ea_valid; + events <= r3.events; flush <= exception; diff --git a/pmu.vhdl b/pmu.vhdl index 928d6c2..2afa1eb 100644 --- a/pmu.vhdl +++ b/pmu.vhdl @@ -183,12 +183,12 @@ begin end if; if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "1100" then siar <= p_in.spr_val; - elsif doalert = '1' then + elsif doalert = '1' or p_in.trace = '1' then siar <= p_in.nia; end if; if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "1101" then sdar <= p_in.spr_val; - elsif doalert = '1' then + elsif doalert = '1' or p_in.trace = '1' then sdar <= p_in.addr; end if; if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "0000" then