cvw/pipelined/src/privileged/csrm.sv
2022-02-02 20:28:21 +00:00

210 lines
10 KiB
Systemverilog

///////////////////////////////////////////
// csrm.sv
//
// Written: David_Harris@hmc.edu 9 January 2021
// Modified:
// dottolia@hmc.edu 7 April 2021
//
// Purpose: Machine-Mode Control and Status Registers
// See RISC-V Privileged Mode Specification 20190608
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// MIT LICENSE
// 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 csrm #(parameter
// Machine CSRs
MVENDORID = 12'hF11,
MARCHID = 12'hF12,
MIMPID = 12'hF13,
MHARTID = 12'hF14,
MSTATUS = 12'h300,
MISA_ADR = 12'h301,
MEDELEG = 12'h302,
MIDELEG = 12'h303,
MIE = 12'h304,
MTVEC = 12'h305,
MCOUNTEREN = 12'h306,
MSTATUSH = 12'h310,
MCOUNTINHIBIT = 12'h320,
MSCRATCH = 12'h340,
MEPC = 12'h341,
MCAUSE = 12'h342,
MTVAL = 12'h343,
MIP = 12'h344,
PMPCFG0 = 12'h3A0,
// .. up to 15 more at consecutive addresses
PMPADDR0 = 12'h3B0,
// ... up to 63 more at consecutive addresses
TSELECT = 12'h7A0,
TDATA1 = 12'h7A1,
TDATA2 = 12'h7A2,
TDATA3 = 12'h7A3,
DCSR = 12'h7B0,
DPC = 12'h7B1,
DSCRATCH0 = 12'h7B2,
DSCRATCH1 = 12'h7B3,
// Constants
ZERO = {(`XLEN){1'b0}},
MEDELEG_MASK = ~(ZERO | `XLEN'b1 << 11),
MIDELEG_MASK = {{(`XLEN-12){1'b0}}, 12'h222}
) (
input logic clk, reset,
input logic InstrValidNotFlushedM, StallW,
input logic CSRMWriteM, MTrapM,
input logic [11:0] CSRAdrM,
input logic [`XLEN-1:0] NextEPCM, NextCauseM, NextMtvalM, MSTATUS_REGW,
input logic [`XLEN-1:0] CSRWriteValM,
output logic [`XLEN-1:0] CSRMReadValM, MTVEC_REGW,
(* mark_debug = "true" *) output logic [`XLEN-1:0] MEPC_REGW,
output logic [31:0] MCOUNTEREN_REGW, MCOUNTINHIBIT_REGW,
output logic [`XLEN-1:0] MEDELEG_REGW, MIDELEG_REGW,
// 64-bit registers in RV64, or two 32-bit registers in RV32
//output var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
output var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
output var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
(* mark_debug = "true" *) input logic [11:0] MIP_REGW, MIE_REGW,
output logic WriteMSTATUSM,
output logic IllegalCSRMAccessM, IllegalCSRMWriteReadonlyM
);
logic [`XLEN-1:0] MISA_REGW, MHARTID_REGW;
(* mark_debug = "true" *) logic [`XLEN-1:0] MSCRATCH_REGW;
(* mark_debug = "true" *) logic [`XLEN-1:0] MCAUSE_REGW, MTVAL_REGW;
logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM;
logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM;
logic WriteMCOUNTERENM, WriteMCOUNTINHIBITM;
// There are PMP_ENTRIES = 0, 16, or 64 PMPADDR registers, each of which has its own flop
genvar i;
if (`PMP_ENTRIES > 0) begin:pmp
logic [`PMP_ENTRIES-1:0] WritePMPCFGM;
logic [`PMP_ENTRIES-1:0] WritePMPADDRM ;
logic [`PMP_ENTRIES-1:0] ADDRLocked, CFGLocked;
for(i=0; i<`PMP_ENTRIES; i++) begin
// when the lock bit is set, don't allow writes to the PMPCFG or PMPADDR
// also, when the lock bit of the next entry is set and the next entry is TOR, don't allow writes to this entry PMPADDR
assign CFGLocked[i] = PMPCFG_ARRAY_REGW[i][7];
if (i == `PMP_ENTRIES-1)
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7];
else
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7] | (PMPCFG_ARRAY_REGW[i+1][7] & PMPCFG_ARRAY_REGW[i+1][4:3] == 2'b01);
assign WritePMPADDRM[i] = (CSRMWriteM & (CSRAdrM == (PMPADDR0+i))) & InstrValidNotFlushedM & ~ADDRLocked[i];
flopenr #(`XLEN) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM, PMPADDR_ARRAY_REGW[i]);
if (`XLEN==64) begin
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+2*(i/8)))) & InstrValidNotFlushedM & ~CFGLocked[i];
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%8)*8+7:(i%8)*8], PMPCFG_ARRAY_REGW[i]);
end else begin
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+i/4))) & InstrValidNotFlushedM & ~CFGLocked[i];
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%4)*8+7:(i%4)*8], PMPCFG_ARRAY_REGW[i]);
end
end
end
localparam MISA_26 = (`MISA) & 32'h03ffffff;
// MISA is hardwired. Spec says it could be written to disable features, but this is not supported by Wally
assign MISA_REGW = {(`XLEN == 32 ? 2'b01 : 2'b10), {(`XLEN-28){1'b0}}, MISA_26[25:0]};
// MHARTID is hardwired. It only exists as a signal so that the testbench can easily see it.
assign MHARTID_REGW = 0;
// Write machine Mode CSRs
assign WriteMSTATUSM = CSRMWriteM & (CSRAdrM == MSTATUS) & InstrValidNotFlushedM;
assign WriteMTVECM = CSRMWriteM & (CSRAdrM == MTVEC) & InstrValidNotFlushedM;
assign WriteMEDELEGM = CSRMWriteM & (CSRAdrM == MEDELEG) & InstrValidNotFlushedM;
assign WriteMIDELEGM = CSRMWriteM & (CSRAdrM == MIDELEG) & InstrValidNotFlushedM;
assign WriteMSCRATCHM = CSRMWriteM & (CSRAdrM == MSCRATCH) & InstrValidNotFlushedM;
assign WriteMEPCM = MTrapM | (CSRMWriteM & (CSRAdrM == MEPC)) & InstrValidNotFlushedM;
assign WriteMCAUSEM = MTrapM | (CSRMWriteM & (CSRAdrM == MCAUSE)) & InstrValidNotFlushedM;
assign WriteMTVALM = MTrapM | (CSRMWriteM & (CSRAdrM == MTVAL)) & InstrValidNotFlushedM;
assign WriteMCOUNTERENM = CSRMWriteM & (CSRAdrM == MCOUNTEREN) & InstrValidNotFlushedM;
assign WriteMCOUNTINHIBITM = CSRMWriteM & (CSRAdrM == MCOUNTINHIBIT) & InstrValidNotFlushedM;
assign IllegalCSRMWriteReadonlyM = CSRMWriteM & (CSRAdrM == MVENDORID | CSRAdrM == MARCHID | CSRAdrM == MIMPID | CSRAdrM == MHARTID);
// CSRs
flopenr #(`XLEN) MTVECreg(clk, reset, WriteMTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, MTVEC_REGW);
if (`S_SUPPORTED | (`U_SUPPORTED & `N_SUPPORTED)) begin:deleg // DELEG registers should exist
flopenr #(`XLEN) MEDELEGreg(clk, reset, WriteMEDELEGM, CSRWriteValM & MEDELEG_MASK /*12'h7FF*/, MEDELEG_REGW);
flopenr #(`XLEN) MIDELEGreg(clk, reset, WriteMIDELEGM, CSRWriteValM & MIDELEG_MASK /*12'h222*/, MIDELEG_REGW);
end else assign {MEDELEG_REGW, MIDELEG_REGW} = 0;
flopenr #(`XLEN) MSCRATCHreg(clk, reset, WriteMSCRATCHM, CSRWriteValM, MSCRATCH_REGW);
flopenr #(`XLEN) MEPCreg(clk, reset, WriteMEPCM, NextEPCM, MEPC_REGW);
flopenr #(`XLEN) MCAUSEreg(clk, reset, WriteMCAUSEM, NextCauseM, MCAUSE_REGW);
if(`QEMU) assign MTVAL_REGW = `XLEN'b0;
else flopenr #(`XLEN) MTVALreg(clk, reset, WriteMTVALM, NextMtvalM, MTVAL_REGW);
flopenr #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, CSRWriteValM[31:0], MCOUNTEREN_REGW);
flopenr #(32) MCOUNTINHIBITreg(clk, reset, WriteMCOUNTINHIBITM, CSRWriteValM[31:0], MCOUNTINHIBIT_REGW);
// Read machine mode CSRs
// verilator lint_off WIDTH
logic [5:0] entry;
always_comb begin
entry = '0;
IllegalCSRMAccessM = !(`S_SUPPORTED | `U_SUPPORTED & `N_SUPPORTED) &
(CSRAdrM == MEDELEG | CSRAdrM == MIDELEG); // trap on DELEG register access when no S or N-mode
if (CSRAdrM >= PMPADDR0 & CSRAdrM < PMPADDR0 + `PMP_ENTRIES) // reading a PMP entry
CSRMReadValM = PMPADDR_ARRAY_REGW[CSRAdrM - PMPADDR0];
else if (CSRAdrM >= PMPCFG0 & CSRAdrM < PMPCFG0 + `PMP_ENTRIES/4) begin
if (`XLEN==64) begin
entry = ({CSRAdrM[11:1], 1'b0} - PMPCFG0)*4; // disregard odd entries in RV64
CSRMReadValM = {PMPCFG_ARRAY_REGW[entry+7],PMPCFG_ARRAY_REGW[entry+6],PMPCFG_ARRAY_REGW[entry+5],PMPCFG_ARRAY_REGW[entry+4],
PMPCFG_ARRAY_REGW[entry+3],PMPCFG_ARRAY_REGW[entry+2],PMPCFG_ARRAY_REGW[entry+1],PMPCFG_ARRAY_REGW[entry]};
end else begin
entry = (CSRAdrM - PMPCFG0)*4;
CSRMReadValM = {PMPCFG_ARRAY_REGW[entry+3],PMPCFG_ARRAY_REGW[entry+2],PMPCFG_ARRAY_REGW[entry+1],PMPCFG_ARRAY_REGW[entry]};
end
end
else case (CSRAdrM)
MISA_ADR: CSRMReadValM = MISA_REGW;
MVENDORID: CSRMReadValM = 0;
MARCHID: CSRMReadValM = 0;
MIMPID: CSRMReadValM = `XLEN'h100; // pipelined implementation
MHARTID: CSRMReadValM = MHARTID_REGW; // hardwired to 0
MSTATUS: CSRMReadValM = MSTATUS_REGW;
MSTATUSH: CSRMReadValM = 0; // flush this out later if MBE and SBE fields are supported
MTVEC: CSRMReadValM = MTVEC_REGW;
MEDELEG: CSRMReadValM = MEDELEG_REGW;
MIDELEG: CSRMReadValM = MIDELEG_REGW;
MIP: CSRMReadValM = {{(`XLEN-12){1'b0}}, MIP_REGW};
MIE: CSRMReadValM = {{(`XLEN-12){1'b0}}, MIE_REGW};
MSCRATCH: CSRMReadValM = MSCRATCH_REGW;
MEPC: CSRMReadValM = MEPC_REGW;
MCAUSE: CSRMReadValM = MCAUSE_REGW;
MTVAL: CSRMReadValM = MTVAL_REGW;
MCOUNTEREN:CSRMReadValM = {{(`XLEN-32){1'b0}}, MCOUNTEREN_REGW};
MCOUNTINHIBIT:CSRMReadValM = {{(`XLEN-32){1'b0}}, MCOUNTINHIBIT_REGW};
default: begin
CSRMReadValM = 0;
IllegalCSRMAccessM = 1;
end
endcase
end
// verilator lint_on WIDTH
endmodule