diff --git a/CHANGELOG.md b/CHANGELOG.md index 5af490e70..fd87b0313 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed +- Fix privilege bug in performance counters. The counters have always been accessible in user mode. - Re-work interrupt and debug subsystem to associate requests during decode. This improves stability on for non-idempotent loads. - Fix RISC-V PK simulation bug caused due to insufficient time to init the `a0` and `a1` registers via the bootrom - Fix bug in wt_axi_adapter (only appeared when dcache lines were wider than icache lines) diff --git a/include/riscv_pkg.sv b/include/riscv_pkg.sv index 4fbbee14c..031e572a2 100644 --- a/include/riscv_pkg.sv +++ b/include/riscv_pkg.sv @@ -354,26 +354,55 @@ package riscv; CSR_MHARTID = 12'hF14, CSR_MCYCLE = 12'hB00, CSR_MINSTRET = 12'hB02, + // Performance counters (Machine Mode) + CSR_ML1_ICACHE_MISS = 12'hB03, // L1 Instr Cache Miss + CSR_ML1_DCACHE_MISS = 12'hB04, // L1 Data Cache Miss + CSR_MITLB_MISS = 12'hB05, // ITLB Miss + CSR_MDTLB_MISS = 12'hB06, // DTLB Miss + CSR_MLOAD = 12'hB07, // Loads + CSR_MSTORE = 12'hB08, // Stores + CSR_MEXCEPTION = 12'hB09, // Taken exceptions + CSR_MEXCEPTION_RET = 12'hB0A, // Exception return + CSR_MBRANCH_JUMP = 12'hB0B, // Software change of PC + CSR_MCALL = 12'hB0C, // Procedure call + CSR_MRET = 12'hB0D, // Procedure Return + CSR_MMIS_PREDICT = 12'hB0E, // Branch mis-predicted + CSR_MSB_FULL = 12'hB0F, // Scoreboard full + CSR_MIF_EMPTY = 12'hB10, // instruction fetch queue empty + CSR_MHPM_COUNTER_17 = 12'hB11, // reserved + CSR_MHPM_COUNTER_18 = 12'hB12, // reserved + CSR_MHPM_COUNTER_19 = 12'hB13, // reserved + CSR_MHPM_COUNTER_20 = 12'hB14, // reserved + CSR_MHPM_COUNTER_21 = 12'hB15, // reserved + CSR_MHPM_COUNTER_22 = 12'hB16, // reserved + CSR_MHPM_COUNTER_23 = 12'hB17, // reserved + CSR_MHPM_COUNTER_24 = 12'hB18, // reserved + CSR_MHPM_COUNTER_25 = 12'hB19, // reserved + CSR_MHPM_COUNTER_26 = 12'hB1A, // reserved + CSR_MHPM_COUNTER_27 = 12'hB1B, // reserved + CSR_MHPM_COUNTER_28 = 12'hB1C, // reserved + CSR_MHPM_COUNTER_29 = 12'hB1D, // reserved + CSR_MHPM_COUNTER_30 = 12'hB1E, // reserved + CSR_MHPM_COUNTER_31 = 12'hB1F, // reserved + // Cache Control (platform specifc) CSR_DCACHE = 12'h701, CSR_ICACHE = 12'h700, - + // Triggers CSR_TSELECT = 12'h7A0, CSR_TDATA1 = 12'h7A1, CSR_TDATA2 = 12'h7A2, CSR_TDATA3 = 12'h7A3, CSR_TINFO = 12'h7A4, - // Debug CSR CSR_DCSR = 12'h7b0, CSR_DPC = 12'h7b1, CSR_DSCRATCH0 = 12'h7b2, // optional CSR_DSCRATCH1 = 12'h7b3, // optional - - // Counters and Timers + // Counters and Timers (User Mode - R/O Shadows) CSR_CYCLE = 12'hC00, CSR_TIME = 12'hC01, CSR_INSTRET = 12'hC02, - // Performance counters + // Performance counters (User Mode - R/O Shadows) CSR_L1_ICACHE_MISS = 12'hC03, // L1 Instr Cache Miss CSR_L1_DCACHE_MISS = 12'hC04, // L1 Data Cache Miss CSR_ITLB_MISS = 12'hC05, // ITLB Miss @@ -387,7 +416,22 @@ package riscv; CSR_RET = 12'hC0D, // Procedure Return CSR_MIS_PREDICT = 12'hC0E, // Branch mis-predicted CSR_SB_FULL = 12'hC0F, // Scoreboard full - CSR_IF_EMPTY = 12'hC10 // instruction fetch queue empty + CSR_IF_EMPTY = 12'hC10, // instruction fetch queue empty + CSR_HPM_COUNTER_17 = 12'hC11, // reserved + CSR_HPM_COUNTER_18 = 12'hC12, // reserved + CSR_HPM_COUNTER_19 = 12'hC13, // reserved + CSR_HPM_COUNTER_20 = 12'hC14, // reserved + CSR_HPM_COUNTER_21 = 12'hC15, // reserved + CSR_HPM_COUNTER_22 = 12'hC16, // reserved + CSR_HPM_COUNTER_23 = 12'hC17, // reserved + CSR_HPM_COUNTER_24 = 12'hC18, // reserved + CSR_HPM_COUNTER_25 = 12'hC19, // reserved + CSR_HPM_COUNTER_26 = 12'hC1A, // reserved + CSR_HPM_COUNTER_27 = 12'hC1B, // reserved + CSR_HPM_COUNTER_28 = 12'hC1C, // reserved + CSR_HPM_COUNTER_29 = 12'hC1D, // reserved + CSR_HPM_COUNTER_30 = 12'hC1E, // reserved + CSR_HPM_COUNTER_31 = 12'hC1F // reserved } csr_reg_t; localparam logic [63:0] SSTATUS_UIE = 64'h00000001; diff --git a/src/csr_regfile.sv b/src/csr_regfile.sv index 101cecf30..bbf3e143b 100644 --- a/src/csr_regfile.sv +++ b/src/csr_regfile.sv @@ -234,26 +234,39 @@ module csr_regfile #( riscv::CSR_MHARTID: csr_rdata = hart_id_i; riscv::CSR_MCYCLE: csr_rdata = cycle_q; riscv::CSR_MINSTRET: csr_rdata = instret_q; + // Counters and Timers + riscv::CSR_ML1_ICACHE_MISS, + riscv::CSR_ML1_DCACHE_MISS, + riscv::CSR_MITLB_MISS, + riscv::CSR_MDTLB_MISS, + riscv::CSR_MLOAD, + riscv::CSR_MSTORE, + riscv::CSR_MEXCEPTION, + riscv::CSR_MEXCEPTION_RET, + riscv::CSR_MBRANCH_JUMP, + riscv::CSR_MCALL, + riscv::CSR_MRET, + riscv::CSR_MMIS_PREDICT, + riscv::CSR_MSB_FULL, + riscv::CSR_MIF_EMPTY, + riscv::CSR_MHPM_COUNTER_17, + riscv::CSR_MHPM_COUNTER_18, + riscv::CSR_MHPM_COUNTER_19, + riscv::CSR_MHPM_COUNTER_20, + riscv::CSR_MHPM_COUNTER_21, + riscv::CSR_MHPM_COUNTER_22, + riscv::CSR_MHPM_COUNTER_23, + riscv::CSR_MHPM_COUNTER_24, + riscv::CSR_MHPM_COUNTER_25, + riscv::CSR_MHPM_COUNTER_26, + riscv::CSR_MHPM_COUNTER_27, + riscv::CSR_MHPM_COUNTER_28, + riscv::CSR_MHPM_COUNTER_29, + riscv::CSR_MHPM_COUNTER_30, + riscv::CSR_MHPM_COUNTER_31: csr_rdata = perf_data_i; // custom (non RISC-V) cache control riscv::CSR_DCACHE: csr_rdata = dcache_q; riscv::CSR_ICACHE: csr_rdata = icache_q; - // Counters and Timers - riscv::CSR_CYCLE: csr_rdata = cycle_q; - riscv::CSR_INSTRET: csr_rdata = instret_q; - riscv::CSR_L1_ICACHE_MISS, - riscv::CSR_L1_DCACHE_MISS, - riscv::CSR_ITLB_MISS, - riscv::CSR_DTLB_MISS, - riscv::CSR_LOAD, - riscv::CSR_STORE, - riscv::CSR_EXCEPTION, - riscv::CSR_EXCEPTION_RET, - riscv::CSR_BRANCH_JUMP, - riscv::CSR_CALL, - riscv::CSR_RET, - riscv::CSR_MIS_PREDICT, - riscv::CSR_SB_FULL, - riscv::CSR_IF_EMPTY: csr_rdata = perf_data_i; default: read_access_exception = 1'b1; endcase end @@ -508,23 +521,41 @@ module csr_regfile #( // performance counters riscv::CSR_MCYCLE: cycle_d = csr_wdata; riscv::CSR_MINSTRET: instret = csr_wdata; - riscv::CSR_DCACHE: dcache_d = csr_wdata[0]; // enable bit - riscv::CSR_ICACHE: icache_d = csr_wdata[0]; // enable bit - riscv::CSR_L1_ICACHE_MISS, - riscv::CSR_L1_DCACHE_MISS, - riscv::CSR_ITLB_MISS, - riscv::CSR_DTLB_MISS, - riscv::CSR_LOAD, - riscv::CSR_STORE, - riscv::CSR_EXCEPTION, - riscv::CSR_EXCEPTION_RET, - riscv::CSR_BRANCH_JUMP, - riscv::CSR_CALL, - riscv::CSR_RET, - riscv::CSR_MIS_PREDICT: begin + riscv::CSR_ML1_ICACHE_MISS, + riscv::CSR_ML1_DCACHE_MISS, + riscv::CSR_MITLB_MISS, + riscv::CSR_MDTLB_MISS, + riscv::CSR_MLOAD, + riscv::CSR_MSTORE, + riscv::CSR_MEXCEPTION, + riscv::CSR_MEXCEPTION_RET, + riscv::CSR_MBRANCH_JUMP, + riscv::CSR_MCALL, + riscv::CSR_MRET, + riscv::CSR_MMIS_PREDICT, + riscv::CSR_MSB_FULL, + riscv::CSR_MIF_EMPTY, + riscv::CSR_MHPM_COUNTER_17, + riscv::CSR_MHPM_COUNTER_18, + riscv::CSR_MHPM_COUNTER_19, + riscv::CSR_MHPM_COUNTER_20, + riscv::CSR_MHPM_COUNTER_21, + riscv::CSR_MHPM_COUNTER_22, + riscv::CSR_MHPM_COUNTER_23, + riscv::CSR_MHPM_COUNTER_24, + riscv::CSR_MHPM_COUNTER_25, + riscv::CSR_MHPM_COUNTER_26, + riscv::CSR_MHPM_COUNTER_27, + riscv::CSR_MHPM_COUNTER_28, + riscv::CSR_MHPM_COUNTER_29, + riscv::CSR_MHPM_COUNTER_30, + riscv::CSR_MHPM_COUNTER_31: begin perf_data_o = csr_wdata; perf_we_o = 1'b1; end + + riscv::CSR_DCACHE: dcache_d = csr_wdata[0]; // enable bit + riscv::CSR_ICACHE: icache_d = csr_wdata[0]; // enable bit default: update_access_exception = 1'b1; endcase end diff --git a/src/perf_counters.sv b/src/perf_counters.sv index ad8fabdb2..eb096b8fc 100644 --- a/src/perf_counters.sv +++ b/src/perf_counters.sv @@ -44,8 +44,7 @@ module perf_counters #( input logic eret_i, input branchpredict_t resolved_branch_i ); - - logic [riscv::CSR_IF_EMPTY[4:0] : riscv::CSR_L1_ICACHE_MISS[4:0]][63:0] perf_counter_d, perf_counter_q; + logic [riscv::CSR_MIF_EMPTY[4:0] : riscv::CSR_ML1_ICACHE_MISS[4:0]][63:0] perf_counter_d, perf_counter_q; always_comb begin : perf_counters perf_counter_d = perf_counter_q; @@ -57,56 +56,56 @@ module perf_counters #( // Update Performance Counters // ------------------------------ if (l1_icache_miss_i) - perf_counter_d[riscv::CSR_L1_ICACHE_MISS[4:0]] = perf_counter_q[riscv::CSR_L1_ICACHE_MISS[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_ML1_ICACHE_MISS[4:0]] = perf_counter_q[riscv::CSR_ML1_ICACHE_MISS[4:0]] + 1'b1; if (l1_dcache_miss_i) - perf_counter_d[riscv::CSR_L1_DCACHE_MISS[4:0]] = perf_counter_q[riscv::CSR_L1_DCACHE_MISS[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_ML1_DCACHE_MISS[4:0]] = perf_counter_q[riscv::CSR_ML1_DCACHE_MISS[4:0]] + 1'b1; if (itlb_miss_i) - perf_counter_d[riscv::CSR_ITLB_MISS[4:0]] = perf_counter_q[riscv::CSR_ITLB_MISS[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MITLB_MISS[4:0]] = perf_counter_q[riscv::CSR_MITLB_MISS[4:0]] + 1'b1; if (dtlb_miss_i) - perf_counter_d[riscv::CSR_DTLB_MISS[4:0]] = perf_counter_q[riscv::CSR_DTLB_MISS[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MDTLB_MISS[4:0]] = perf_counter_q[riscv::CSR_MDTLB_MISS[4:0]] + 1'b1; // instruction related perf counters for (int unsigned i = 0; i < NR_COMMIT_PORTS-1; i++) begin if (commit_ack_i[i]) begin if (commit_instr_i[i].fu == LOAD) - perf_counter_d[riscv::CSR_LOAD[4:0]] = perf_counter_q[riscv::CSR_LOAD[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MLOAD[4:0]] = perf_counter_q[riscv::CSR_MLOAD[4:0]] + 1'b1; if (commit_instr_i[i].fu == STORE) - perf_counter_d[riscv::CSR_STORE[4:0]] = perf_counter_q[riscv::CSR_STORE[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MSTORE[4:0]] = perf_counter_q[riscv::CSR_MSTORE[4:0]] + 1'b1; if (commit_instr_i[i].fu == CTRL_FLOW) - perf_counter_d[riscv::CSR_BRANCH_JUMP[4:0]] = perf_counter_q[riscv::CSR_BRANCH_JUMP[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MBRANCH_JUMP[4:0]] = perf_counter_q[riscv::CSR_MBRANCH_JUMP[4:0]] + 1'b1; // The standard software calling convention uses register x1 to hold the return address on a call // the unconditional jump is decoded as ADD op if (commit_instr_i[i].fu == CTRL_FLOW && commit_instr_i[i].op == '0 && (commit_instr_i[i].rd == 'd1 || commit_instr_i[i].rd == 'd1)) - perf_counter_d[riscv::CSR_CALL[4:0]] = perf_counter_q[riscv::CSR_CALL[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MCALL[4:0]] = perf_counter_q[riscv::CSR_MCALL[4:0]] + 1'b1; // Return from call if (commit_instr_i[i].op == JALR && (commit_instr_i[i].rd == 'd1 || commit_instr_i[i].rd == 'd1)) - perf_counter_d[riscv::CSR_RET[4:0]] = perf_counter_q[riscv::CSR_RET[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MRET[4:0]] = perf_counter_q[riscv::CSR_MRET[4:0]] + 1'b1; end end if (ex_i.valid) - perf_counter_d[riscv::CSR_EXCEPTION[4:0]] = perf_counter_q[riscv::CSR_EXCEPTION[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MEXCEPTION[4:0]] = perf_counter_q[riscv::CSR_MEXCEPTION[4:0]] + 1'b1; if (eret_i) - perf_counter_d[riscv::CSR_EXCEPTION_RET[4:0]] = perf_counter_q[riscv::CSR_EXCEPTION_RET[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MEXCEPTION_RET[4:0]] = perf_counter_q[riscv::CSR_MEXCEPTION_RET[4:0]] + 1'b1; if (resolved_branch_i.valid && resolved_branch_i.is_mispredict) - perf_counter_d[riscv::CSR_MIS_PREDICT[4:0]] = perf_counter_q[riscv::CSR_MIS_PREDICT[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MMIS_PREDICT[4:0]] = perf_counter_q[riscv::CSR_MMIS_PREDICT[4:0]] + 1'b1; if (sb_full_i) begin - perf_counter_d[riscv::CSR_SB_FULL[4:0]] = perf_counter_q[riscv::CSR_SB_FULL[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MSB_FULL[4:0]] = perf_counter_q[riscv::CSR_MSB_FULL[4:0]] + 1'b1; end if (if_empty_i) begin - perf_counter_d[riscv::CSR_IF_EMPTY[4:0]] = perf_counter_q[riscv::CSR_IF_EMPTY[4:0]] + 1'b1; + perf_counter_d[riscv::CSR_MIF_EMPTY[4:0]] = perf_counter_q[riscv::CSR_MIF_EMPTY[4:0]] + 1'b1; end end