From b589d2d472be58d81e01aad6de467119ee15e1a4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 28 Aug 2020 20:34:09 +1000 Subject: [PATCH] execute1: Implement trace interrupts Trace interrupts occur when the MSR[TE] field is non-zero and an instruction other than rfid has been successfully completed. A trace interrupt occurs before the next instruction is executed or any asynchronous interrupt is taken. Since the trace interrupt is defined to set SRR1 bits depending on whether the traced instruction is a load or an instruction treated as a load, or a store or an instruction treated as a store, we need to make sure the treated-as-a-load instructions (icbi, icbt, dcbt, dcbst, dcbf) and the treated-as-a-store instructions (dcbtst, dcbz) have the correct opcodes in decode1. Several of them were previously marked as OP_NOP. We don't yet implement the SIAR or SDAR registers, which should be set by trace interrupts. Signed-off-by: Paul Mackerras --- common.vhdl | 2 ++ decode1.vhdl | 10 +++++----- execute1.vhdl | 42 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/common.vhdl b/common.vhdl index 03211ce..1ca1178 100644 --- a/common.vhdl +++ b/common.vhdl @@ -13,6 +13,8 @@ package common is constant MSR_SF : integer := (63 - 0); -- Sixty-Four bit mode constant MSR_EE : integer := (63 - 48); -- External interrupt Enable constant MSR_PR : integer := (63 - 49); -- PRoblem state + constant MSR_SE : integer := (63 - 53); -- Single-step bit of TE field + constant MSR_BE : integer := (63 - 54); -- Branch trace bit of TE field constant MSR_IR : integer := (63 - 58); -- Instruction Relocation constant MSR_DR : integer := (63 - 59); -- Data Relocation constant MSR_RI : integer := (63 - 62); -- Recoverable Interrupt diff --git a/decode1.vhdl b/decode1.vhdl index 9544637..a7d5910 100644 --- a/decode1.vhdl +++ b/decode1.vhdl @@ -201,10 +201,10 @@ architecture behaviour of decode1 is 2#1000111010# => (ALU, OP_CNTZ, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- cnttzd 2#1000011010# => (ALU, OP_CNTZ, NONE, NONE, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0'), -- cnttzw 2#1011110011# => (ALU, OP_DARN, NONE, NONE, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- darn - 2#0001010110# => (ALU, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbf - 2#0000110110# => (ALU, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbst - 2#0100010110# => (ALU, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbt - 2#0011110110# => (ALU, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbtst + 2#0001010110# => (ALU, OP_DCBF, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbf + 2#0000110110# => (ALU, OP_DCBST, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbst + 2#0100010110# => (ALU, OP_DCBT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbt + 2#0011110110# => (ALU, OP_DCBTST, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbtst 2#1111110110# => (LDST, OP_DCBZ, RA_OR_ZERO, RB, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- dcbz 2#0110001001# => (ALU, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- divdeu 2#1110001001# => (ALU, OP_DIVE, RA, RB, NONE, RT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- divdeuo @@ -230,7 +230,7 @@ architecture behaviour of decode1 is 2#1101111010# => (ALU, OP_EXTSWSLI, NONE, CONST_SH, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- extswsli 2#1101111011# => (ALU, OP_EXTSWSLI, NONE, CONST_SH, RS, RA, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0'), -- extswsli 2#1111010110# => (ALU, OP_ICBI, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- icbi - 2#0000010110# => (ALU, OP_NOP, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- icbt + 2#0000010110# => (ALU, OP_ICBT, NONE, NONE, NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- icbt 2#0000001111# => (ALU, OP_ISEL, RA_OR_ZERO, RB, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- isel 2#0000101111# => (ALU, OP_ISEL, RA_OR_ZERO, RB, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- isel 2#0001001111# => (ALU, OP_ISEL, RA_OR_ZERO, RB, NONE, RT, '1', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- isel diff --git a/execute1.vhdl b/execute1.vhdl index 076c4ae..04cc970 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -53,6 +53,8 @@ architecture behaviour of execute1 is f : Execute1ToFetch1Type; busy: std_ulogic; terminate: std_ulogic; + trace_next : std_ulogic; + prev_op : insn_type_t; lr_update : std_ulogic; next_lr : std_ulogic_vector(63 downto 0); mul_in_progress : std_ulogic; @@ -69,7 +71,7 @@ architecture behaviour of execute1 is end record; constant reg_type_init : reg_type := (e => Execute1ToWritebackInit, f => Execute1ToFetch1Init, - busy => '0', lr_update => '0', terminate => '0', + busy => '0', lr_update => '0', terminate => '0', trace_next => '0', prev_op => OP_ILLEGAL, mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0', slow_op_insn => OP_ILLEGAL, slow_op_rc => '0', slow_op_oe => '0', slow_op_xerc => xerc_init, next_lr => (others => '0'), last_nia => (others => '0'), others => (others => '0')); @@ -330,6 +332,7 @@ begin variable abs_branch : std_ulogic; variable spr_val : std_ulogic_vector(63 downto 0); variable addend : std_ulogic_vector(127 downto 0); + variable do_trace : std_ulogic; begin result := (others => '0'); sum_with_carry := (others => '0'); @@ -525,6 +528,11 @@ begin v.e.mode_32bit := not ctrl.msr(MSR_SF); + do_trace := valid_in and ctrl.msr(MSR_SE); + if valid_in = '1' then + v.prev_op := e_in.insn_type; + end if; + if ctrl.irq_state = WRITE_SRR1 then v.e.exc_write_reg := fast_spr_num(SPR_SRR1); v.e.exc_write_data := ctrl.srr1; @@ -532,13 +540,29 @@ begin ctrl_tmp.msr(MSR_SF) <= '1'; ctrl_tmp.msr(MSR_EE) <= '0'; ctrl_tmp.msr(MSR_PR) <= '0'; + ctrl_tmp.msr(MSR_SE) <= '0'; + ctrl_tmp.msr(MSR_BE) <= '0'; ctrl_tmp.msr(MSR_IR) <= '0'; ctrl_tmp.msr(MSR_DR) <= '0'; ctrl_tmp.msr(MSR_RI) <= '0'; ctrl_tmp.msr(MSR_LE) <= '1'; v.e.valid := '1'; + v.trace_next := '0'; report "Writing SRR1: " & to_hstring(ctrl.srr1); + elsif r.trace_next = '1' and valid_in = '1' then + -- Generate a trace interrupt rather than executing the next instruction + -- or taking any asynchronous interrupt + v.f.redirect_nia := std_logic_vector(to_unsigned(16#d00#, 64)); + ctrl_tmp.srr1(63 - 33) <= '1'; + if r.prev_op = OP_LOAD or r.prev_op = OP_ICBI or r.prev_op = OP_ICBT or + r.prev_op = OP_DCBT or r.prev_op = OP_DCBST or r.prev_op = OP_DCBF then + ctrl_tmp.srr1(63 - 35) <= '1'; + elsif r.prev_op = OP_STORE or r.prev_op = OP_DCBZ or r.prev_op = OP_DCBTST then + ctrl_tmp.srr1(63 - 36) <= '1'; + end if; + exception := '1'; + elsif irq_valid = '1' and valid_in = '1' then -- we need two cycles to write srr0 and 1 -- will need more when we have to write HEIR @@ -594,7 +618,7 @@ begin else illegal := '1'; end if; - when OP_NOP => + when OP_NOP | OP_DCBF | OP_DCBST | OP_DCBT | OP_DCBTST | OP_ICBT => -- Do nothing when OP_ADD | OP_CMP | OP_TRAP => result := sum_with_carry(63 downto 0); @@ -715,6 +739,9 @@ begin is_branch := '1'; taken_branch := '1'; abs_branch := insn_aa(e_in.insn); + if ctrl.msr(MSR_BE) = '1' then + do_trace := '1'; + end if; when OP_BC => -- read_data1 is CTR bo := insn_bo(e_in.insn); @@ -727,6 +754,9 @@ begin is_branch := '1'; taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in); abs_branch := insn_aa(e_in.insn); + if ctrl.msr(MSR_BE) = '1' then + do_trace := '1'; + end if; when OP_BCREG => -- read_data1 is CTR -- read_data2 is target register (CTR, LR or TAR) @@ -740,6 +770,9 @@ begin is_branch := '1'; taken_branch := ppc_bc_taken(bo, bi, cr_in, a_in); abs_branch := '1'; + if ctrl.msr(MSR_BE) = '1' then + do_trace := '1'; + end if; when OP_RFID => v.f.virt_mode := a_in(MSR_IR) or a_in(MSR_PR); @@ -760,6 +793,7 @@ begin is_branch := '1'; taken_branch := '1'; abs_branch := '1'; + do_trace := '0'; when OP_CNTZ => v.e.valid := '0'; @@ -1135,6 +1169,10 @@ begin end if; end if; + if do_trace = '1' then + v.trace_next := '1'; + end if; + v.e.write_data := result; v.e.write_enable := result_en and not exception;