From e3cdb5746806f912030f514431e9065798c304d4 Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 18 Sep 2026 03:52:07 -0700 Subject: [PATCH 1/3] mseccfg implementation --- src/privileged/csrm.sv | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/privileged/csrm.sv b/src/privileged/csrm.sv index 785a4d9aac..0d69a5ce0a 100644 --- a/src/privileged/csrm.sv +++ b/src/privileged/csrm.sv @@ -58,6 +58,7 @@ module csrm import cvw::*; #(parameter cvw_t P) ( logic [P.XLEN-1:0] MISA_REGW, MHARTID_REGW; logic [P.XLEN-1:0] MSCRATCH_REGW, MTVAL_REGW, MCAUSE_REGW; logic [P.XLEN-1:0] MENVCFGH_REGW; + logic [63:0] MSECCFG_REGW; logic [P.XLEN-1:0] TVECWriteValM; logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM; logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM; @@ -89,6 +90,8 @@ module csrm import cvw::*; #(parameter cvw_t P) ( // .. up to 15 more at consecutive addresses localparam PMPADDR0 = 12'h3B0; // ... up to 63 more at consecutive addresses + localparam MSECCFG = 12'h747; + localparam MSECCFGH = 12'h757; /* verilator lint_off UNUSEDPARAM */ localparam TSELECT = 12'h7A0; localparam TDATA1 = 12'h7A1; @@ -225,6 +228,49 @@ module csrm import cvw::*; #(parameter cvw_t P) ( assign MENVCFGH_REGW = '0; end + // MSECCFG register + // mseccfg is 64 bits wide even in RV32, where the upper half is accessed as mseccfgh. + // Wally does not yet support any of the extensions that define mseccfg fields, so every + // field is presently read-only 0. Uncomment the terms below as each extension is added. + // Note that the Smepmp fields also need sticky/locking behavior: MML and MMWP cannot be + // cleared once set, and RLB cannot be set once any pmpcfg entry has its L bit set, both + // until a PMP reset. + logic WriteMSECCFGM; + logic [63:0] MSECCFG_WriteValM; + logic [63:0] MSECCFG_PreWriteValM; +//logic [1:0] LegalizedPMM; + + assign WriteMSECCFGM = CSRMWriteM & (CSRAdrM == MSECCFG); + // PMM is a WARL field: 00 = disabled, 10 = PMLEN 7, 11 = PMLEN 16, and 01 is reserved. + // Smmpm requires the largest supported address to fit in XLEN-PMLEN bits, so PMLEN 16 is + // unavailable with Sv57 or PA_BITS > 48. Illegal writes keep the old value, as menvcfg.CBIE does. +//localparam PMLEN16_OK = !P.SV57_SUPPORTED & (P.PA_BITS <= 48); +//assign LegalizedPMM = ((MSECCFG_PreWriteValM[33:32] == 2'b01) | // reserved encoding +// (MSECCFG_PreWriteValM[33:32] == 2'b11 & !PMLEN16_OK)) ? // PMLEN 16 too wide +// MSECCFG_REGW[33:32] : MSECCFG_PreWriteValM[33:32]; + assign MSECCFG_WriteValM = { + 30'b0, // 63:34 WPRI + 2'b0, // LegalizedPMM & {2{P.SMMPM_SUPPORTED & (P.XLEN==64)}}, // 33:32 PMM (Smmpm); read-only 0 on RV32 + 21'b0, // 31:11 WPRI + 1'b0, // MSECCFG_PreWriteValM[10] & P.ZICFILP_SUPPORTED, // 10 MLPE (Zicfilp) + 1'b0, // MSECCFG_PreWriteValM[9] & P.ZKR_SUPPORTED & P.S_SUPPORTED, // 9 SSEED (Zkr) + 1'b0, // MSECCFG_PreWriteValM[8] & P.ZKR_SUPPORTED & P.U_SUPPORTED, // 8 USEED (Zkr) + 5'b0, // 7:3 WPRI + 1'b0, // MSECCFG_PreWriteValM[2] & P.SMEPMP_SUPPORTED, // 2 RLB (Smepmp) + 1'b0, // MSECCFG_PreWriteValM[1] & P.SMEPMP_SUPPORTED, // 1 MMWP (Smepmp) + 1'b0 // MSECCFG_PreWriteValM[0] & P.SMEPMP_SUPPORTED // 0 MML (Smepmp) + }; + if (P.XLEN == 64) begin + assign MSECCFG_PreWriteValM = CSRWriteValM; + flopenr #(P.XLEN) MSECCFGreg(clk, reset, WriteMSECCFGM, MSECCFG_WriteValM, MSECCFG_REGW); + end else begin // RV32 has high and low halves + logic WriteMSECCFGHM; + assign MSECCFG_PreWriteValM = {CSRWriteValM, CSRWriteValM}; + assign WriteMSECCFGHM = CSRMWriteM & (CSRAdrM == MSECCFGH); + flopenr #(P.XLEN) MSECCFGreg(clk, reset, WriteMSECCFGM, MSECCFG_WriteValM[31:0], MSECCFG_REGW[31:0]); + flopenr #(P.XLEN) MSECCFGHreg(clk, reset, WriteMSECCFGHM, MSECCFG_WriteValM[63:32], MSECCFG_REGW[63:32]); + end + // Grain alignment for PMPADDR read values. for(i=0; i Date: Fri, 18 Sep 2026 04:36:22 -0700 Subject: [PATCH 2/3] Trace mseccfg from the register rather than a constant zero The tracer reported both CSRs as literal 0, which is right only while every field is read-only zero. Connect it to MSECCFG_REGW so that enabling a field later cannot silently leave lockstep comparing against a stale constant. Co-Authored-By: Claude Opus 5 (1M context) --- testbench/common/wallyTracer.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testbench/common/wallyTracer.sv b/testbench/common/wallyTracer.sv index 8c9cad424e..d1ed45b294 100644 --- a/testbench/common/wallyTracer.sv +++ b/testbench/common/wallyTracer.sv @@ -217,7 +217,7 @@ module wallyTracer import cvw::*; #(parameter cvw_t P) (rvviTrace rvvi); // Machine Information Registers and Configuration CSRs `CONNECT_CSR(MISA, 12'h301, testbench.dut.core.priv.priv.csr.csrm.MISA_REGW); `CONNECT_CSR(MENVCFG, 12'h30A, testbench.dut.core.priv.priv.csr.csrm.MENVCFG_REGW); - `CONNECT_CSR(MSECCFG, 12'h747, 0); // mseccfg + `CONNECT_CSR(MSECCFG, 12'h747, testbench.dut.core.priv.priv.csr.csrm.MSECCFG_REGW[P.XLEN-1:0]); `CONNECT_CSR(MVENDORID, 12'hF11, 0); //mvendorid `CONNECT_CSR(MARCHID, 12'hF12, 0); // marchid `CONNECT_CSR(MIMPID, 12'hF13, {{P.XLEN-12{1'b0}}, 12'h100}); // mimpid @@ -244,7 +244,7 @@ module wallyTracer import cvw::*; #(parameter cvw_t P) (rvviTrace rvvi); if (P.XLEN == 32) begin `CONNECT_CSR(MSTATUSH, 12'h310, testbench.dut.core.priv.priv.csr.csrsr.MSTATUSH_REGW); `CONNECT_CSR(MENVCFGH, 12'h31A, testbench.dut.core.priv.priv.csr.csrm.MENVCFGH_REGW); - `CONNECT_CSR(MSECCFGH, 12'h757, 0); // mseccfgh + `CONNECT_CSR(MSECCFGH, 12'h757, testbench.dut.core.priv.priv.csr.csrm.MSECCFG_REGW[63:32]); end end From 176a385a230d573625402b8fc945ae1901fbc596 Mon Sep 17 00:00:00 2001 From: David Harris Date: Mon, 12 Oct 2026 11:48:31 -0700 Subject: [PATCH 3/3] Implement mseccfg only when an extension defines one of its fields mseccfg/mseccfgh exist only if Smepmp, Zkr, Zicfilp or Smmpm is implemented; otherwise accesses are illegal. Add a derived MSECCFG_SUPPORTED parameter (presently 0, since Wally supports none of those extensions) that gates the register, the CSR read decode and the tracer connections. Co-Authored-By: Claude Opus 5.5 (1M context) --- config/shared/config-shared.vh | 4 ++ config/shared/parameter-defs.vh | 1 + src/cvw.sv | 1 + src/privileged/csrm.sv | 81 ++++++++++++++++++--------------- testbench/common/wallyTracer.sv | 8 +++- 5 files changed, 56 insertions(+), 39 deletions(-) diff --git a/config/shared/config-shared.vh b/config/shared/config-shared.vh index ea6885f9be..a3a5fdce31 100644 --- a/config/shared/config-shared.vh +++ b/config/shared/config-shared.vh @@ -34,6 +34,10 @@ localparam logic A_SUPPORTED = (ZAAMO_SUPPORTED & ZALRSC_SUPPORTED); localparam logic B_SUPPORTED = ((ZBA_SUPPORTED & ZBB_SUPPORTED & ZBS_SUPPORTED)); localparam logic C_SUPPORTED = ZCA_SUPPORTED & (D_SUPPORTED ? ZCD_SUPPORTED : 1) & (F_SUPPORTED ? ((XLEN == 32) ? ZCF_SUPPORTED : 1) : 1); localparam logic ZKN_SUPPORTED = (ZBKB_SUPPORTED & ZBKC_SUPPORTED & ZBKX_SUPPORTED & ZKND_SUPPORTED & ZKNE_SUPPORTED & ZKNH_SUPPORTED); +// mseccfg/mseccfgh exist only when an extension defining one of their fields is implemented +// (Smepmp, Zkr, Zicfilp, Smmpm); otherwise accesses raise illegal instruction. +// Wally supports none of them yet. Replace the 0 with the OR of those parameters as they are added. +localparam logic MSECCFG_SUPPORTED = 0; // SMEPMP_SUPPORTED | ZKR_SUPPORTED | ZICFILP_SUPPORTED | SMMPM_SUPPORTED // Configure MISA based on supported extensions localparam MISA = {6'b0, 5'b0, U_SUPPORTED, 1'b0, S_SUPPORTED, 1'b0, Q_SUPPORTED, 3'b0, M_SUPPORTED, 3'b0, I_SUPPORTED, 2'b0, diff --git a/config/shared/parameter-defs.vh b/config/shared/parameter-defs.vh index e9603a3998..279511026c 100644 --- a/config/shared/parameter-defs.vh +++ b/config/shared/parameter-defs.vh @@ -18,6 +18,7 @@ localparam cvw_t P = '{ ZFH_SUPPORTED : ZFH_SUPPORTED, ZFA_SUPPORTED : ZFA_SUPPORTED, SSTC_SUPPORTED : SSTC_SUPPORTED, + MSECCFG_SUPPORTED : MSECCFG_SUPPORTED, VIRTMEM_SUPPORTED : VIRTMEM_SUPPORTED, SV32_SUPPORTED : SV32_SUPPORTED, SV39_SUPPORTED : SV39_SUPPORTED, diff --git a/src/cvw.sv b/src/cvw.sv index c6244edfa6..c157a87adf 100644 --- a/src/cvw.sv +++ b/src/cvw.sv @@ -53,6 +53,7 @@ typedef struct packed { logic ZFH_SUPPORTED; logic ZFA_SUPPORTED; logic SSTC_SUPPORTED; + logic MSECCFG_SUPPORTED; logic VIRTMEM_SUPPORTED; logic SVPBMT_SUPPORTED; logic SVNAPOT_SUPPORTED; diff --git a/src/privileged/csrm.sv b/src/privileged/csrm.sv index 0d69a5ce0a..3497bb952d 100644 --- a/src/privileged/csrm.sv +++ b/src/privileged/csrm.sv @@ -230,45 +230,51 @@ module csrm import cvw::*; #(parameter cvw_t P) ( // MSECCFG register // mseccfg is 64 bits wide even in RV32, where the upper half is accessed as mseccfgh. - // Wally does not yet support any of the extensions that define mseccfg fields, so every - // field is presently read-only 0. Uncomment the terms below as each extension is added. + // It exists only if an extension defining one of its fields is implemented (P.MSECCFG_SUPPORTED); + // otherwise mseccfg and mseccfgh are illegal. Wally does not yet support any of those + // extensions, so every field is presently read-only 0. Uncomment the terms below as each + // extension is added. // Note that the Smepmp fields also need sticky/locking behavior: MML and MMWP cannot be // cleared once set, and RLB cannot be set once any pmpcfg entry has its L bit set, both // until a PMP reset. - logic WriteMSECCFGM; - logic [63:0] MSECCFG_WriteValM; - logic [63:0] MSECCFG_PreWriteValM; -//logic [1:0] LegalizedPMM; + if (P.MSECCFG_SUPPORTED) begin:mseccfg + logic WriteMSECCFGM; + logic [63:0] MSECCFG_WriteValM; + logic [63:0] MSECCFG_PreWriteValM; +// logic [1:0] LegalizedPMM; - assign WriteMSECCFGM = CSRMWriteM & (CSRAdrM == MSECCFG); - // PMM is a WARL field: 00 = disabled, 10 = PMLEN 7, 11 = PMLEN 16, and 01 is reserved. - // Smmpm requires the largest supported address to fit in XLEN-PMLEN bits, so PMLEN 16 is - // unavailable with Sv57 or PA_BITS > 48. Illegal writes keep the old value, as menvcfg.CBIE does. -//localparam PMLEN16_OK = !P.SV57_SUPPORTED & (P.PA_BITS <= 48); -//assign LegalizedPMM = ((MSECCFG_PreWriteValM[33:32] == 2'b01) | // reserved encoding -// (MSECCFG_PreWriteValM[33:32] == 2'b11 & !PMLEN16_OK)) ? // PMLEN 16 too wide -// MSECCFG_REGW[33:32] : MSECCFG_PreWriteValM[33:32]; - assign MSECCFG_WriteValM = { - 30'b0, // 63:34 WPRI - 2'b0, // LegalizedPMM & {2{P.SMMPM_SUPPORTED & (P.XLEN==64)}}, // 33:32 PMM (Smmpm); read-only 0 on RV32 - 21'b0, // 31:11 WPRI - 1'b0, // MSECCFG_PreWriteValM[10] & P.ZICFILP_SUPPORTED, // 10 MLPE (Zicfilp) - 1'b0, // MSECCFG_PreWriteValM[9] & P.ZKR_SUPPORTED & P.S_SUPPORTED, // 9 SSEED (Zkr) - 1'b0, // MSECCFG_PreWriteValM[8] & P.ZKR_SUPPORTED & P.U_SUPPORTED, // 8 USEED (Zkr) - 5'b0, // 7:3 WPRI - 1'b0, // MSECCFG_PreWriteValM[2] & P.SMEPMP_SUPPORTED, // 2 RLB (Smepmp) - 1'b0, // MSECCFG_PreWriteValM[1] & P.SMEPMP_SUPPORTED, // 1 MMWP (Smepmp) - 1'b0 // MSECCFG_PreWriteValM[0] & P.SMEPMP_SUPPORTED // 0 MML (Smepmp) - }; - if (P.XLEN == 64) begin - assign MSECCFG_PreWriteValM = CSRWriteValM; - flopenr #(P.XLEN) MSECCFGreg(clk, reset, WriteMSECCFGM, MSECCFG_WriteValM, MSECCFG_REGW); - end else begin // RV32 has high and low halves - logic WriteMSECCFGHM; - assign MSECCFG_PreWriteValM = {CSRWriteValM, CSRWriteValM}; - assign WriteMSECCFGHM = CSRMWriteM & (CSRAdrM == MSECCFGH); - flopenr #(P.XLEN) MSECCFGreg(clk, reset, WriteMSECCFGM, MSECCFG_WriteValM[31:0], MSECCFG_REGW[31:0]); - flopenr #(P.XLEN) MSECCFGHreg(clk, reset, WriteMSECCFGHM, MSECCFG_WriteValM[63:32], MSECCFG_REGW[63:32]); + assign WriteMSECCFGM = CSRMWriteM & (CSRAdrM == MSECCFG); + // PMM is a WARL field: 00 = disabled, 10 = PMLEN 7, 11 = PMLEN 16, and 01 is reserved. + // Smmpm requires the largest supported address to fit in XLEN-PMLEN bits, so PMLEN 16 is + // unavailable with Sv57 or PA_BITS > 48. Illegal writes keep the old value, as menvcfg.CBIE does. +// localparam PMLEN16_OK = !P.SV57_SUPPORTED & (P.PA_BITS <= 48); +// assign LegalizedPMM = ((MSECCFG_PreWriteValM[33:32] == 2'b01) | // reserved encoding +// (MSECCFG_PreWriteValM[33:32] == 2'b11 & !PMLEN16_OK)) ? // PMLEN 16 too wide +// MSECCFG_REGW[33:32] : MSECCFG_PreWriteValM[33:32]; + assign MSECCFG_WriteValM = { + 30'b0, // 63:34 WPRI + 2'b0, // LegalizedPMM & {2{P.SMMPM_SUPPORTED & (P.XLEN==64)}}, // 33:32 PMM (Smmpm); read-only 0 on RV32 + 21'b0, // 31:11 WPRI + 1'b0, // MSECCFG_PreWriteValM[10] & P.ZICFILP_SUPPORTED, // 10 MLPE (Zicfilp) + 1'b0, // MSECCFG_PreWriteValM[9] & P.ZKR_SUPPORTED & P.S_SUPPORTED, // 9 SSEED (Zkr) + 1'b0, // MSECCFG_PreWriteValM[8] & P.ZKR_SUPPORTED & P.U_SUPPORTED, // 8 USEED (Zkr) + 5'b0, // 7:3 WPRI + 1'b0, // MSECCFG_PreWriteValM[2] & P.SMEPMP_SUPPORTED, // 2 RLB (Smepmp) + 1'b0, // MSECCFG_PreWriteValM[1] & P.SMEPMP_SUPPORTED, // 1 MMWP (Smepmp) + 1'b0 // MSECCFG_PreWriteValM[0] & P.SMEPMP_SUPPORTED // 0 MML (Smepmp) + }; + if (P.XLEN == 64) begin + assign MSECCFG_PreWriteValM = CSRWriteValM; + flopenr #(P.XLEN) MSECCFGreg(clk, reset, WriteMSECCFGM, MSECCFG_WriteValM, MSECCFG_REGW); + end else begin // RV32 has high and low halves + logic WriteMSECCFGHM; + assign MSECCFG_PreWriteValM = {CSRWriteValM, CSRWriteValM}; + assign WriteMSECCFGHM = CSRMWriteM & (CSRAdrM == MSECCFGH); + flopenr #(P.XLEN) MSECCFGreg(clk, reset, WriteMSECCFGM, MSECCFG_WriteValM[31:0], MSECCFG_REGW[31:0]); + flopenr #(P.XLEN) MSECCFGHreg(clk, reset, WriteMSECCFGHM, MSECCFG_WriteValM[63:32], MSECCFG_REGW[63:32]); + end + end else begin + assign MSECCFG_REGW = '0; end // Grain alignment for PMPADDR read values. @@ -326,8 +332,9 @@ module csrm import cvw::*; #(parameter cvw_t P) ( MENVCFGH: if (P.U_SUPPORTED & P.XLEN==32) CSRMReadValM = MENVCFGH_REGW; else IllegalCSRMAccessM = 1'b1; MCOUNTINHIBIT: CSRMReadValM = {{(P.XLEN-32){1'b0}}, MCOUNTINHIBIT_REGW}; - MSECCFG: CSRMReadValM = MSECCFG_REGW[P.XLEN-1:0]; - MSECCFGH: if (P.XLEN==32) CSRMReadValM = MSECCFG_REGW[63:32]; + MSECCFG: if (P.MSECCFG_SUPPORTED) CSRMReadValM = MSECCFG_REGW[P.XLEN-1:0]; + else IllegalCSRMAccessM = 1'b1; + MSECCFGH: if (P.MSECCFG_SUPPORTED & P.XLEN==32) CSRMReadValM = MSECCFG_REGW[63:32]; else IllegalCSRMAccessM = 1'b1; default: IllegalCSRMAccessM = 1'b1; endcase diff --git a/testbench/common/wallyTracer.sv b/testbench/common/wallyTracer.sv index d1ed45b294..8ec78e4796 100644 --- a/testbench/common/wallyTracer.sv +++ b/testbench/common/wallyTracer.sv @@ -217,12 +217,17 @@ module wallyTracer import cvw::*; #(parameter cvw_t P) (rvviTrace rvvi); // Machine Information Registers and Configuration CSRs `CONNECT_CSR(MISA, 12'h301, testbench.dut.core.priv.priv.csr.csrm.MISA_REGW); `CONNECT_CSR(MENVCFG, 12'h30A, testbench.dut.core.priv.priv.csr.csrm.MENVCFG_REGW); - `CONNECT_CSR(MSECCFG, 12'h747, testbench.dut.core.priv.priv.csr.csrm.MSECCFG_REGW[P.XLEN-1:0]); `CONNECT_CSR(MVENDORID, 12'hF11, 0); //mvendorid `CONNECT_CSR(MARCHID, 12'hF12, 0); // marchid `CONNECT_CSR(MIMPID, 12'hF13, {{P.XLEN-12{1'b0}}, 12'h100}); // mimpid `CONNECT_CSR(MHARTID, 12'hF14, testbench.dut.core.priv.priv.csr.csrm.MHARTID_REGW); `CONNECT_CSR(MCONFIGPTR, 12'hF15, 0); //mconfigptr + if (P.MSECCFG_SUPPORTED) begin + `CONNECT_CSR(MSECCFG, 12'h747, testbench.dut.core.priv.priv.csr.csrm.MSECCFG_REGW[P.XLEN-1:0]); + if (P.XLEN == 32) begin + `CONNECT_CSR(MSECCFGH, 12'h757, testbench.dut.core.priv.priv.csr.csrm.MSECCFG_REGW[63:32]); + end + end // Supervisor Information Registers and Configuration CSRs if (P.S_SUPPORTED) begin @@ -244,7 +249,6 @@ module wallyTracer import cvw::*; #(parameter cvw_t P) (rvviTrace rvvi); if (P.XLEN == 32) begin `CONNECT_CSR(MSTATUSH, 12'h310, testbench.dut.core.priv.priv.csr.csrsr.MSTATUSH_REGW); `CONNECT_CSR(MENVCFGH, 12'h31A, testbench.dut.core.priv.priv.csr.csrm.MENVCFGH_REGW); - `CONNECT_CSR(MSECCFGH, 12'h757, testbench.dut.core.priv.priv.csr.csrm.MSECCFG_REGW[63:32]); end end