diff --git a/Makefile b/Makefile index e486a29..a4b8df5 100644 --- 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 \ diff --git a/common.vhdl b/common.vhdl index deba7be..467f2a8 100644 --- a/common.vhdl +++ b/common.vhdl @@ -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 diff --git a/core.vhdl b/core.vhdl index c36f9cf..5d8a822 100644 --- 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 ); diff --git a/execute1.vhdl b/execute1.vhdl index 9ae4b37..5d2fa79 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -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 diff --git a/microwatt.core b/microwatt.core index b01983f..21468de 100644 --- a/microwatt.core +++ b/microwatt.core @@ -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 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; diff --git a/writeback.vhdl b/writeback.vhdl index 516e6ba..b056ee1 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -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;