Configurable number of performance counters

This commit is contained in:
David Harris 2021-06-10 09:41:26 -04:00
parent 75870a16d7
commit 3e8026dc21
2 changed files with 295 additions and 4 deletions

View File

@ -35,7 +35,7 @@
// MISA RISC-V configuration per specification // MISA RISC-V configuration per specification
`define MISA (32'h00000104 | 0 << 5 | 0 << 3 | 1 << 18 | 1 << 20 | 1 << 12 | 1 << 0) `define MISA (32'h00000104 | 0 << 5 | 0 << 3 | 1 << 18 | 1 << 20 | 1 << 12 | 1 << 0)
`define ZCSR_SUPPORTED 1 `define ZCSR_SUPPORTED 1
31 `define COUNTERS 32
`define ZCOUNTERS_SUPPORTED 1 `define ZCOUNTERS_SUPPORTED 1
// Microarchitectural Features // Microarchitectural Features

View File

@ -1,3 +1,285 @@
///////////////////////////////////////////
// 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
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
`include "wally-config.vh"
module csrc #(parameter
MCYCLE = 12'hB00,
// MTIME = 12'hB01, // address not specified in privileged spec. Consider moving to CLINT to match SiFive
// MTIMECMP = 12'hB21, // not specified in privileged spec. Move to CLINT
MINSTRET = 12'hB02,
MHPMCOUNTERBASE = 12'hB00,
//MHPMCOUNTER3 = 12'hB03,
//MHPMCOUNTER4 = 12'hB04,
// ... more counters
//MHPMCOUNTER31 = 12'hB1F,
MCYCLEH = 12'hB80,
// MTIMEH = 12'hB81, // address not specified in privileged spec. Consider moving to CLINT to match SiFive
// MTIMECMPH = 12'hBA1, // not specified in privileged spec. Move to CLINT
MINSTRETH = 12'hB82,
MHPMCOUNTERHBASE = 12'hB80,
//MHPMCOUNTER3H = 12'hB83,
//MHPMCOUNTER4H = 12'hB84,
// ... more counters
//MHPMCOUNTER31H = 12'hB9F,
MCOUNTERINHIBIT = 12'h320,
MHPMEVENTBASE = 12'h320,
//MHPMEVENT3 = 12'h323,
//MHPMEVENT4 = 12'h324,
// ... more counters
//MHPMEVENT31 = 12'h33F,
CYCLE = 12'hC00,
// TIME = 12'hC01, // not specified
INSTRET = 12'hC02,
HPMCOUNTERBASE = 12'hC00,
//HPMCOUNTER3 = 12'hC03,
//HPMCOUNTER4 = 12'hC04,
// ...more counters
//HPMCOUNTER31 = 12'hC1F,
CYCLEH = 12'hC80,
// TIMEH = 12'hC81, // not specified
INSTRETH = 12'hC82,
HPMCOUNTERHBASE = 12'hC80
//HPMCOUNTER3H = 12'hC83,
//HPMCOUNTER4H = 12'hC84,
// ... more counters
//HPMCOUNTER31H = 12'hC9F
) (
input logic clk, reset,
input logic InstrValidW, LoadStallD, CSRMWriteM,
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,
output logic [`XLEN-1:0] CSRCReadValM,
output logic IllegalCSRCAccessM
);
generate
if (`ZCOUNTERS_SUPPORTED) begin
// logic [63:0] TIME_REGW, TIMECMP_REGW;
logic [63:0] CYCLE_REGW, INSTRET_REGW;
logic [63:0] HPMCOUNTER3_REGW, HPMCOUNTER4_REGW; // add more performance counters here if desired
logic [63:0] CYCLEPlusM, INSTRETPlusM;
logic [63:0] HPMCOUNTER3PlusM, HPMCOUNTER4PlusM;
// logic [`XLEN-1:0] NextTIMEM;
logic [`XLEN-1:0] NextCYCLEM, NextINSTRETM;
logic [`XLEN-1:0] NextHPMCOUNTER3M, NextHPMCOUNTER4M;
logic WriteCYCLEM, WriteINSTRETM;
logic WriteHPMCOUNTER3M, WriteHPMCOUNTER4M;
logic [4:0] CounterNumM;
logic [`COUNTERS-1:3][`XLEN-1:0] HPMCOUNTER_REGW, HPMCOUNTERH_REGW;
//logic [`COUNTERS-1:3][`XLEN-1:0] HPMCOUNTERH_REGW;
// Write enables
// assign WriteTIMEM = CSRMWriteM && (CSRAdrM == MTIME);
// assign WriteTIMECMPM = CSRMWriteM && (CSRAdrM == MTIMECMP);
assign WriteCYCLEM = CSRMWriteM && (CSRAdrM == MCYCLE);
assign WriteINSTRETM = CSRMWriteM && (CSRAdrM == MINSTRET);
//assign WriteHPMCOUNTER3M = CSRMWriteM && (CSRAdrM == MHPMCOUNTER3);
//assign WriteHPMCOUNTER4M = CSRMWriteM && (CSRAdrM == MHPMCOUNTER4);
// Counter adders with inhibits for power savings
assign CYCLEPlusM = CYCLE_REGW + {63'b0, ~MCOUNTINHIBIT_REGW[0]};
// assign TIMEPlusM = TIME_REGW + 1; // can't be inhibited
assign INSTRETPlusM = INSTRET_REGW + {63'b0, InstrValidW & ~MCOUNTINHIBIT_REGW[2]};
//assign HPMCOUNTER3PlusM = HPMCOUNTER3_REGW + {63'b0, LoadStallD & ~MCOUNTINHIBIT_REGW[3]}; // count load stalls
///assign HPMCOUNTER4PlusM = HPMCOUNTER4_REGW + {63'b0, 1'b0 & ~MCOUNTINHIBIT_REGW[4]}; // change to count signals
assign NextCYCLEM = WriteCYCLEM ? CSRWriteValM : CYCLEPlusM[`XLEN-1:0];
// assign NextTIMEM = WriteTIMEM ? CSRWriteValM : TIMEPlusM[`XLEN-1:0];
assign NextINSTRETM = WriteINSTRETM ? CSRWriteValM : INSTRETPlusM[`XLEN-1:0];
//assign NextHPMCOUNTER3M = WriteHPMCOUNTER3M ? CSRWriteValM : HPMCOUNTER3PlusM[`XLEN-1:0];
//assign NextHPMCOUNTER4M = WriteHPMCOUNTER4M ? CSRWriteValM : HPMCOUNTER4PlusM[`XLEN-1:0];
// parameterized number of additional counters
if (`COUNTERS > 3) begin
logic [`COUNTERS-1:3] WriteHPMCOUNTERM, CounterEvent;
logic [63:0] /*HPMCOUNTER_REGW[`COUNTERS-1:3], */ HPMCOUNTERPlusM[`COUNTERS-1:3];
logic [`XLEN-1:0] NextHPMCOUNTERM[`COUNTERS-1:3];
genvar i;
assign CounterEvent[3] = LoadStallD;
assign CounterEvent[`COUNTERS-1:4] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
for (i = 3; i < `COUNTERS; i = i+1) begin
assign WriteHPMCOUNTERM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERBASE + i);
assign NextHPMCOUNTERM[i][`XLEN-1:0] = WriteHPMCOUNTERM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][`XLEN-1:0];
always @(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];
//flopr #(`XLEN) HPMCOUNTERreg[i](clk, reset, NextHPMCOUNTERM[i], HPMCOUNTER_REGW[i]);
if (`XLEN==32) begin
logic [`COUNTERS-1:3] WriteHPMCOUNTERHM;
logic [`XLEN-1:0] NextHPMCOUNTERHM[`COUNTERS-1:3];
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 @(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];
//flopr #(`XLEN) HPMCOUNTERHreg[i](clk, reset, NextHPMCOUNTERHM[i], HPMCOUNTER_REGW[i][63:32]);
end else begin
assign HPMCOUNTERPlusM[i] = HPMCOUNTER_REGW[i] + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]};
end
end
end
// Write / update counters
// Only the Machine mode versions of the counter CSRs are writable
if (`XLEN==64) begin// 64-bit counters
// flopr #(64) TIMEreg(clk, reset, WriteTIMEM ? CSRWriteValM : TIME_REGW + 1, TIME_REGW); // may count off a different clock***
// flopenr #(64) TIMECMPreg(clk, reset, WriteTIMECMPM, CSRWriteValM, TIMECMP_REGW);
flopr #(64) CYCLEreg(clk, reset, NextCYCLEM, CYCLE_REGW);
flopr #(64) INSTRETreg(clk, reset, NextINSTRETM, INSTRET_REGW);
//flopr #(64) HPMCOUNTER3reg(clk, reset, NextHPMCOUNTER3M, HPMCOUNTER3_REGW);
//flopr #(64) HPMCOUNTER4reg(clk, reset, NextHPMCOUNTER4M, HPMCOUNTER4_REGW);
end else begin // 32-bit low and high counters
logic WriteTIMEHM, WriteTIMECMPHM, WriteCYCLEHM, WriteINSTRETHM;
//logic WriteHPMCOUNTER3HM, WriteHPMCOUNTER4HM;
logic [`XLEN-1:0] NextCYCLEHM, NextTIMEHM, NextINSTRETHM;
//logic [`XLEN-1:0] NextHPMCOUNTER3HM, NextHPMCOUNTER4HM;
// Write Enables
// assign WriteTIMEHM = CSRMWriteM && (CSRAdrM == MTIMEH);
// assign WriteTIMECMPHM = CSRMWriteM && (CSRAdrM == MTIMECMPH);
assign WriteCYCLEHM = CSRMWriteM && (CSRAdrM == MCYCLEH);
assign WriteINSTRETHM = CSRMWriteM && (CSRAdrM == MINSTRETH);
//assign WriteHPMCOUNTER3HM = CSRMWriteM && (CSRAdrM == MHPMCOUNTER3H);
//assign WriteHPMCOUNTER4HM = CSRMWriteM && (CSRAdrM == MHPMCOUNTER4H);
assign NextCYCLEHM = WriteCYCLEM ? CSRWriteValM : CYCLEPlusM[63:32];
// assign NextTIMEHM = WriteTIMEHM ? CSRWriteValM : TIMEPlusM[63:32];
assign NextINSTRETHM = WriteINSTRETHM ? CSRWriteValM : INSTRETPlusM[63:32];
//assign NextHPMCOUNTER3HM = WriteHPMCOUNTER3HM ? CSRWriteValM : HPMCOUNTER3PlusM[63:32];
//assign NextHPMCOUNTER4HM = WriteHPMCOUNTER4HM ? CSRWriteValM : HPMCOUNTER4PlusM[63:32];
// Counter CSRs
// flopr #(32) TIMEreg(clk, reset, NextTIMEM, TIME_REGW); // may count off a different clock***
// flopenr #(32) TIMECMPreg(clk, reset, WriteTIMECMPM, CSRWriteValM, TIMECMP_REGW[31:0]);
flopr #(32) CYCLEreg(clk, reset, NextCYCLEM, CYCLE_REGW[31:0]);
flopr #(32) INSTRETreg(clk, reset, NextINSTRETM, INSTRET_REGW[31:0]);
//flopr #(32) HPMCOUNTER3reg(clk, reset, NextHPMCOUNTER3M, HPMCOUNTER3_REGW[31:0]);
//flopr #(32) HPMCOUNTER4reg(clk, reset, NextHPMCOUNTER4M, HPMCOUNTER4_REGW[31:0]);
// flopr #(32) TIMEHreg(clk, reset, NextTIMEHM, TIME_REGW); // may count off a different clock***
// flopenr #(32) TIMECMPHreg(clk, reset, WriteTIMECMPHM, CSRWriteValM, TIMECMP_REGW[63:32]);
flopr #(32) CYCLEHreg(clk, reset, NextCYCLEHM, CYCLE_REGW[63:32]);
flopr #(32) INSTRETHreg(clk, reset, NextINSTRETHM, INSTRET_REGW[63:32]);
//flopr #(32) HPMCOUNTER3Hreg(clk, reset, NextHPMCOUNTER3HM, HPMCOUNTER3_REGW[63:32]);
//flopr #(32) HPMCOUNTER4Hreg(clk, reset, NextHPMCOUNTER4HM, HPMCOUNTER4_REGW[63:32]);
end
// eventually move TIME and TIMECMP to the CLINT
// run TIME off asynchronous reference clock
// synchronize write enable to TIME
// four phase handshake to synchronize reads from TIME
// interrupt on timer compare
// ability to disable optional CSRs
// Read Counters, or cause excepiton if insufficient privilege in light of COUNTEREN flags
assign CounterNumM = CSRAdrM[4:0]; // which counter to read?
if (`XLEN==64) // 64-bit counter reads
always_comb
if (PrivilegeModeW == `M_MODE ||
MCOUNTEREN_REGW[CounterNumM] && (PrivilegeModeW == `S_MODE || SCOUNTEREN_REGW[CounterNumM])) begin
IllegalCSRCAccessM = 0;
if (CSRAdrM >= MHPMCOUNTERBASE+3 && CSRAdrM < MHPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CSRAdrM-MHPMCOUNTERBASE];
else if (CSRAdrM >= HPMCOUNTERBASE+3 && CSRAdrM < HPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CSRAdrM-HPMCOUNTERBASE];
else case (CSRAdrM)
// MTIME: CSRCReadValM = TIME_REGW;
// MTIMECMP: CSRCReadValM = TIMECMP_REGW;
MCYCLE: CSRCReadValM = CYCLE_REGW;
MINSTRET: CSRCReadValM = INSTRET_REGW;
//MHPMCOUNTER3: CSRCReadValM = HPMCOUNTER3_REGW;
//MHPMCOUNTER4: CSRCReadValM = HPMCOUNTER4_REGW;
// TIME: CSRCReadValM = TIME_REGW;
CYCLE: CSRCReadValM = CYCLE_REGW;
INSTRET: CSRCReadValM = INSTRET_REGW;
//HPMCOUNTER3: CSRCReadValM = HPMCOUNTER3_REGW;
//HPMCOUNTER4: CSRCReadValM = HPMCOUNTER4_REGW;
default: begin
CSRCReadValM = 0;
IllegalCSRCAccessM = 1;
end
endcase
end else begin
IllegalCSRCAccessM = 1; // no privileges for this csr
CSRCReadValM = 0;
end
else // 32-bit counter reads
always_comb
if (PrivilegeModeW == `M_MODE || MCOUNTEREN_REGW[CounterNumM] && (PrivilegeModeW == `S_MODE || SCOUNTEREN_REGW[CounterNumM])) begin
IllegalCSRCAccessM = 0;
if (CSRAdrM >= MHPMCOUNTERBASE+3 && CSRAdrM < MHPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CSRAdrM-MHPMCOUNTERBASE];
else if (CSRAdrM >= HPMCOUNTERBASE+3 && CSRAdrM < HPMCOUNTERBASE+`COUNTERS) CSRCReadValM = HPMCOUNTER_REGW[CSRAdrM-HPMCOUNTERBASE];
else if (CSRAdrM >= MHPMCOUNTERHBASE+3 && CSRAdrM < MHPMCOUNTERHBASE+`COUNTERS) CSRCReadValM = HPMCOUNTERH_REGW[CSRAdrM-MHPMCOUNTERHBASE];
else if (CSRAdrM >= HPMCOUNTERHBASE+3 && CSRAdrM < HPMCOUNTERHBASE+`COUNTERS) CSRCReadValM = HPMCOUNTERH_REGW[CSRAdrM-HPMCOUNTERHBASE];
else case (CSRAdrM)
// MTIME: CSRCReadValM = TIME_REGW[31:0];
// MTIMECMP: CSRCReadValM = TIMECMP_REGW[31:0];
MCYCLE: CSRCReadValM = CYCLE_REGW[31:0];
MINSTRET: CSRCReadValM = INSTRET_REGW[31:0];
//MHPMCOUNTER3: CSRCReadValM = HPMCOUNTER3_REGW[31:0];
//MHPMCOUNTER4: CSRCReadValM = HPMCOUNTER4_REGW[31:0];
// TIME: CSRCReadValM = TIME_REGW[31:0];
CYCLE: CSRCReadValM = CYCLE_REGW[31:0];
INSTRET: CSRCReadValM = INSTRET_REGW[31:0];
//HPMCOUNTER3: CSRCReadValM = HPMCOUNTER3_REGW[31:0];
//HPMCOUNTER4: CSRCReadValM = HPMCOUNTER4_REGW[31:0];
// MTIMEH: CSRCReadValM = TIME_REGW[63:32];
// MTIMECMPH: CSRCReadValM = TIMECMP_REGW[63:32];
MCYCLEH: CSRCReadValM = CYCLE_REGW[63:32];
MINSTRETH: CSRCReadValM = INSTRET_REGW[63:32];
//MHPMCOUNTER3H: CSRCReadValM = HPMCOUNTER3_REGW[63:32];
//MHPMCOUNTER4H: CSRCReadValM = HPMCOUNTER4_REGW[63:32];
// TIMEH: CSRCReadValM = TIME_REGW[63:32];
CYCLEH: CSRCReadValM = CYCLE_REGW[63:32];
INSTRETH: CSRCReadValM = INSTRET_REGW[63:32];
//HPMCOUNTER3H: CSRCReadValM = HPMCOUNTER3_REGW[63:32];
//HPMCOUNTER4H: CSRCReadValM = HPMCOUNTER4_REGW[63:32];
default: begin
CSRCReadValM = 0;
IllegalCSRCAccessM = 1;
end
endcase
end else begin
IllegalCSRCAccessM = 1; // no privileges for this csr
CSRCReadValM = 0;
end
end else begin
assign CSRCReadValM = 0;
assign IllegalCSRCAccessM = 1;
end
endgenerate
endmodule
/* Bad code from class
/////////////////////////////////////////// ///////////////////////////////////////////
// csrc.sv // csrc.sv
// //
@ -29,8 +311,14 @@
`include "wally-config.vh" `include "wally-config.vh"
module csrc ( module csrc #(parameter
input logic clk, reset, // counters
MHPMCOUNTERBASE = 12'hB00,
MHPMCOUNTERHBASE = 12'hB80,
MPHMEVENTBASE = 12'h320,
HPMCOUNTERBASE = 12'hC00,
HPMCOUNTERHBASE = 12'hC80,
)(input logic clk, reset,
input logic StallD, StallE, StallM, StallW, input logic StallD, StallE, StallM, StallW,
input logic InstrValidW, LoadStallD, CSRMWriteM, input logic InstrValidW, LoadStallD, CSRMWriteM,
input logic BPPredDirWrongM, input logic BPPredDirWrongM,
@ -45,6 +333,9 @@ module csrc (
output logic [`XLEN-1:0] CSRCReadValM, output logic [`XLEN-1:0] CSRCReadValM,
output logic IllegalCSRCAccessM); output logic IllegalCSRCAccessM);
// counters
// create Counter arrays to store address of each counter // create Counter arrays to store address of each counter
integer MHPMCOUNTER [`COUNTERS:0]; integer MHPMCOUNTER [`COUNTERS:0];
integer MHPMCOUNTERH [`COUNTERS:0]; integer MHPMCOUNTERH [`COUNTERS:0];
@ -199,4 +490,4 @@ module csrc (
end // end for else end // end for else
endgenerate endgenerate
endmodule endmodule
*/