core: Add a basic performance monitor unit (PMU) implementation
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 26 Apr 2021 08:09:48 +0000 (18:09 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Wed, 11 Aug 2021 06:05:47 +0000 (16:05 +1000)
This is the start of an implementation of a PMU according to PowerISA
v3.0B.  Things not implemented yet include most architected events,
the BHRB, event-based branches, thresholding, MMCR0[TBCC] field, etc.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Makefile
common.vhdl
core.vhdl
execute1.vhdl
microwatt.core
pmu.vhdl [new file with mode: 0644]
writeback.vhdl

index f57d33379a05c6e8f8230a3cf2cee597161376ad..ff1a002b9b67bd765c1b6c5387ad2d73306d1949 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@ core_files = decode_types.vhdl common.vhdl wishbone_types.vhdl fetch1.vhdl \
        cr_file.vhdl crhelpers.vhdl ppc_fx_insns.vhdl rotator.vhdl \
        logical.vhdl countzero.vhdl multiply.vhdl divider.vhdl execute1.vhdl \
        loadstore1.vhdl mmu.vhdl dcache.vhdl writeback.vhdl core_debug.vhdl \
-       core.vhdl fpu.vhdl
+       core.vhdl fpu.vhdl pmu.vhdl
 
 soc_files = wishbone_arbiter.vhdl wishbone_bram_wrapper.vhdl sync_fifo.vhdl \
        wishbone_debug_master.vhdl xics.vhdl syscon.vhdl gpio.vhdl soc.vhdl \
index deba7beeb6de5f0c75e8d7ee14bdd9221bf50ecf..467f2a8e8ae51608fcd283c3d520c6d1e9822a0c 100644 (file)
@@ -21,6 +21,7 @@ package common is
     constant MSR_FE1 : integer := (63 - 55);    -- Floating Exception mode
     constant MSR_IR  : integer := (63 - 58);    -- Instruction Relocation
     constant MSR_DR  : integer := (63 - 59);    -- Data Relocation
+    constant MSR_PMM : integer := (63 - 61);    -- Performance Monitor Mark
     constant MSR_RI  : integer := (63 - 62);    -- Recoverable Interrupt
     constant MSR_LE  : integer := (63 - 63);    -- Little Endian
 
@@ -54,6 +55,34 @@ package common is
     constant SPR_PTCR   : spr_num_t := 464;
     constant SPR_PVR   : spr_num_t := 287;
 
+    -- PMU registers
+    constant SPR_UPMC1  : spr_num_t := 771;
+    constant SPR_UPMC2  : spr_num_t := 772;
+    constant SPR_UPMC3  : spr_num_t := 773;
+    constant SPR_UPMC4  : spr_num_t := 774;
+    constant SPR_UPMC5  : spr_num_t := 775;
+    constant SPR_UPMC6  : spr_num_t := 776;
+    constant SPR_UMMCR0 : spr_num_t := 779;
+    constant SPR_UMMCR1 : spr_num_t := 782;
+    constant SPR_UMMCR2 : spr_num_t := 769;
+    constant SPR_UMMCRA : spr_num_t := 770;
+    constant SPR_USIER  : spr_num_t := 768;
+    constant SPR_USIAR  : spr_num_t := 780;
+    constant SPR_USDAR  : spr_num_t := 781;
+    constant SPR_PMC1   : spr_num_t := 787;
+    constant SPR_PMC2   : spr_num_t := 788;
+    constant SPR_PMC3   : spr_num_t := 789;
+    constant SPR_PMC4   : spr_num_t := 790;
+    constant SPR_PMC5   : spr_num_t := 791;
+    constant SPR_PMC6   : spr_num_t := 792;
+    constant SPR_MMCR0  : spr_num_t := 795;
+    constant SPR_MMCR1  : spr_num_t := 798;
+    constant SPR_MMCR2  : spr_num_t := 785;
+    constant SPR_MMCRA  : spr_num_t := 786;
+    constant SPR_SIER   : spr_num_t := 784;
+    constant SPR_SIAR   : spr_num_t := 796;
+    constant SPR_SDAR   : spr_num_t := 797;
+
     -- GPR indices in the register file (GPR only)
     subtype gpr_index_t is std_ulogic_vector(4 downto 0);
 
@@ -303,6 +332,49 @@ package common is
                                                               is_extended => '0', is_modulus => '0',
                                                               neg_result => '0', others => (others => '0'));
 
+    type PMUEventType is record
+        no_instr_avail      : std_ulogic;
+        dispatch            : std_ulogic;
+        ext_interrupt       : std_ulogic;
+        instr_complete      : std_ulogic;
+        fp_complete         : std_ulogic;
+        ld_complete         : std_ulogic;
+        st_complete         : std_ulogic;
+        br_taken_complete   : std_ulogic;
+        br_mispredict       : std_ulogic;
+        ipref_discard       : std_ulogic;
+        itlb_miss           : std_ulogic;
+        itlb_miss_resolved  : std_ulogic;
+        icache_miss         : std_ulogic;
+        dc_miss_resolved    : std_ulogic;
+        dc_ld_miss_resolved : std_ulogic;
+        dc_store_miss       : std_ulogic;
+        dtlb_miss_resolved  : std_ulogic;
+        ld_miss_nocache     : std_ulogic;
+        ld_fill_nocache     : std_ulogic;
+    end record;
+    constant PMUEventInit : PMUEventType := (others => '0');
+
+    type Execute1ToPMUType is record
+        mfspr   : std_ulogic;
+        mtspr   : std_ulogic;
+        spr_num : std_ulogic_vector(4 downto 0);
+        spr_val : std_ulogic_vector(63 downto 0);
+        tbbits  : std_ulogic_vector(3 downto 0);        -- event bits from timebase
+        pmm_msr : std_ulogic;                           -- PMM bit from MSR
+        pr_msr  : std_ulogic;                           -- PR bit from MSR
+        run     : std_ulogic;
+        nia     : std_ulogic_vector(63 downto 0);
+        addr    : std_ulogic_vector(63 downto 0);
+        addr_v  : std_ulogic;
+        occur   : PMUEventType;
+    end record;
+
+    type PMUToExecute1Type is record
+        spr_val : std_ulogic_vector(63 downto 0);
+        intr    : std_ulogic;
+    end record;
+
     type Decode2ToRegisterFileType is record
        read1_enable : std_ulogic;
        read1_reg : gspr_index_t;
@@ -595,6 +667,10 @@ package common is
                                                               write_cr_mask => (others => '0'),
                                                               write_cr_data => (others => '0'));
 
+    type WritebackEventType is record
+        instr_complete      : std_ulogic;
+    end record;
+
 end common;
 
 package body common is
index c36f9cf6919fd2a18de287b1834a94b2f222d16a..5d8a822cb14e5a1ec4fbb3dc4a8e9bcfbcb046b8 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -147,6 +147,9 @@ architecture behave of core is
 
     signal msr : std_ulogic_vector(63 downto 0);
 
+    -- PMU event bus
+    signal writeback_events : WritebackEventType;
+
     -- Debug status
     signal dbg_core_is_stopped: std_ulogic;
 
@@ -352,6 +355,7 @@ begin
             bypass_cr_data => execute1_cr_bypass,
            icache_inval => ex1_icache_inval,
             dbg_msr_out => msr,
+            wb_events => writeback_events,
             terminate_out => terminate,
             log_out => log_data(134 downto 120),
             log_rd_addr => log_rd_addr,
@@ -441,6 +445,7 @@ begin
             w_out => writeback_to_register_file,
             c_out => writeback_to_cr_file,
             f_out => writeback_to_fetch1,
+            events => writeback_events,
             interrupt_out => do_interrupt,
             complete_out => complete
             );
index 9ae4b370a09a9deadd45bf87e4ec8aa0bc100fb2..5d2fa797d5e00737f47b1eb31cf07cd8e5350ec1 100644 (file)
@@ -45,6 +45,9 @@ entity execute1 is
        icache_inval : out std_ulogic;
        terminate_out : out std_ulogic;
 
+        -- PMU event buses
+        wb_events    : in WritebackEventType;
+
         log_out : out std_ulogic_vector(14 downto 0);
         log_rd_addr : out std_ulogic_vector(31 downto 0);
         log_rd_data : in std_ulogic_vector(63 downto 0);
@@ -125,6 +128,10 @@ architecture behaviour of execute1 is
     signal random_cond : std_ulogic_vector(63 downto 0);
     signal random_err  : std_ulogic;
 
+    -- PMU signals
+    signal x_to_pmu : Execute1ToPMUType;
+    signal pmu_to_x : PMUToExecute1Type;
+
     -- signals for logging
     signal exception_log : std_ulogic;
     signal irq_valid_log : std_ulogic;
@@ -279,6 +286,14 @@ begin
             err => random_err
             );
 
+    pmu_0: entity work.pmu
+        port map (
+            clk => clk,
+            rst => rst,
+            p_in => x_to_pmu,
+            p_out => pmu_to_x
+            );
+
     dbg_msr_out <= ctrl.msr;
     log_rd_addr <= r.log_addr_spr;
 
@@ -287,6 +302,14 @@ 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.nia <= current.nia;
+    x_to_pmu.addr <= (others => '0');
+    x_to_pmu.addr_v <= '0';
+    x_to_pmu.spr_num <= e_in.insn(20 downto 16);
+    x_to_pmu.spr_val <= c_in;
+    x_to_pmu.run <= '1';
+
     -- XER forwarding. To avoid having to track XER hazards, we use
     -- the previously latched value.  Since the XER common bits
     -- (SO, OV[32] and CA[32]) are only modified by instructions that are
@@ -693,6 +716,15 @@ begin
         v.cntz_in_progress := '0';
         v.mul_finish := '0';
 
+        x_to_pmu.mfspr <= '0';
+        x_to_pmu.mtspr <= '0';
+        x_to_pmu.tbbits(3) <= ctrl.tb(63 - 47);
+        x_to_pmu.tbbits(2) <= ctrl.tb(63 - 51);
+        x_to_pmu.tbbits(1) <= ctrl.tb(63 - 55);
+        x_to_pmu.tbbits(0) <= ctrl.tb(63 - 63);
+        x_to_pmu.pmm_msr <= ctrl.msr(MSR_PMM);
+        x_to_pmu.pr_msr <= ctrl.msr(MSR_PR);
+
         spr_result <= (others => '0');
         spr_val := (others => '0');
 
@@ -701,7 +733,7 @@ begin
        ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1);
        ctrl_tmp.dec <= std_ulogic_vector(unsigned(ctrl.dec) - 1);
 
-        irq_valid := ctrl.msr(MSR_EE) and (ctrl.dec(63) or ext_irq_in);
+        irq_valid := ctrl.msr(MSR_EE) and (pmu_to_x.intr or ctrl.dec(63) or ext_irq_in);
 
        v.terminate := '0';
        icache_inval <= '0';
@@ -763,7 +795,10 @@ begin
             elsif irq_valid = '1' then
                 -- Don't deliver the interrupt until we have a valid instruction
                 -- coming in, so we have a valid NIA to put in SRR0.
-                if ctrl.dec(63) = '1' then
+                if pmu_to_x.intr = '1' then
+                    v.e.intr_vec := 16#f00#;
+                    report "IRQ valid: PMU";
+                elsif ctrl.dec(63) = '1' then
                     v.e.intr_vec := 16#900#;
                     report "IRQ valid: DEC";
                 elsif ext_irq_in = '1' then
@@ -963,6 +998,12 @@ begin
                     when 725 =>     -- LOG_DATA SPR
                         spr_val := log_rd_data;
                         v.log_addr_spr := std_ulogic_vector(unsigned(r.log_addr_spr) + 1);
+                    when SPR_UPMC1 | SPR_UPMC2 | SPR_UPMC3 | SPR_UPMC4 | SPR_UPMC5 | SPR_UPMC6 |
+                        SPR_UMMCR0 | SPR_UMMCR1 | SPR_UMMCR2 | SPR_UMMCRA | SPR_USIER | SPR_USIAR | SPR_USDAR |
+                        SPR_PMC1 | SPR_PMC2 | SPR_PMC3 | SPR_PMC4 | SPR_PMC5 | SPR_PMC6 |
+                        SPR_MMCR0 | SPR_MMCR1 | SPR_MMCR2 | SPR_MMCRA | SPR_SIER | SPR_SIAR | SPR_SDAR =>
+                        x_to_pmu.mfspr <= '1';
+                        spr_val := pmu_to_x.spr_val;
                     when others =>
                         -- mfspr from unimplemented SPRs should be a nop in
                         -- supervisor mode and a program interrupt for user mode
@@ -1017,6 +1058,11 @@ begin
                        ctrl_tmp.dec <= c_in;
                     when 724 =>     -- LOG_ADDR SPR
                         v.log_addr_spr := c_in(31 downto 0);
+                    when SPR_UPMC1 | SPR_UPMC2 | SPR_UPMC3 | SPR_UPMC4 | SPR_UPMC5 | SPR_UPMC6 |
+                        SPR_UMMCR0 | SPR_UMMCR2 | SPR_UMMCRA |
+                        SPR_PMC1 | SPR_PMC2 | SPR_PMC3 | SPR_PMC4 | SPR_PMC5 | SPR_PMC6 |
+                        SPR_MMCR0 | SPR_MMCR1 | SPR_MMCR2 | SPR_MMCRA | SPR_SIER | SPR_SIAR | SPR_SDAR =>
+                        x_to_pmu.mtspr <= '1';
                    when others =>
                         -- mtspr to unimplemented SPRs should be a nop in
                         -- supervisor mode and a program interrupt for user mode
index 41421c396bc66034df5ddfaba9bf8aa1722db96b..cf890180a931d1b1f75a8d7ec3631f1630409d29 100644 (file)
@@ -27,6 +27,7 @@ filesets:
       - dcache.vhdl
       - divider.vhdl
       - rotator.vhdl
+      - pmu.vhdl
       - writeback.vhdl
       - insn_helpers.vhdl
       - core.vhdl
diff --git a/pmu.vhdl b/pmu.vhdl
new file mode 100644 (file)
index 0000000..ccb33e7
--- /dev/null
+++ b/pmu.vhdl
@@ -0,0 +1,354 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.common.all;
+use work.decode_types.all;
+
+entity pmu is
+    port (
+        clk   : in  std_ulogic;
+        rst   : in  std_ulogic;
+        p_in  : in  Execute1ToPMUType;
+        p_out : out PMUToExecute1Type
+        );
+end entity pmu;
+
+architecture behaviour of pmu is
+
+    -- MMCR0 bit numbers
+    constant MMCR0_FC      : integer := 63 - 32;
+    constant MMCR0_FCS     : integer := 63 - 33;
+    constant MMCR0_FCP     : integer := 63 - 34;
+    constant MMCR0_FCM1    : integer := 63 - 35;
+    constant MMCR0_FCM0    : integer := 63 - 36;
+    constant MMCR0_PMAE    : integer := 63 - 37;
+    constant MMCR0_FCECE   : integer := 63 - 38;
+    constant MMCR0_TBSEL   : integer := 63 - 40;
+    constant MMCR0_TBEE    : integer := 63 - 41;
+    constant MMCR0_BHRBA   : integer := 63 - 42;
+    constant MMCR0_EBE     : integer := 63 - 43;
+    constant MMCR0_PMCC    : integer := 63 - 45;
+    constant MMCR0_PMC1CE  : integer := 63 - 48;
+    constant MMCR0_PMCjCE  : integer := 63 - 49;
+    constant MMCR0_TRIGGER : integer := 63 - 50;
+    constant MMCR0_FCPC    : integer := 63 - 51;
+    constant MMCR0_PMAQ    : integer := 63 - 52;
+    constant MMCR0_PMCCEXT : integer := 63 - 54;
+    constant MMCR0_CC56RUN : integer := 63 - 55;
+    constant MMCR0_PMAO    : integer := 63 - 56;
+    constant MMCR0_FC1_4   : integer := 63 - 58;
+    constant MMCR0_FC5_6   : integer := 63 - 59;
+    constant MMCR0_FC1_4W  : integer := 63 - 62;
+
+    -- MMCR2 bit numbers
+    constant MMCR2_FC0S    : integer := 63 - 0;
+    constant MMCR2_FC0P0   : integer := 63 - 1;
+    constant MMCR2_FC0M1   : integer := 63 - 3;
+    constant MMCR2_FC0M0   : integer := 63 - 4;
+    constant MMCR2_FC0WAIT : integer := 63 - 5;
+    constant MMCR2_FC1S    : integer := 54 - 0;
+    constant MMCR2_FC1P0   : integer := 54 - 1;
+    constant MMCR2_FC1M1   : integer := 54 - 3;
+    constant MMCR2_FC1M0   : integer := 54 - 4;
+    constant MMCR2_FC1WAIT : integer := 54 - 5;
+    constant MMCR2_FC2S    : integer := 45 - 0;
+    constant MMCR2_FC2P0   : integer := 45 - 1;
+    constant MMCR2_FC2M1   : integer := 45 - 3;
+    constant MMCR2_FC2M0   : integer := 45 - 4;
+    constant MMCR2_FC2WAIT : integer := 45 - 5;
+    constant MMCR2_FC3S    : integer := 36 - 0;
+    constant MMCR2_FC3P0   : integer := 36 - 1;
+    constant MMCR2_FC3M1   : integer := 36 - 3;
+    constant MMCR2_FC3M0   : integer := 36 - 4;
+    constant MMCR2_FC3WAIT : integer := 36 - 5;
+    constant MMCR2_FC4S    : integer := 27 - 0;
+    constant MMCR2_FC4P0   : integer := 27 - 1;
+    constant MMCR2_FC4M1   : integer := 27 - 3;
+    constant MMCR2_FC4M0   : integer := 27 - 4;
+    constant MMCR2_FC4WAIT : integer := 27 - 5;
+    constant MMCR2_FC5S    : integer := 18 - 0;
+    constant MMCR2_FC5P0   : integer := 18 - 1;
+    constant MMCR2_FC5M1   : integer := 18 - 3;
+    constant MMCR2_FC5M0   : integer := 18 - 4;
+    constant MMCR2_FC5WAIT : integer := 18 - 5;
+    constant MMCR2_FC6S    : integer :=  9 - 0;
+    constant MMCR2_FC6P0   : integer :=  9 - 1;
+    constant MMCR2_FC6M1   : integer :=  9 - 3;
+    constant MMCR2_FC6M0   : integer :=  9 - 4;
+    constant MMCR2_FC6WAIT : integer :=  9 - 5;
+
+    -- MMCRA bit numbers
+    constant MMCRA_TECX    : integer := 63 - 36;
+    constant MMCRA_TECM    : integer := 63 - 44;
+    constant MMCRA_TECE    : integer := 63 - 47;
+    constant MMCRA_TS      : integer := 63 - 51;
+    constant MMCRA_TE      : integer := 63 - 55;
+    constant MMCRA_ES      : integer := 63 - 59;
+    constant MMCRA_SM      : integer := 63 - 62;
+    constant MMCRA_SE      : integer := 63 - 63;
+
+    -- SIER bit numbers
+    constant SIER_SAMPPR   : integer := 63 - 38;
+    constant SIER_SIARV    : integer := 63 - 41;
+    constant SIER_SDARV    : integer := 63 - 42;
+    constant SIER_TE       : integer := 63 - 43;
+    constant SIER_SITYPE   : integer := 63 - 48;
+    constant SIER_SICACHE  : integer := 63 - 51;
+    constant SIER_SITAKBR  : integer := 63 - 52;
+    constant SIER_SIMISPR  : integer := 63 - 53;
+    constant SIER_SIMISPRI : integer := 63 - 55;
+    constant SIER_SIDERAT  : integer := 63 - 56;
+    constant SIER_SIDAXL   : integer := 63 - 59;
+    constant SIER_SIDSAI   : integer := 63 - 62;
+    constant SIER_SICMPL   : integer := 63 - 63;
+
+    type pmc_array is array(1 to 6) of std_ulogic_vector(31 downto 0);
+    signal pmcs  : pmc_array;
+    signal mmcr0 : std_ulogic_vector(31 downto 0);
+    signal mmcr1 : std_ulogic_vector(63 downto 0);
+    signal mmcr2 : std_ulogic_vector(63 downto 0);
+    signal mmcra : std_ulogic_vector(63 downto 0);
+    signal siar  : std_ulogic_vector(63 downto 0);
+    signal sdar  : std_ulogic_vector(63 downto 0);
+    signal sier  : std_ulogic_vector(63 downto 0);
+
+    signal doinc : std_ulogic_vector(1 to 6);
+    signal doalert : std_ulogic;
+    signal doevent : std_ulogic;
+
+    signal prev_tb : std_ulogic_vector(3 downto 0);
+
+begin
+    -- mfspr mux
+    with p_in.spr_num(3 downto 0) select p_out.spr_val <=
+        32x"0" & pmcs(1) when "0011",
+        32x"0" & pmcs(2) when "0100",
+        32x"0" & pmcs(3) when "0101",
+        32x"0" & pmcs(4) when "0110",
+        32x"0" & pmcs(5) when "0111",
+        32x"0" & pmcs(6) when "1000",
+        32x"0" & mmcr0   when "1011",
+        mmcr1            when "1110",
+        mmcr2            when "0001",
+        mmcra            when "0010",
+        siar             when "1100",
+        sdar             when "1101",
+        sier             when "0000",
+        64x"0"           when others;
+
+    p_out.intr <= mmcr0(MMCR0_PMAO);
+
+    pmu_1: process(clk)
+    begin
+        if rising_edge(clk) then
+            if rst = '1' then
+                mmcr0 <= 32x"80000000";
+            else
+                for i in 1 to 6 loop
+                    if p_in.mtspr = '1' and to_integer(unsigned(p_in.spr_num(3 downto 0))) = i + 2 then
+                        pmcs(i) <= p_in.spr_val(31 downto 0);
+                    elsif doinc(i) = '1' then
+                        pmcs(i) <= std_ulogic_vector(unsigned(pmcs(i)) + 1);
+                    end if;
+                end loop;
+                if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "1011" then
+                    mmcr0 <= p_in.spr_val(31 downto 0);
+                    mmcr0(MMCR0_BHRBA) <= '0';          -- no BHRB yet
+                    mmcr0(MMCR0_EBE) <= '0';            -- no EBBs yet
+                else
+                    if doalert = '1' then
+                        mmcr0(MMCR0_PMAE) <= '0';
+                        mmcr0(MMCR0_PMAO) <= '1';
+                        mmcr0(MMCR0_PMAQ) <= '0';
+                    end if;
+                    if doevent = '1' and mmcr0(MMCR0_FCECE) = '1' and mmcr0(MMCR0_TRIGGER) = '0' then
+                        mmcr0(MMCR0_FC) <= '1';
+                    end if;
+                    if (doevent = '1' or pmcs(1)(31) = '1') and mmcr0(MMCR0_TRIGGER) = '1' then
+                        mmcr0(MMCR0_TRIGGER) <= '0';
+                    end if;
+                end if;
+                if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "1110" then
+                    mmcr1 <= p_in.spr_val;
+                end if;
+                if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "0001" then
+                    mmcr2 <= p_in.spr_val;
+                end if;
+                if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "0010" then
+                    mmcra <= p_in.spr_val;
+                    -- we don't support random sampling yet
+                    mmcra(MMCRA_SE) <= '0';
+                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
+                    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
+                    sdar <= p_in.addr;
+                end if;
+                if p_in.mtspr = '1' and p_in.spr_num(3 downto 0) = "0000" then
+                    sier <= p_in.spr_val;
+                elsif doalert = '1' then
+                    sier <= (others => '0');
+                    sier(SIER_SAMPPR) <= p_in.pr_msr;
+                    sier(SIER_SIARV) <= '1';
+                    sier(SIER_SDARV) <= p_in.addr_v;
+                end if;
+            end if;
+            prev_tb <= p_in.tbbits;
+        end if;
+    end process;
+
+    pmu_2: process(all)
+        variable tbdiff : std_ulogic_vector(3 downto 0);
+        variable tbbit  : std_ulogic;
+        variable freeze : std_ulogic;
+        variable event  : std_ulogic;
+        variable j      : integer;
+        variable inc    : std_ulogic_vector(1 to 6);
+        variable fc14wo : std_ulogic;
+    begin
+        event := '0';
+
+        -- Check for timebase events
+        tbdiff := p_in.tbbits and not prev_tb;
+        tbbit := tbdiff(3 - to_integer(unsigned(mmcr0(MMCR0_TBSEL + 1 downto MMCR0_TBSEL))));
+        if tbbit = '1' and mmcr0(MMCR0_TBEE) = '1' then
+            event := '1';
+        end if;
+
+        -- Check for counter negative events
+        if mmcr0(MMCR0_PMC1CE) = '1' and pmcs(1)(31) = '1' then
+            event := '1';
+        end if;
+        if mmcr0(MMCR0_PMCjCE) = '1' and
+            (pmcs(2)(31) or pmcs(3)(31) or pmcs(4)(31) or pmcs(5)(31) or pmcs(6)(31)) = '1' then
+            event := '1';
+        end if;
+
+        -- Event selection
+        inc := (others => '0');
+        fc14wo := '0';
+        case mmcr1(31 downto 24) is
+            when x"f0" =>
+                inc(1) := '1';
+                fc14wo := '1';          -- override MMCR0[FC1_4WAIT]
+            when x"f2" | x"fe" =>
+                inc(1) := p_in.occur.instr_complete;
+            when x"f4" =>
+                inc(1) := p_in.occur.fp_complete;
+            when x"f6" =>
+                inc(1) := p_in.occur.itlb_miss;
+            when x"f8" =>
+                inc(1) := p_in.occur.no_instr_avail;
+            when x"fa" =>
+                inc(1) := p_in.run;
+            when x"fc" =>
+                inc(1) := p_in.occur.ld_complete;
+            when others =>
+        end case;
+
+        case mmcr1(23 downto 16) is
+            when x"f0" =>
+                inc(2) := p_in.occur.st_complete;
+            when x"f2" =>
+                inc(2) := p_in.occur.dispatch;
+            when x"f4" =>
+                inc(2) := p_in.run;
+            when x"f6" =>
+                inc(2) := p_in.occur.dtlb_miss_resolved;
+            when x"f8" =>
+                inc(2) := p_in.occur.ext_interrupt;
+            when x"fa" =>
+                inc(2) := p_in.occur.br_taken_complete;
+            when x"fc" =>
+                inc(2) := p_in.occur.icache_miss;
+            when x"fe" =>
+                inc(2) := p_in.occur.dc_miss_resolved;
+            when others =>
+        end case;
+
+        case mmcr1(15 downto 8) is
+            when x"f0" =>
+                inc(3) := p_in.occur.dc_store_miss;
+            when x"f2" =>
+                inc(3) := p_in.occur.dispatch;
+            when x"f4" =>
+                inc(3) := p_in.occur.instr_complete and p_in.run;
+            when x"f6" =>
+                inc(3) := p_in.occur.dc_ld_miss_resolved;
+            when x"f8" =>
+                inc(3) := tbbit;
+            when x"fe" =>
+                inc(3) := p_in.occur.ld_fill_nocache;
+            when others =>
+        end case;
+
+        case mmcr1(7 downto 0) is
+            when x"f0" =>
+                inc(4) := p_in.occur.dc_store_miss;
+            when x"f2" =>
+                inc(4) := p_in.occur.dispatch;
+            when x"f4" =>
+                inc(4) := p_in.run;
+            when x"f6" =>
+                inc(4) := p_in.occur.br_mispredict;
+            when x"f8" =>
+                inc(4) := p_in.occur.ipref_discard;
+            when x"fa" =>
+                inc(4) := p_in.occur.instr_complete and p_in.run;
+            when x"fc" =>
+                inc(4) := p_in.occur.itlb_miss_resolved;
+            when x"fe" =>
+                inc(4) := p_in.occur.ld_miss_nocache;
+            when others =>
+        end case;
+
+        if mmcr0(MMCR0_PMCC + 1 downto MMCR0_PMCC) /= "11" then
+            inc(5) := (mmcr0(MMCR0_CC56RUN) or p_in.run) and p_in.occur.instr_complete;
+            inc(6) := mmcr0(MMCR0_CC56RUN) or p_in.run;
+        end if;
+
+        -- Evaluate freeze conditions
+        freeze := mmcr0(MMCR0_FC) or
+                  (mmcr0(MMCR0_FCS) and not p_in.pr_msr) or
+                  (mmcr0(MMCR0_FCP) and not mmcr0(MMCR0_FCPC) and p_in.pr_msr) or
+                  (not mmcr0(MMCR0_FCP) and mmcr0(MMCR0_FCPC) and p_in.pr_msr) or
+                  (mmcr0(MMCR0_FCM1) and p_in.pmm_msr) or
+                  (mmcr0(MMCR0_FCM0) and not p_in.pmm_msr);
+
+        if freeze = '1' or mmcr0(MMCR0_FC1_4) = '1' or
+            (mmcr0(MMCR0_FC1_4W) = '1' and p_in.run = '0' and fc14wo = '0') then
+            inc(1) := '0';
+        end if;
+        if freeze = '1' or mmcr0(MMCR0_FC1_4) = '1' or
+            (mmcr0(MMCR0_FC1_4W) = '1' and p_in.run = '0') then
+            inc(2 to 4) := "000";
+        end if;
+        if freeze = '1' or mmcr0(MMCR0_FC5_6) = '1' then
+            inc(5 to 6) := "00";
+        end if;
+        if mmcr0(MMCR0_TRIGGER) = '1' then
+            inc(2 to 6) := "00000";
+        end if;
+        for i in 1 to 6 loop
+            j := (i - 1) * 9;
+            if (mmcr2(MMCR2_FC0S - j) = '1' and p_in.pr_msr = '0') or
+                (mmcr2(MMCR2_FC0P0 - j) = '1' and p_in.pr_msr = '1') or
+                (mmcr2(MMCR2_FC0M1 - j) = '1' and p_in.pmm_msr = '1') or
+                (mmcr2(MMCR2_FC0M1 - j) = '1' and p_in.pmm_msr = '1') then
+                inc(i) := '0';
+            end if;
+        end loop;
+
+        doinc <= inc;
+        doevent <= event;
+        doalert <= event and mmcr0(MMCR0_PMAE);
+    end process;
+
+end architecture behaviour;
index 516e6bad775322de57b81d6118e1228e329c14fb..b056ee1e319afccab36a9979d664db612b02c4e2 100644 (file)
@@ -19,6 +19,9 @@ entity writeback is
         c_out        : out WritebackToCrFileType;
         f_out        : out WritebackToFetch1Type;
 
+        -- PMU event bus
+        events       : out WritebackEventType;
+
         flush_out    : out std_ulogic;
         interrupt_out: out std_ulogic;
         complete_out : out instr_tag_t
@@ -100,6 +103,7 @@ begin
         elsif fp_in.valid = '1' then
             complete_out <= fp_in.instr_tag;
         end if;
+        events.instr_complete <= complete_out.valid;
 
         intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;