URL
https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk
Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc
[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [src_processor/] [mor1kx-5.0/] [rtl/] [verilog/] [mor1kx_pcu.v] - Rev 48
Compare with Previous | Blame | View Log
/* **************************************************************************** This Source Code Form is subject to the terms of the Open Hardware Description License, v. 1.0. If a copy of the OHDL was not distributed with this file, You can obtain one at http://juliusbaxter.net/ohdl/ohdl.txt Description: mor1kx Perfomance Counters Unit Copyright (C) 2016 Authors Author(s): Alexey Baturo <baturo.alexey@gmail.com> ***************************************************************************** */ `include "mor1kx-defines.v" module mor1kx_pcu #( parameter OPTION_PERFCOUNTERS_NUM = 7 ) ( input clk, input rst, // SPR Bus interface input spr_access_i, input spr_we_i, input spr_re_i, input [15:0] spr_addr_i, input [31:0] spr_dat_i, output spr_bus_ack, output [31:0] spr_dat_o, // Current cpu mode: user/supervisor input spr_sys_mode_i, // Events that can occur input pcu_event_load_i, // track load insn input pcu_event_store_i, // track store insn input pcu_event_ifetch_i, // track insn fetch input pcu_event_dcache_miss_i, // track data cache miss input pcu_event_icache_miss_i, // track insn cache miss input pcu_event_ifetch_stall_i, // track SOME stall input pcu_event_lsu_stall_i, // track LSU stall input pcu_event_brn_stall_i, // track brn miss input pcu_event_dtlb_miss_i, // track data tlb miss input pcu_event_itlb_miss_i, // track insn tlb miss input pcu_event_datadep_stall_i // track SOME stall ); // Registers reg [31:0] pcu_pccr[0:OPTION_PERFCOUNTERS_NUM]; reg [31:0] pcu_pcmr[0:OPTION_PERFCOUNTERS_NUM]; wire pcu_pccr_access; wire pcu_pcmr_access; // check if we access pcu // TODO: generate this signals according to present units assign pcu_pccr_access = spr_access_i & ((`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR0_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR1_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR2_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR3_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR4_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR5_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR6_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCCR7_ADDR))); assign pcu_pcmr_access = spr_access_i & ((`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR0_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR1_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR2_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR3_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR4_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR5_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR6_ADDR)) | (`SPR_OFFSET(spr_addr_i) == `SPR_OFFSET(`OR1K_SPR_PCMR7_ADDR))); // put data on data bus assign spr_bus_ack = spr_access_i; assign spr_dat_o = (spr_access_i & pcu_pccr_access & spr_re_i) ? pcu_pccr[spr_addr_i[2:0]] : (spr_access_i & pcu_pcmr_access & spr_re_i & spr_sys_mode_i) ? pcu_pcmr[spr_addr_i[2:0]] : 0; genvar pcu_num; generate for(pcu_num = 0; pcu_num < OPTION_PERFCOUNTERS_NUM + 1; pcu_num = pcu_num + 1) begin: pcu_generate wire [`OR1K_PCMR_DDS:`OR1K_PCMR_LA] pcu_events_active; wire [`OR1K_PCMR_DDS:`OR1K_PCMR_LA] pcu_events_hit; assign pcu_events_active = (pcu_event_load_i << `OR1K_PCMR_LA) | (pcu_event_store_i << `OR1K_PCMR_SA) | (pcu_event_ifetch_i << `OR1K_PCMR_IF) | (pcu_event_dcache_miss_i << `OR1K_PCMR_DCM) | (pcu_event_icache_miss_i << `OR1K_PCMR_ICM) | (pcu_event_ifetch_stall_i << `OR1K_PCMR_IFS) | (pcu_event_lsu_stall_i << `OR1K_PCMR_LSUS) | (pcu_event_brn_stall_i << `OR1K_PCMR_BS) | (pcu_event_dtlb_miss_i << `OR1K_PCMR_DTLBM) | (pcu_event_itlb_miss_i << `OR1K_PCMR_ITLBM) | (pcu_event_datadep_stall_i << `OR1K_PCMR_DDS); assign pcu_events_hit = pcu_events_active & pcu_pcmr[pcu_num]; always @(posedge clk `OR_ASYNC_RST) begin if (rst) begin pcu_pccr[pcu_num] <= 32'd0; pcu_pcmr[pcu_num] <= 32'd0 | 1 << `OR1K_PCMR_CP; // we could write pcu registers only in system mode end else if (spr_we_i && spr_sys_mode_i) begin if (pcu_pccr_access & (spr_addr_i[2:0] == pcu_num)) pcu_pccr[pcu_num] <= spr_dat_i; // WPE are not implemented, hence we do not update WPE part if (pcu_pcmr_access && (spr_addr_i[2:0] == pcu_num)) begin pcu_pcmr[pcu_num][`OR1K_PCMR_DDS:`OR1K_PCMR_CISM] <= spr_dat_i[`OR1K_PCMR_DDS:`OR1K_PCMR_CISM]; end end else if (((pcu_pcmr[pcu_num][`OR1K_PCMR_CISM] & spr_sys_mode_i) | (pcu_pcmr[pcu_num][`OR1K_PCMR_CIUM] & ~spr_sys_mode_i))) begin pcu_pccr[pcu_num] <= pcu_pccr[pcu_num] + pcu_events_hit[`OR1K_PCMR_LA] + pcu_events_hit[`OR1K_PCMR_SA] + pcu_events_hit[`OR1K_PCMR_IF] + pcu_events_hit[`OR1K_PCMR_DCM] + pcu_events_hit[`OR1K_PCMR_ICM] + pcu_events_hit[`OR1K_PCMR_IFS] + pcu_events_hit[`OR1K_PCMR_LSUS] + pcu_events_hit[`OR1K_PCMR_BS] + pcu_events_hit[`OR1K_PCMR_DTLBM] + pcu_events_hit[`OR1K_PCMR_ITLBM] + pcu_events_hit[`OR1K_PCMR_DDS]; end end end endgenerate endmodule // mor1kx_pcu