core: Add a basic performance monitor unit (PMU) implementation

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>
pull/315/head
Paul Mackerras 4 years ago
parent f40842d9b2
commit a7873b45f7

@ -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 \ cr_file.vhdl crhelpers.vhdl ppc_fx_insns.vhdl rotator.vhdl \
logical.vhdl countzero.vhdl multiply.vhdl divider.vhdl execute1.vhdl \ logical.vhdl countzero.vhdl multiply.vhdl divider.vhdl execute1.vhdl \
loadstore1.vhdl mmu.vhdl dcache.vhdl writeback.vhdl core_debug.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 \ soc_files = wishbone_arbiter.vhdl wishbone_bram_wrapper.vhdl sync_fifo.vhdl \
wishbone_debug_master.vhdl xics.vhdl syscon.vhdl gpio.vhdl soc.vhdl \ wishbone_debug_master.vhdl xics.vhdl syscon.vhdl gpio.vhdl soc.vhdl \

@ -21,6 +21,7 @@ package common is
constant MSR_FE1 : integer := (63 - 55); -- Floating Exception mode constant MSR_FE1 : integer := (63 - 55); -- Floating Exception mode
constant MSR_IR : integer := (63 - 58); -- Instruction Relocation constant MSR_IR : integer := (63 - 58); -- Instruction Relocation
constant MSR_DR : integer := (63 - 59); -- Data 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_RI : integer := (63 - 62); -- Recoverable Interrupt
constant MSR_LE : integer := (63 - 63); -- Little Endian constant MSR_LE : integer := (63 - 63); -- Little Endian


@ -54,6 +55,34 @@ package common is
constant SPR_PTCR : spr_num_t := 464; constant SPR_PTCR : spr_num_t := 464;
constant SPR_PVR : spr_num_t := 287; 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) -- GPR indices in the register file (GPR only)
subtype gpr_index_t is std_ulogic_vector(4 downto 0); subtype gpr_index_t is std_ulogic_vector(4 downto 0);


@ -303,6 +332,49 @@ package common is
is_extended => '0', is_modulus => '0', is_extended => '0', is_modulus => '0',
neg_result => '0', others => (others => '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 type Decode2ToRegisterFileType is record
read1_enable : std_ulogic; read1_enable : std_ulogic;
read1_reg : gspr_index_t; read1_reg : gspr_index_t;
@ -595,6 +667,10 @@ package common is
write_cr_mask => (others => '0'), write_cr_mask => (others => '0'),
write_cr_data => (others => '0')); write_cr_data => (others => '0'));


type WritebackEventType is record
instr_complete : std_ulogic;
end record;

end common; end common;


package body common is package body common is

@ -147,6 +147,9 @@ architecture behave of core is


signal msr : std_ulogic_vector(63 downto 0); signal msr : std_ulogic_vector(63 downto 0);


-- PMU event bus
signal writeback_events : WritebackEventType;

-- Debug status -- Debug status
signal dbg_core_is_stopped: std_ulogic; signal dbg_core_is_stopped: std_ulogic;


@ -352,6 +355,7 @@ begin
bypass_cr_data => execute1_cr_bypass, bypass_cr_data => execute1_cr_bypass,
icache_inval => ex1_icache_inval, icache_inval => ex1_icache_inval,
dbg_msr_out => msr, dbg_msr_out => msr,
wb_events => writeback_events,
terminate_out => terminate, terminate_out => terminate,
log_out => log_data(134 downto 120), log_out => log_data(134 downto 120),
log_rd_addr => log_rd_addr, log_rd_addr => log_rd_addr,
@ -441,6 +445,7 @@ begin
w_out => writeback_to_register_file, w_out => writeback_to_register_file,
c_out => writeback_to_cr_file, c_out => writeback_to_cr_file,
f_out => writeback_to_fetch1, f_out => writeback_to_fetch1,
events => writeback_events,
interrupt_out => do_interrupt, interrupt_out => do_interrupt,
complete_out => complete complete_out => complete
); );

@ -45,6 +45,9 @@ entity execute1 is
icache_inval : out std_ulogic; icache_inval : out std_ulogic;
terminate_out : 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_out : out std_ulogic_vector(14 downto 0);
log_rd_addr : out std_ulogic_vector(31 downto 0); log_rd_addr : out std_ulogic_vector(31 downto 0);
log_rd_data : in std_ulogic_vector(63 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_cond : std_ulogic_vector(63 downto 0);
signal random_err : std_ulogic; signal random_err : std_ulogic;


-- PMU signals
signal x_to_pmu : Execute1ToPMUType;
signal pmu_to_x : PMUToExecute1Type;

-- signals for logging -- signals for logging
signal exception_log : std_ulogic; signal exception_log : std_ulogic;
signal irq_valid_log : std_ulogic; signal irq_valid_log : std_ulogic;
@ -279,6 +286,14 @@ begin
err => random_err 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; dbg_msr_out <= ctrl.msr;
log_rd_addr <= r.log_addr_spr; log_rd_addr <= r.log_addr_spr;


@ -287,6 +302,14 @@ begin
c_in <= e_in.read_data3; c_in <= e_in.read_data3;
cr_in <= e_in.cr; 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 -- XER forwarding. To avoid having to track XER hazards, we use
-- the previously latched value. Since the XER common bits -- the previously latched value. Since the XER common bits
-- (SO, OV[32] and CA[32]) are only modified by instructions that are -- (SO, OV[32] and CA[32]) are only modified by instructions that are
@ -693,6 +716,15 @@ begin
v.cntz_in_progress := '0'; v.cntz_in_progress := '0';
v.mul_finish := '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_result <= (others => '0');
spr_val := (others => '0'); spr_val := (others => '0');


@ -701,7 +733,7 @@ begin
ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1); ctrl_tmp.tb <= std_ulogic_vector(unsigned(ctrl.tb) + 1);
ctrl_tmp.dec <= std_ulogic_vector(unsigned(ctrl.dec) - 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'; v.terminate := '0';
icache_inval <= '0'; icache_inval <= '0';
@ -763,7 +795,10 @@ begin
elsif irq_valid = '1' then elsif irq_valid = '1' then
-- Don't deliver the interrupt until we have a valid instruction -- Don't deliver the interrupt until we have a valid instruction
-- coming in, so we have a valid NIA to put in SRR0. -- 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#; v.e.intr_vec := 16#900#;
report "IRQ valid: DEC"; report "IRQ valid: DEC";
elsif ext_irq_in = '1' then elsif ext_irq_in = '1' then
@ -963,6 +998,12 @@ begin
when 725 => -- LOG_DATA SPR when 725 => -- LOG_DATA SPR
spr_val := log_rd_data; spr_val := log_rd_data;
v.log_addr_spr := std_ulogic_vector(unsigned(r.log_addr_spr) + 1); 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 => when others =>
-- mfspr from unimplemented SPRs should be a nop in -- mfspr from unimplemented SPRs should be a nop in
-- supervisor mode and a program interrupt for user mode -- supervisor mode and a program interrupt for user mode
@ -1017,6 +1058,11 @@ begin
ctrl_tmp.dec <= c_in; ctrl_tmp.dec <= c_in;
when 724 => -- LOG_ADDR SPR when 724 => -- LOG_ADDR SPR
v.log_addr_spr := c_in(31 downto 0); 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 => when others =>
-- mtspr to unimplemented SPRs should be a nop in -- mtspr to unimplemented SPRs should be a nop in
-- supervisor mode and a program interrupt for user mode -- supervisor mode and a program interrupt for user mode

@ -27,6 +27,7 @@ filesets:
- dcache.vhdl - dcache.vhdl
- divider.vhdl - divider.vhdl
- rotator.vhdl - rotator.vhdl
- pmu.vhdl
- writeback.vhdl - writeback.vhdl
- insn_helpers.vhdl - insn_helpers.vhdl
- core.vhdl - core.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;

@ -19,6 +19,9 @@ entity writeback is
c_out : out WritebackToCrFileType; c_out : out WritebackToCrFileType;
f_out : out WritebackToFetch1Type; f_out : out WritebackToFetch1Type;


-- PMU event bus
events : out WritebackEventType;

flush_out : out std_ulogic; flush_out : out std_ulogic;
interrupt_out: out std_ulogic; interrupt_out: out std_ulogic;
complete_out : out instr_tag_t complete_out : out instr_tag_t
@ -100,6 +103,7 @@ begin
elsif fp_in.valid = '1' then elsif fp_in.valid = '1' then
complete_out <= fp_in.instr_tag; complete_out <= fp_in.instr_tag;
end if; end if;
events.instr_complete <= complete_out.valid;


intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt; intr := e_in.interrupt or l_in.interrupt or fp_in.interrupt;



Loading…
Cancel
Save