2021-06-10 13:41:26 +00:00
///////////////////////////////////////////
// csrc.sv
//
// Written: David_Harris@hmc.edu 9 January 2021
// Modified:
//
// Purpose: Counter CSRs
// See RISC-V Privileged Mode Specification 20190608 3.1.10-11
//
2023-01-14 03:44:38 +00:00
// Documentation: RISC-V System on Chip Design Chapter 5
2023-01-14 05:25:55 +00:00
// MHPMEVENT is not supported
2023-01-14 03:44:38 +00:00
//
2023-01-11 23:15:08 +00:00
// A component of the CORE-V-WALLY configurable RISC-V project.
2021-06-10 13:41:26 +00:00
//
2023-01-10 19:35:20 +00:00
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
2021-06-10 13:41:26 +00:00
//
2023-01-10 19:35:20 +00:00
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
2021-06-10 13:41:26 +00:00
//
2023-01-10 19:35:20 +00:00
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
2021-06-10 13:41:26 +00:00
//
2023-01-10 19:35:20 +00:00
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work distributed under the
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
2022-01-07 12:58:40 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////
2021-06-10 13:41:26 +00:00
`include " wally-config.vh "
module csrc # ( parameter
MHPMCOUNTERBASE = 12 'hB00 ,
MHPMCOUNTERHBASE = 12 'hB80 ,
2022-01-02 21:18:16 +00:00
MHPMEVENTBASE = 12 'h320 ,
2021-06-10 13:41:26 +00:00
HPMCOUNTERBASE = 12 'hC00 ,
2021-12-31 06:40:21 +00:00
HPMCOUNTERHBASE = 12 'hC80 ,
TIME = 12 'hC01 ,
TIMEH = 12 'hC81
2021-06-10 13:41:26 +00:00
) (
2023-01-14 05:09:29 +00:00
input logic clk , reset ,
input logic StallE , StallM ,
input logic FlushM ,
2023-03-03 05:21:29 +00:00
input logic InstrValidNotFlushedM , LoadStallD , StoreStallD ,
input logic CSRMWriteM , CSRWriteM ,
2023-02-25 01:51:47 +00:00
input logic BPDirPredWrongM ,
2023-01-14 05:09:29 +00:00
input logic BTBPredPCWrongM ,
input logic RASPredPCWrongM ,
2023-02-28 23:48:58 +00:00
input logic IClassWrongM ,
2023-02-28 21:37:25 +00:00
input logic BPWrongM , // branch predictor is wrong
2023-01-14 05:09:29 +00:00
input logic [ 3 : 0 ] InstrClassM ,
input logic DCacheMiss ,
input logic DCacheAccess ,
input logic ICacheMiss ,
input logic ICacheAccess ,
2023-03-03 05:54:56 +00:00
input logic ICacheStallF ,
input logic DCacheStallM ,
2023-03-03 05:21:29 +00:00
input logic sfencevmaM ,
input logic InterruptM ,
input logic ExceptionM ,
2023-03-03 05:29:20 +00:00
input logic FenceM ,
2023-03-03 05:59:52 +00:00
input logic DivBusyE , // integer divide busy
input logic FDivBusyE , // floating point divide busy
2023-01-14 05:09:29 +00:00
input logic [ 11 : 0 ] CSRAdrM ,
2023-03-03 05:10:54 +00:00
input logic [ 1 : 0 ] PrivilegeModeW ,
2023-01-14 05:09:29 +00:00
input logic [ `XLEN - 1 : 0 ] CSRWriteValM ,
input logic [ 31 : 0 ] MCOUNTINHIBIT_REGW , MCOUNTEREN_REGW , SCOUNTEREN_REGW ,
input logic [ 63 : 0 ] MTIME_CLINT ,
output logic [ `XLEN - 1 : 0 ] CSRCReadValM ,
output logic IllegalCSRCAccessM
2023-01-14 04:49:34 +00:00
) ;
2021-06-10 13:41:26 +00:00
2023-01-14 05:25:55 +00:00
logic [ 4 : 0 ] CounterNumM ;
2023-01-21 00:47:36 +00:00
logic [ `XLEN - 1 : 0 ] HPMCOUNTER_REGW [ `COUNTERS - 1 : 0 ] ;
2023-01-14 05:25:55 +00:00
logic [ `XLEN - 1 : 0 ] HPMCOUNTERH_REGW [ `COUNTERS - 1 : 0 ] ;
logic LoadStallE , LoadStallM ;
2023-03-03 05:10:54 +00:00
logic StoreStallE , StoreStallM ;
2023-01-14 05:25:55 +00:00
logic [ `COUNTERS - 1 : 0 ] WriteHPMCOUNTERM ;
logic [ `COUNTERS - 1 : 0 ] CounterEvent ;
logic [ 63 : 0 ] HPMCOUNTERPlusM [ `COUNTERS - 1 : 0 ] ;
logic [ `XLEN - 1 : 0 ] NextHPMCOUNTERM [ `COUNTERS - 1 : 0 ] ;
2023-01-14 05:09:29 +00:00
genvar i ;
2021-08-23 17:24:03 +00:00
2023-01-14 05:09:29 +00:00
// Interface signals
2023-03-03 05:10:54 +00:00
flopenrc # ( 2 ) LoadStallEReg ( . clk , . reset , . clear ( 1 'b0 ) , . en ( ~ StallE ) , . d ( { StoreStallD , LoadStallD } ) , . q ( { StoreStallE , LoadStallE } ) ) ; // don't flush the load stall during a load stall.
flopenrc # ( 2 ) LoadStallMReg ( . clk , . reset , . clear ( FlushM ) , . en ( ~ StallM ) , . d ( { StoreStallE , LoadStallE } ) , . q ( { StoreStallM , LoadStallM } ) ) ;
2023-01-14 05:09:29 +00:00
// Determine when to increment each counter
2023-01-14 05:25:55 +00:00
assign CounterEvent [ 0 ] = 1 'b1 ; // MCYCLE always increments
assign CounterEvent [ 1 ] = 1 'b0 ; // Counter 1 doesn't exist
assign CounterEvent [ 2 ] = InstrValidNotFlushedM ; // MINSTRET instructions retired
2023-01-14 05:09:29 +00:00
if ( `QEMU ) begin : cevent // No other performance counters in QEMU
assign CounterEvent [ `COUNTERS - 1 : 3 ] = 0 ;
2023-01-14 05:25:55 +00:00
end else begin : cevent // User-defined counters
2023-03-03 05:04:31 +00:00
assign CounterEvent [ 3 ] = InstrClassM [ 0 ] & InstrValidNotFlushedM ; // branch instruction
assign CounterEvent [ 4 ] = InstrClassM [ 1 ] & ~ InstrClassM [ 2 ] & InstrValidNotFlushedM ; // jump and not return instructions
assign CounterEvent [ 5 ] = InstrClassM [ 2 ] & InstrValidNotFlushedM ; // return instructions
assign CounterEvent [ 6 ] = BPWrongM & InstrValidNotFlushedM ; // branch predictor wrong
assign CounterEvent [ 7 ] = BPDirPredWrongM & InstrValidNotFlushedM ; // Branch predictor wrong direction
assign CounterEvent [ 8 ] = BTBPredPCWrongM & InstrValidNotFlushedM ; // branch predictor wrong target
assign CounterEvent [ 9 ] = RASPredPCWrongM & InstrValidNotFlushedM ; // return address stack wrong address
2023-02-28 23:48:58 +00:00
assign CounterEvent [ 10 ] = IClassWrongM & InstrValidNotFlushedM ; // instruction class predictor wrong
2023-03-03 05:10:54 +00:00
assign CounterEvent [ 11 ] = LoadStallM & InstrValidNotFlushedM ; // Load Stalls. don't want to suppress on flush as this only happens if flushed.
assign CounterEvent [ 12 ] = StoreStallM & InstrValidNotFlushedM ; // Store Stall
2023-03-03 05:04:31 +00:00
assign CounterEvent [ 13 ] = DCacheAccess & InstrValidNotFlushedM ; // data cache access
assign CounterEvent [ 14 ] = DCacheMiss ; // data cache miss. Miss asserted 1 cycle at start of cache miss
2023-03-03 05:54:56 +00:00
assign CounterEvent [ 15 ] = DCacheStallM ; // d cache miss cycles
2023-03-03 05:04:31 +00:00
assign CounterEvent [ 16 ] = ICacheAccess & InstrValidNotFlushedM ; // instruction cache access
assign CounterEvent [ 17 ] = ICacheMiss ; // instruction cache miss. Miss asserted 1 cycle at start of cache miss
2023-03-03 05:54:56 +00:00
assign CounterEvent [ 18 ] = ICacheStallF ; // i cache miss cycles
2023-03-03 05:21:29 +00:00
assign CounterEvent [ 19 ] = CSRWriteM & InstrValidNotFlushedM ; // CSR writes
2023-03-03 05:29:20 +00:00
assign CounterEvent [ 20 ] = FenceM & InstrValidNotFlushedM ; // fence.i
2023-03-03 05:21:29 +00:00
assign CounterEvent [ 21 ] = sfencevmaM & InstrValidNotFlushedM ; // sfence.vma
assign CounterEvent [ 22 ] = InterruptM ; // interrupt, InstrValidNotFlushedM will be low
assign CounterEvent [ 23 ] = ExceptionM ; // exceptions, InstrValidNotFlushedM will be low
2023-03-03 05:59:52 +00:00
assign CounterEvent [ 24 ] = DivBusyE | FDivBusyE ; // division cycles *** RT: might need to be delay until the next cycle
2023-03-03 05:04:31 +00:00
assign CounterEvent [ `COUNTERS - 1 : 25 ] = 0 ; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
2023-01-14 05:09:29 +00:00
end
// Counter update and write logic
for ( i = 0 ; i < `COUNTERS ; i = i + 1 ) begin : cntr
assign WriteHPMCOUNTERM [ i ] = CSRMWriteM & ( CSRAdrM = = MHPMCOUNTERBASE + i ) ;
assign NextHPMCOUNTERM [ i ] [ `XLEN - 1 : 0 ] = WriteHPMCOUNTERM [ i ] ? CSRWriteValM : HPMCOUNTERPlusM [ i ] [ `XLEN - 1 : 0 ] ;
always_ff @ ( posedge clk ) //, posedge reset) // ModelSim doesn't like syntax of passing array element to flop
if ( reset ) HPMCOUNTER_REGW [ i ] [ `XLEN - 1 : 0 ] < = # 1 0 ;
else HPMCOUNTER_REGW [ i ] [ `XLEN - 1 : 0 ] < = # 1 NextHPMCOUNTERM [ i ] ;
2021-06-10 13:41:26 +00:00
2023-01-14 05:09:29 +00:00
if ( `XLEN = = 32 ) begin // write high and low separately
logic [ `COUNTERS - 1 : 0 ] WriteHPMCOUNTERHM ;
logic [ `XLEN - 1 : 0 ] NextHPMCOUNTERHM [ `COUNTERS - 1 : 0 ] ;
assign HPMCOUNTERPlusM [ i ] = { HPMCOUNTERH_REGW [ i ] , HPMCOUNTER_REGW [ i ] } + { 63 'b0 , CounterEvent [ i ] & ~ MCOUNTINHIBIT_REGW [ i ] } ;
assign WriteHPMCOUNTERHM [ i ] = CSRMWriteM & ( CSRAdrM = = MHPMCOUNTERHBASE + i ) ;
assign NextHPMCOUNTERHM [ i ] = WriteHPMCOUNTERHM [ i ] ? CSRWriteValM : HPMCOUNTERPlusM [ i ] [ 63 : 32 ] ;
always_ff @ ( posedge clk ) //, posedge reset) // ModelSim doesn't like syntax of passing array element to flop
if ( reset ) HPMCOUNTERH_REGW [ i ] [ `XLEN - 1 : 0 ] < = # 1 0 ;
else HPMCOUNTERH_REGW [ i ] [ `XLEN - 1 : 0 ] < = # 1 NextHPMCOUNTERHM [ i ] ;
end else begin // XLEN=64; write entire register
assign HPMCOUNTERPlusM [ i ] = HPMCOUNTER_REGW [ i ] + { 63 'b0 , CounterEvent [ i ] & ~ MCOUNTINHIBIT_REGW [ i ] } ;
end
end
2021-06-10 13:41:26 +00:00
2023-01-14 05:09:29 +00:00
// Read Counters, or cause excepiton if insufficient privilege in light of COUNTEREN flags
assign CounterNumM = CSRAdrM [ 4 : 0 ] ; // which counter to read?
always_comb
if ( PrivilegeModeW = = `M_MODE |
MCOUNTEREN_REGW [ CounterNumM ] & ( ! `S_SUPPORTED | PrivilegeModeW = = `S_MODE | SCOUNTEREN_REGW [ CounterNumM ] ) ) begin
IllegalCSRCAccessM = 0 ;
if ( `XLEN = = 64 ) begin // 64-bit counter reads
// Veri lator doesn't realize this only occurs for XLEN=64
/* verilator lint_off WIDTH */
if ( CSRAdrM = = TIME ) CSRCReadValM = MTIME_CLINT ; // TIME register is a shadow of the memory-mapped MTIME from the CLINT
/* verilator lint_on WIDTH */
else if ( CSRAdrM > = MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE + `COUNTERS ) CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE + `COUNTERS ) CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
else begin
2022-01-05 14:35:25 +00:00
CSRCReadValM = 0 ;
2023-01-14 05:09:29 +00:00
IllegalCSRCAccessM = 1 ; // requested CSR doesn't exist
2021-12-30 23:39:59 +00:00
end
2023-01-14 05:09:29 +00:00
end else begin // 32-bit counter reads
// Veri lator doesn't realize this only occurs for XLEN=32
/* verilator lint_off WIDTH */
if ( CSRAdrM = = TIME ) CSRCReadValM = MTIME_CLINT [ 31 : 0 ] ; // TIME register is a shadow of the memory-mapped MTIME from the CLINT
else if ( CSRAdrM = = TIMEH ) CSRCReadValM = MTIME_CLINT [ 63 : 32 ] ;
/* verilator lint_on WIDTH */
else if ( CSRAdrM > = MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE + `COUNTERS ) CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE + `COUNTERS ) CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = MHPMCOUNTERHBASE & CSRAdrM < MHPMCOUNTERHBASE + `COUNTERS ) CSRCReadValM = HPMCOUNTERH_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = HPMCOUNTERHBASE & CSRAdrM < HPMCOUNTERHBASE + `COUNTERS ) CSRCReadValM = HPMCOUNTERH_REGW [ CounterNumM ] ;
else begin
CSRCReadValM = 0 ;
IllegalCSRCAccessM = 1 ; // requested CSR doesn't exist
end
2022-01-05 14:35:25 +00:00
end
2023-01-14 05:09:29 +00:00
end else begin
CSRCReadValM = 0 ;
IllegalCSRCAccessM = 1 ; // no privileges for this csr
end
2021-06-10 13:41:26 +00:00
endmodule
2022-01-02 21:18:16 +00:00
// mounteren should only exist if u-mode exists