/////////////////////////////////////////// // csr.sv // // Written: David_Harris@hmc.edu 9 January 2021 // Modified: // dottolia@hmc.edu 7 April 2021 // // Purpose: Counter 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 csr #(parameter MIP = 12'h344, SIP = 12'h144 ) ( input logic clk, reset, input logic FlushE, FlushM, FlushW, input logic StallE, StallM, StallW, input logic [31:0] InstrM, input logic [`XLEN-1:0] PCM, SrcAM, IEUAdrM, input logic CSRReadM, CSRWriteM, TrapM, MTrapM, STrapM, mretM, sretM, wfiM, InterruptM, input logic MTimerInt, MExtInt, SExtInt, MSwInt, input logic [63:0] MTIME_CLINT, input logic InstrValidM, FRegWriteM, LoadStallD, input logic BPPredDirWrongM, input logic BTBPredPCWrongM, input logic RASPredPCWrongM, input logic BPPredClassNonCFIWrongM, input logic [4:0] InstrClassM, input logic DCacheMiss, input logic DCacheAccess, input logic ICacheMiss, input logic ICacheAccess, input logic [1:0] NextPrivilegeModeM, PrivilegeModeW, input logic [`XLEN-1:0] CauseM, //NextFaultMtvalM, input logic SelHPTW, output logic [1:0] STATUS_MPP, output logic STATUS_SPP, STATUS_TSR, STATUS_TVM, output logic [`XLEN-1:0] MEPC_REGW, SEPC_REGW, output logic [`XLEN-1:0] MEDELEG_REGW, output logic [`XLEN-1:0] SATP_REGW, output logic [11:0] MIP_REGW, MIE_REGW, MIDELEG_REGW, output logic STATUS_MIE, STATUS_SIE, output logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, STATUS_TW, output logic [1:0] STATUS_FS, 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], input logic [4:0] SetFflagsM, output logic [2:0] FRM_REGW, output logic [`XLEN-1:0] CSRReadValW, PrivilegedNextPCM, output logic IllegalCSRAccessM, BigEndianM ); localparam NOP = 32'h13; logic [`XLEN-1:0] CSRMReadValM, CSRSReadValM, CSRUReadValM, CSRCReadValM; (* mark_debug = "true" *) logic [`XLEN-1:0] CSRReadValM; (* mark_debug = "true" *) logic [`XLEN-1:0] CSRSrcM; logic [`XLEN-1:0] CSRRWM, CSRRSM, CSRRCM; (* mark_debug = "true" *) logic [`XLEN-1:0] CSRWriteValM; (* mark_debug = "true" *) logic [`XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, MSTATUSH_REGW; logic [`XLEN-1:0] STVEC_REGW, MTVEC_REGW; logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW; logic WriteMSTATUSM, WriteMSTATUSHM, WriteSSTATUSM; logic CSRMWriteM, CSRSWriteM, CSRUWriteM; logic WriteFRMM, WriteFFLAGSM; logic [`XLEN-1:0] UnalignedNextEPCM, NextEPCM, NextCauseM, NextMtvalM; logic [11:0] CSRAdrM; //logic [11:0] UIP_REGW, UIE_REGW = 0; // N user-mode exceptions not supported logic IllegalCSRCAccessM, IllegalCSRMAccessM, IllegalCSRSAccessM, IllegalCSRUAccessM, InsufficientCSRPrivilegeM; logic IllegalCSRMWriteReadonlyM; logic [`XLEN-1:0] CSRReadVal2M; logic [11:0] MIP_REGW_writeable; logic [`XLEN-1:0] PrivilegedTrapVector, PrivilegedVectoredTrapVector, NextFaultMtvalM; logic InstrValidNotFlushedM; assign InstrValidNotFlushedM = ~StallW & ~FlushW; /////////////////////////////////////////// // MTVAL /////////////////////////////////////////// always_comb case (CauseM) 12, 1, 3: NextFaultMtvalM = PCM; // Instruction page/access faults, breakpoint 2: NextFaultMtvalM = {{(`XLEN-32){1'b0}}, InstrM}; // Illegal instruction fault 0, 4, 6, 13, 15, 5, 7: NextFaultMtvalM = IEUAdrM; // Instruction misaligned, Load/Store Misaligned/page/access faults default: NextFaultMtvalM = 0; // Ecall, interrupts endcase /////////////////////////////////////////// // Trap Vectoring /////////////////////////////////////////// // // POSSIBLE OPTIMIZATION: // From 20190608 privielegd spec page 27 (3.1.7) // > Allowing coarser alignments in Vectored mode enables vectoring to be // > implemented without a hardware adder circuit. // For example, we could require m/stvec be aligned on 7 bits to let us replace the adder directly below with // [untested] PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:7], CauseM[3:0], 4'b0000} // However, this is program dependent, so not implemented at this time. always_comb if (NextPrivilegeModeM == `S_MODE) PrivilegedTrapVector = STVEC_REGW; else PrivilegedTrapVector = MTVEC_REGW; if(`VECTORED_INTERRUPTS_SUPPORTED) begin:vec always_comb if (PrivilegedTrapVector[1:0] == 2'b01 & CauseM[`XLEN-1] == 1) PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2] + CauseM[`XLEN-3:0], 2'b00}; else PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00}; end else begin assign PrivilegedVectoredTrapVector = {PrivilegedTrapVector[`XLEN-1:2], 2'b00}; end always_comb if (TrapM) PrivilegedNextPCM = PrivilegedVectoredTrapVector; else if (mretM) PrivilegedNextPCM = MEPC_REGW; else PrivilegedNextPCM = SEPC_REGW; /////////////////////////////////////////// // CSRWriteValM /////////////////////////////////////////// always_comb begin // Choose either rs1 or uimm[4:0] as source CSRSrcM = InstrM[14] ? {{(`XLEN-5){1'b0}}, InstrM[19:15]} : SrcAM; // CSR set and clear for MIP/SIP should only touch internal state, not interrupt inputs if (CSRAdrM == MIP | CSRAdrM == SIP) CSRReadVal2M = {{(`XLEN-12){1'b0}}, MIP_REGW_writeable}; else CSRReadVal2M = CSRReadValM; // Compute AND/OR modification CSRRWM = CSRSrcM; CSRRSM = CSRReadVal2M | CSRSrcM; CSRRCM = CSRReadVal2M & ~CSRSrcM; case (InstrM[13:12]) 2'b01: CSRWriteValM = CSRRWM; 2'b10: CSRWriteValM = CSRRSM; 2'b11: CSRWriteValM = CSRRCM; default: CSRWriteValM = CSRReadValM; endcase end /////////////////////////////////////////// // CSR Write values /////////////////////////////////////////// assign CSRAdrM = InstrM[31:20]; assign UnalignedNextEPCM = TrapM ? ((wfiM & InterruptM) ? PCM+4 : PCM) : CSRWriteValM; assign NextEPCM = `C_SUPPORTED ? {UnalignedNextEPCM[`XLEN-1:1], 1'b0} : {UnalignedNextEPCM[`XLEN-1:2], 2'b00}; // 3.1.15 alignment assign NextCauseM = TrapM ? CauseM : CSRWriteValM; assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValM; assign CSRMWriteM = CSRWriteM & (PrivilegeModeW == `M_MODE); assign CSRSWriteM = CSRWriteM & (|PrivilegeModeW); assign CSRUWriteM = CSRWriteM; /////////////////////////////////////////// // CSRs /////////////////////////////////////////// csri csri(.clk, .reset, .InstrValidNotFlushedM, .StallW, .CSRMWriteM, .CSRSWriteM, .CSRWriteValM, .CSRAdrM, .MExtInt, .SExtInt, .MTimerInt, .MSwInt, .MIP_REGW, .MIE_REGW, .MIP_REGW_writeable); csrsr csrsr(.clk, .reset, .StallW, .WriteMSTATUSM, .WriteMSTATUSHM, .WriteSSTATUSM, .TrapM, .FRegWriteM, .NextPrivilegeModeM, .PrivilegeModeW, .mretM, .sretM, .WriteFRMM, .WriteFFLAGSM, .CSRWriteValM, .SelHPTW, .MSTATUS_REGW, .SSTATUS_REGW, .MSTATUSH_REGW, .STATUS_MPP, .STATUS_SPP, .STATUS_TSR, .STATUS_TW, .STATUS_MIE, .STATUS_SIE, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_TVM, .STATUS_FS, .BigEndianM); csrc counters(.clk, .reset, .StallE, .StallM, .StallW, .FlushM, .FlushW, .InstrValidM, .LoadStallD, .CSRMWriteM, .BPPredDirWrongM, .BTBPredPCWrongM, .RASPredPCWrongM, .BPPredClassNonCFIWrongM, .InstrClassM, .DCacheMiss, .DCacheAccess, .ICacheMiss, .ICacheAccess, .CSRAdrM, .PrivilegeModeW, .CSRWriteValM, .MCOUNTINHIBIT_REGW, .MCOUNTEREN_REGW, .SCOUNTEREN_REGW, .MTIME_CLINT, .CSRCReadValM, .IllegalCSRCAccessM); csrm csrm(.clk, .reset, .InstrValidNotFlushedM, .StallW, .CSRMWriteM, .MTrapM, .CSRAdrM, .NextEPCM, .NextCauseM, .NextMtvalM, .MSTATUS_REGW, .MSTATUSH_REGW, .CSRWriteValM, .CSRMReadValM, .MTVEC_REGW, .MEPC_REGW, .MCOUNTEREN_REGW, .MCOUNTINHIBIT_REGW, .MEDELEG_REGW, .MIDELEG_REGW,.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .MIP_REGW, .MIE_REGW, .WriteMSTATUSM, .WriteMSTATUSHM, .IllegalCSRMAccessM, .IllegalCSRMWriteReadonlyM); csrs csrs(.clk, .reset, .InstrValidNotFlushedM, .StallW, .CSRSWriteM, .STrapM, .CSRAdrM, .NextEPCM, .NextCauseM, .NextMtvalM, .SSTATUS_REGW, .STATUS_TVM, .CSRWriteValM, .PrivilegeModeW, .CSRSReadValM, .STVEC_REGW, .SEPC_REGW, .SCOUNTEREN_REGW, .SATP_REGW, .MIP_REGW, .MIE_REGW, .WriteSSTATUSM, .IllegalCSRSAccessM); csru csru(.clk, .reset, .InstrValidNotFlushedM, .StallW, .CSRUWriteM, .CSRAdrM, .CSRWriteValM, .STATUS_FS, .CSRUReadValM, .SetFflagsM, .FRM_REGW, .WriteFRMM, .WriteFFLAGSM, .IllegalCSRUAccessM); // merge CSR Reads assign CSRReadValM = CSRUReadValM | CSRSReadValM | CSRMReadValM | CSRCReadValM; flopenrc #(`XLEN) CSRValWReg(clk, reset, FlushW, ~StallW, CSRReadValM, CSRReadValW); // merge illegal accesses: illegal if none of the CSR addresses is legal or privilege is insufficient assign InsufficientCSRPrivilegeM = (CSRAdrM[9:8] == 2'b11 & PrivilegeModeW != `M_MODE) | (CSRAdrM[9:8] == 2'b01 & PrivilegeModeW == `U_MODE); assign IllegalCSRAccessM = ((IllegalCSRCAccessM & IllegalCSRMAccessM & IllegalCSRSAccessM & IllegalCSRUAccessM | InsufficientCSRPrivilegeM) & CSRReadM) | IllegalCSRMWriteReadonlyM; endmodule