PMU: Add several more events
authorPaul Mackerras <paulus@ozlabs.org>
Fri, 13 Aug 2021 09:29:48 +0000 (19:29 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Sat, 14 Aug 2021 07:35:55 +0000 (17:35 +1000)
This implements most of the architected PMU events.  The ones missing
are mostly the ones that depend on which level of the cache hierarchy
data is fetched from.  The events implemented here, and their raw
event codes, are:

    Floating-point operation completed (100f4)
    Load completed (100fc)
    Store completed (200f0)
    Icache miss (200fc)
    ITLB miss (100f6)
    ITLB miss resolved (400fc)
    Dcache load miss (400f0)
    Dcache load miss resolved (300f8)
    Dcache store miss (300f0)
    DTLB miss (300fc)
    DTLB miss resolved (200f6)
    No instruction available and none being executed (100f8)
    Instruction dispatched (200f2, 300f2, 400f2)
    Taken branch instruction completed (200fa)
    Branch mispredicted (400f6)
    External interrupt taken (200f8)

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
common.vhdl
core.vhdl
dcache.vhdl
execute1.vhdl
icache.vhdl
loadstore1.vhdl
pmu.vhdl
writeback.vhdl

index 467f2a8e8ae51608fcd283c3d520c6d1e9822a0c..a6562e071570d34677d670c0e2ab0b4a3f8117b8 100644 (file)
@@ -209,6 +209,11 @@ package common is
         next_predicted: std_ulogic;
     end record;
 
+    type IcacheEventType is record
+        icache_miss : std_ulogic;
+        itlb_miss_resolved : std_ulogic;
+    end record;
+
     type Decode1ToDecode2Type is record
        valid: std_ulogic;
        stop_mark : std_ulogic;
@@ -347,8 +352,10 @@ package common is
         itlb_miss_resolved  : std_ulogic;
         icache_miss         : std_ulogic;
         dc_miss_resolved    : std_ulogic;
+        dc_load_miss        : std_ulogic;
         dc_ld_miss_resolved : std_ulogic;
         dc_store_miss       : std_ulogic;
+        dtlb_miss           : std_ulogic;
         dtlb_miss_resolved  : std_ulogic;
         ld_miss_nocache     : std_ulogic;
         ld_fill_nocache     : std_ulogic;
@@ -468,6 +475,14 @@ package common is
         cache_paradox : std_ulogic;
     end record;
 
+    type DcacheEventType is record
+        load_miss          : std_ulogic;
+        store_miss         : std_ulogic;
+        dcache_refill      : std_ulogic;
+        dtlb_miss          : std_ulogic;
+        dtlb_miss_resolved : std_ulogic;
+    end record;
+
     type Loadstore1ToMmuType is record
         valid : std_ulogic;
         tlbie : std_ulogic;
@@ -537,6 +552,12 @@ package common is
          interrupt => '0', intr_vec => 0,
          srr0 => (others => '0'), srr1 => (others => '0'));
 
+    type Loadstore1EventType is record
+        load_complete  : std_ulogic;
+        store_complete : std_ulogic;
+        itlb_miss      : std_ulogic;
+    end record;
+
     type Execute1ToWritebackType is record
        valid: std_ulogic;
         instr_tag : instr_tag_t;
@@ -668,7 +689,8 @@ package common is
                                                               write_cr_data => (others => '0'));
 
     type WritebackEventType is record
-        instr_complete      : std_ulogic;
+        instr_complete : std_ulogic;
+        fp_complete    : std_ulogic;
     end record;
 
 end common;
index 5d8a822cb14e5a1ec4fbb3dc4a8e9bcfbcb046b8..32bfe8843bcf0289bab349b34be6b513351f62b5 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -148,6 +148,9 @@ architecture behave of core is
     signal msr : std_ulogic_vector(63 downto 0);
 
     -- PMU event bus
+    signal icache_events    : IcacheEventType;
+    signal loadstore_events : Loadstore1EventType;
+    signal dcache_events    : DcacheEventType;
     signal writeback_events : WritebackEventType;
 
     -- Debug status
@@ -247,6 +250,7 @@ begin
             wishbone_out => wishbone_insn_out,
             wishbone_in => wishbone_insn_in,
             wb_snoop_in => wb_snoop_in,
+            events => icache_events,
             log_out => log_data(96 downto 43)
             );
 
@@ -356,6 +360,9 @@ begin
            icache_inval => ex1_icache_inval,
             dbg_msr_out => msr,
             wb_events => writeback_events,
+            ls_events => loadstore_events,
+            dc_events => dcache_events,
+            ic_events => icache_events,
             terminate_out => terminate,
             log_out => log_data(134 downto 120),
             log_rd_addr => log_rd_addr,
@@ -397,6 +404,7 @@ begin
             m_out => loadstore1_to_mmu,
             m_in => mmu_to_loadstore1,
             dc_stall => dcache_stall_out,
+            events => loadstore_events,
             log_out => log_data(149 downto 140)
             );
 
@@ -431,6 +439,7 @@ begin
             wishbone_in => wishbone_data_in,
             wishbone_out => wishbone_data_out,
             snoop_in => wb_snoop_in,
+            events => dcache_events,
             log_out => log_data(170 downto 151)
             );
 
index 50060b2e464eeaf9f4b291d970a869de3988c038..90771f501a559a7e1591c9bd3d80c4b49d319404 100644 (file)
@@ -46,6 +46,8 @@ entity dcache is
         wishbone_out : out wishbone_master_out;
         wishbone_in  : in wishbone_slave_out;
 
+        events       : out DcacheEventType;
+
         log_out      : out std_ulogic_vector(19 downto 0)
         );
 end entity dcache;
@@ -355,6 +357,8 @@ architecture rtl of dcache is
 
     signal r1 : reg_stage_1_t;
 
+    signal ev : DcacheEventType;
+
     -- Reservation information
     --
     type reservation_t is record
@@ -412,6 +416,7 @@ architecture rtl of dcache is
     signal rc_ok : std_ulogic;
     signal perm_ok : std_ulogic;
     signal access_ok : std_ulogic;
+    signal tlb_miss : std_ulogic;
 
     -- TLB PLRU output interface
     type tlb_plru_out_t is array(tlb_index_t) of std_ulogic_vector(TLB_WAY_BITS-1 downto 0);
@@ -605,6 +610,8 @@ begin
     r0_valid <= r0_full and not r1.full and not d_in.hold;
     stall_out <= r0_stall;
 
+    events <= ev;
+
     -- TLB
     -- Operates in the second cycle on the request latched in r0.req.
     -- TLB updates write the entry at the end of the second cycle.
@@ -689,6 +696,7 @@ begin
             pte <= (others => '0');
         end if;
         valid_ra <= tlb_hit or not r0.req.virt_mode;
+        tlb_miss <= r0_valid and r0.req.virt_mode and not tlb_hit;
         if r0.req.virt_mode = '1' then
             ra <= pte(REAL_ADDR_BITS - 1 downto TLB_LG_PGSZ) &
                   r0.req.addr(TLB_LG_PGSZ - 1 downto ROW_OFF_BITS) &
@@ -712,6 +720,7 @@ begin
         if rising_edge(clk) then
             tlbie := r0_valid and r0.tlbie;
             tlbwe := r0_valid and r0.tlbld;
+            ev.dtlb_miss_resolved <= tlbwe;
             if rst = '1' or (tlbie = '1' and r0.doall = '1') then
                 -- clear all valid bits at once
                 for i in tlb_index_t loop
@@ -1286,6 +1295,11 @@ begin
                 r1.forward_valid1 <= '0';
             end if;
 
+            ev.dcache_refill <= '0';
+            ev.load_miss <= '0';
+            ev.store_miss <= '0';
+            ev.dtlb_miss <= tlb_miss;
+
            -- On reset, clear all valid bits to force misses
             if rst = '1' then
                for i in index_t loop
@@ -1417,6 +1431,7 @@ begin
                        -- Track that we had one request sent
                        r1.state <= RELOAD_WAIT_ACK;
                         r1.write_tag <= '1';
+                        ev.load_miss <= '1';
 
                    when OP_LOAD_NC =>
                         r1.wb.cyc <= '1';
@@ -1449,6 +1464,9 @@ begin
                         r1.wb.we <= '1';
                         r1.wb.cyc <= '1';
                         r1.wb.stb <= '1';
+                        if req.op = OP_STORE_MISS then
+                            ev.store_miss <= '1';
+                        end if;
 
                    -- OP_NONE and OP_BAD do nothing
                     -- OP_BAD & OP_STCX_FAIL were handled above already
@@ -1500,6 +1518,7 @@ begin
                            -- Cache line is now valid
                            cache_valids(r1.store_index)(r1.store_way) <= '1';
 
+                            ev.dcache_refill <= not r1.dcbz;
                             r1.state <= IDLE;
                        end if;
 
index 5d2fa797d5e00737f47b1eb31cf07cd8e5350ec1..3f217570f3dabd1a6ac70ae475ff1691d818a313 100644 (file)
@@ -47,6 +47,9 @@ entity execute1 is
 
         -- PMU event buses
         wb_events    : in WritebackEventType;
+        ls_events    : in Loadstore1EventType;
+        dc_events    : in DcacheEventType;
+        ic_events    : in IcacheEventType;
 
         log_out : out std_ulogic_vector(14 downto 0);
         log_rd_addr : out std_ulogic_vector(31 downto 0);
@@ -70,6 +73,11 @@ architecture behaviour of execute1 is
         mul_finish : std_ulogic;
         div_in_progress : std_ulogic;
         cntz_in_progress : std_ulogic;
+        no_instr_avail : std_ulogic;
+        instr_dispatch : std_ulogic;
+        ext_interrupt : std_ulogic;
+        taken_branch_event : std_ulogic;
+        br_mispredict : std_ulogic;
         log_addr_spr : std_ulogic_vector(31 downto 0);
     end record;
     constant reg_type_init : reg_type :=
@@ -78,6 +86,8 @@ architecture behaviour of execute1 is
          busy => '0', terminate => '0', intr_pending => '0',
          fp_exception_next => '0', trace_next => '0', prev_op => OP_ILLEGAL, br_taken => '0',
          mul_in_progress => '0', mul_finish => '0', div_in_progress => '0', cntz_in_progress => '0',
+         no_instr_avail => '0', instr_dispatch => '0', ext_interrupt => '0',
+         taken_branch_event => '0', br_mispredict => '0',
          others => (others => '0'));
 
     signal r, rin : reg_type;
@@ -302,7 +312,24 @@ begin
     c_in <= e_in.read_data3;
     cr_in <= e_in.cr;
 
-    x_to_pmu.occur <= (instr_complete => wb_events.instr_complete, others => '0');
+    x_to_pmu.occur <= (instr_complete => wb_events.instr_complete,
+                       fp_complete => wb_events.fp_complete,
+                       ld_complete => ls_events.load_complete,
+                       st_complete => ls_events.store_complete,
+                       itlb_miss => ls_events.itlb_miss,
+                       dc_load_miss => dc_events.load_miss,
+                       dc_ld_miss_resolved => dc_events.dcache_refill,
+                       dc_store_miss => dc_events.store_miss,
+                       dtlb_miss => dc_events.dtlb_miss,
+                       dtlb_miss_resolved => dc_events.dtlb_miss_resolved,
+                       icache_miss => ic_events.icache_miss,
+                       itlb_miss_resolved => ic_events.itlb_miss_resolved,
+                       no_instr_avail => r.no_instr_avail,
+                       dispatch => r.instr_dispatch,
+                       ext_interrupt => r.ext_interrupt,
+                       br_taken_complete => r.taken_branch_event,
+                       br_mispredict => r.br_mispredict,
+                       others => '0');
     x_to_pmu.nia <= current.nia;
     x_to_pmu.addr <= (others => '0');
     x_to_pmu.addr_v <= '0';
@@ -715,6 +742,9 @@ begin
         v.div_in_progress := '0';
         v.cntz_in_progress := '0';
         v.mul_finish := '0';
+        v.ext_interrupt := '0';
+        v.taken_branch_event := '0';
+        v.br_mispredict := '0';
 
         x_to_pmu.mfspr <= '0';
         x_to_pmu.mtspr <= '0';
@@ -804,6 +834,7 @@ begin
                 elsif ext_irq_in = '1' then
                     v.e.intr_vec := 16#500#;
                     report "IRQ valid: External";
+                    v.ext_interrupt := '1';
                 end if;
                 exception := '1';
 
@@ -836,6 +867,9 @@ begin
             v.intr_pending := '0';
         end if;
 
+        v.no_instr_avail := not (e_in.valid or l_in.busy or l_in.in_progress or r.busy or fp_in.busy);
+        v.instr_dispatch := valid_in and not exception and not illegal;
+
        if valid_in = '1' and exception = '0' and illegal = '0' and e_in.unit = ALU then
            v.e.valid := '1';
 
@@ -905,6 +939,7 @@ begin
                 if ctrl.msr(MSR_BE) = '1' then
                     do_trace := '1';
                 end if;
+                v.taken_branch_event := '1';
             when OP_BC | OP_BCREG =>
                 -- read_data1 is CTR
                -- for OP_BCREG, read_data2 is target register (CTR, LR or TAR)
@@ -920,6 +955,7 @@ begin
                     taken_branch := r.br_taken;
                 end if;
                 v.br_taken := taken_branch;
+                v.taken_branch_event := taken_branch;
                 abs_branch := e_in.br_abs;
                 if e_in.repeat = '0' or e_in.second = '1' then
                     is_branch := '1';
@@ -1114,6 +1150,7 @@ begin
                 end if;
                 if taken_branch /= e_in.br_pred then
                     v.e.redirect := '1';
+                    v.br_mispredict := is_direct_branch;
                 end if;
                 v.e.br_last := is_direct_branch;
                 v.e.br_taken := taken_branch;
index 4d3b12e4ee22a2d73f9a56b52b1167ecc372facb..57d343768825929e6f6efb155dc8902c2c8a9379 100644 (file)
@@ -70,6 +70,7 @@ entity icache is
 
         wb_snoop_in  : in wishbone_master_out := wishbone_master_out_init;
 
+        events       : out IcacheEventType;
         log_out      : out std_ulogic_vector(53 downto 0)
         );
 end entity icache;
@@ -197,6 +198,8 @@ architecture rtl of icache is
 
     signal r : reg_internal_t;
 
+    signal ev : IcacheEventType;
+
     -- Async signals on incoming request
     signal req_index   : index_t;
     signal req_row     : row_t;
@@ -494,6 +497,7 @@ begin
                 itlb_ptes(wr_index) <= m_in.pte;
                 itlb_valids(wr_index) <= '1';
             end if;
+            ev.itlb_miss_resolved <= m_in.tlbld and not rst;
         end if;
     end process;
 
@@ -627,6 +631,7 @@ begin
         variable snoop_cache_tags : cache_tags_set_t;
     begin
         if rising_edge(clk) then
+            ev.icache_miss <= '0';
            -- On reset, clear all valid bits to force misses
             if rst = '1' then
                for i in index_t loop
@@ -699,6 +704,7 @@ begin
                            " way:" & integer'image(replace_way) &
                            " tag:" & to_hstring(req_tag) &
                             " RA:" & to_hstring(real_addr);
+                        ev.icache_miss <= '1';
 
                        -- Keep track of our index and way for subsequent stores
                        r.store_index <= req_index;
index 243b99df49910aea49b679e8c5b663b3340fb50a..21ed836afd833c38821c3e1cbd572d95a78781fc 100644 (file)
@@ -33,6 +33,8 @@ entity loadstore1 is
 
         dc_stall  : in std_ulogic;
 
+        events  : out Loadstore1EventType;
+
         log_out : out std_ulogic_vector(9 downto 0)
         );
 end loadstore1;
@@ -146,6 +148,7 @@ architecture behave of loadstore1 is
         intr_vec     : integer range 0 to 16#fff#;
         nia          : std_ulogic_vector(63 downto 0);
         srr1         : std_ulogic_vector(15 downto 0);
+        events       : Loadstore1EventType;
     end record;
 
     signal req_in   : request_t;
@@ -668,6 +671,7 @@ begin
         do_update := '0';
         v.convert_lfs := '0';
         v.srr1 := (others => '0');
+        v.events := (others => '0');
 
         -- load data formatting
         -- shift and byte-reverse data bytes
@@ -796,6 +800,7 @@ begin
                     mmu_mtspr := r2.req.write_spr;
                     if r2.req.instr_fault = '1' then
                         v.state := MMU_LOOKUP;
+                        v.events.itlb_miss := '1';
                     else
                         v.state := TLBIE_WAIT;
                     end if;
@@ -838,6 +843,9 @@ begin
             v.state := IDLE;
         end if;
 
+        v.events.load_complete := r2.req.load and complete;
+        v.events.store_complete := (r2.req.store or r2.req.dcbz) and complete;
+
         -- generate DSI or DSegI for load/store exceptions
         -- or ISI or ISegI for instruction fetch exceptions
         v.interrupt := exception;
@@ -946,6 +954,8 @@ begin
         e_out.in_progress <= in_progress;
         e_out.interrupt <= r3.interrupt;
 
+        events <= r3.events;
+
         -- Busy calculation.
         stage3_busy_next <= r2.req.valid and not (complete or part_done or exception);
 
index cf5e7f51c6f4a2dfdf50db4ea6f4f8e04d85f540..2967f4efe8234e534cf3880d47aad679d4585551 100644 (file)
--- a/pmu.vhdl
+++ b/pmu.vhdl
@@ -290,13 +290,13 @@ begin
             when x"f8" =>
                 inc(3) := tbbit;
             when x"fe" =>
-                inc(3) := p_in.occur.ld_fill_nocache;
+                inc(3) := p_in.occur.dtlb_miss;
             when others =>
         end case;
 
         case mmcr1(7 downto 0) is
             when x"f0" =>
-                inc(4) := p_in.occur.dc_store_miss;
+                inc(4) := p_in.occur.dc_load_miss;
             when x"f2" =>
                 inc(4) := p_in.occur.dispatch;
             when x"f4" =>
index b056ee1e319afccab36a9979d664db612b02c4e2..a99d4d2338b6fdbf7fc7897fbf8f7a0275b70dc3 100644 (file)
@@ -104,6 +104,7 @@ begin
             complete_out <= fp_in.instr_tag;
         end if;
         events.instr_complete <= complete_out.valid;
+        events.fp_complete <= fp_in.valid;
 
         intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;