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 ,
2023-04-08 03:43:28 +00:00
MTIME = 12 'hB01 , // this is a memory-mapped register; no such CSR exists, and access should fault
2021-06-10 13:41:26 +00:00
MHPMCOUNTERHBASE = 12 'hB80 ,
2023-04-08 03:43:28 +00:00
MTIMEH = 12 'hB81 , // this is a memory-mapped register; no such CSR exists, and access should fault
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-03-24 22:32:25 +00:00
input logic clk , reset ,
input logic StallE , StallM ,
input logic FlushM ,
input logic InstrValidNotFlushedM , LoadStallD , StoreStallD ,
input logic CSRMWriteM , CSRWriteM ,
input logic BPDirPredWrongM ,
input logic BTAWrongM ,
input logic RASPredPCWrongM ,
input logic IClassWrongM ,
input logic BPWrongM , // branch predictor is wrong
input logic [ 3 : 0 ] InstrClassM ,
input logic DCacheMiss ,
input logic DCacheAccess ,
input logic ICacheMiss ,
input logic ICacheAccess ,
input logic ICacheStallF ,
input logic DCacheStallM ,
input logic sfencevmaM ,
input logic InterruptM ,
input logic ExceptionM ,
input logic InvalidateICacheM ,
input logic DivBusyE , // integer divide busy
input logic FDivBusyE , // floating point divide busy
input logic [ 11 : 0 ] CSRAdrM ,
input logic [ 1 : 0 ] PrivilegeModeW ,
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-03-24 22:32:25 +00:00
logic [ 4 : 0 ] CounterNumM ;
logic [ `XLEN - 1 : 0 ] HPMCOUNTER_REGW [ `COUNTERS - 1 : 0 ] ;
logic [ `XLEN - 1 : 0 ] HPMCOUNTERH_REGW [ `COUNTERS - 1 : 0 ] ;
logic LoadStallE , LoadStallM ;
logic StoreStallE , StoreStallM ;
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 ] ;
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.
2023-03-24 22:32:25 +00:00
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
2023-03-24 22:32:25 +00:00
assign CounterEvent [ 6 ] = BPWrongM & InstrValidNotFlushedM ; // branch predictor wrong
2023-03-03 05:04:31 +00:00
assign CounterEvent [ 7 ] = BPDirPredWrongM & InstrValidNotFlushedM ; // Branch predictor wrong direction
2023-03-24 22:32:25 +00:00
assign CounterEvent [ 8 ] = BTAWrongM & InstrValidNotFlushedM ; // branch predictor wrong target
2023-03-03 05:04:31 +00:00
assign CounterEvent [ 9 ] = RASPredPCWrongM & InstrValidNotFlushedM ; // return address stack wrong address
2023-03-24 22:32:25 +00:00
assign CounterEvent [ 10 ] = IClassWrongM & InstrValidNotFlushedM ; // instruction class predictor wrong
2023-05-22 15:08:49 +00:00
assign CounterEvent [ 11 ] = LoadStallM ; // Load Stalls. don't want to suppress on flush as this only happens if flushed.
assign CounterEvent [ 12 ] = StoreStallM ; // 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-24 22:32:25 +00:00
assign CounterEvent [ 20 ] = InvalidateICacheM & 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-04-11 06:18:25 +00:00
// coverage off
// DivBusyE will never be assert high since this configuration uses the FPU to do integer division
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-04-11 06:18:25 +00:00
// coverage on
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 */
2023-04-08 03:43:28 +00:00
else if ( CSRAdrM > = MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE + `COUNTERS & CSRAdrM ! = MTIME )
CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE + `COUNTERS )
CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
2023-01-14 05:09:29 +00:00
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 */
2023-04-08 03:43:28 +00:00
else if ( CSRAdrM > = MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE + `COUNTERS & CSRAdrM ! = MTIME )
CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE + `COUNTERS )
CSRCReadValM = HPMCOUNTER_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = MHPMCOUNTERHBASE & CSRAdrM < MHPMCOUNTERHBASE + `COUNTERS & CSRAdrM ! = MTIMEH )
CSRCReadValM = HPMCOUNTERH_REGW [ CounterNumM ] ;
else if ( CSRAdrM > = HPMCOUNTERHBASE & CSRAdrM < HPMCOUNTERHBASE + `COUNTERS )
CSRCReadValM = HPMCOUNTERH_REGW [ CounterNumM ] ;
2023-01-14 05:09:29 +00:00
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