mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
The privileged unit is parameterized using Lim's method.
This commit is contained in:
parent
4d961bd080
commit
8cf38b28aa
@ -28,18 +28,14 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module csr #(parameter
|
||||
MIP = 12'h344,
|
||||
SIP = 12'h144) (
|
||||
module csr import cvw::*; #(parameter cvw_t P, MIP = 12'h344, SIP = 12'h144) (
|
||||
input logic clk, reset,
|
||||
input logic FlushM, FlushW,
|
||||
input logic StallE, StallM, StallW,
|
||||
input logic [31:0] InstrM, // current instruction
|
||||
input logic [31:0] InstrOrigM, // Original compressed or uncompressed instruction in Memory stage for Illegal Instruction MTVAL
|
||||
input logic [`XLEN-1:0] PCM, PC2NextF, // program counter, next PC going to trap/return logic
|
||||
input logic [`XLEN-1:0] SrcAM, IEUAdrM, // SrcA and memory address from IEU
|
||||
input logic [P.XLEN-1:0] PCM, PC2NextF, // program counter, next PC going to trap/return logic
|
||||
input logic [P.XLEN-1:0] SrcAM, IEUAdrM, // SrcA and memory address from IEU
|
||||
input logic CSRReadM, CSRWriteM, // read or write CSR
|
||||
input logic TrapM, // trap is occurring
|
||||
input logic mretM, sretM, wfiM, // return or WFI instruction
|
||||
@ -80,48 +76,48 @@ module csr #(parameter
|
||||
output logic [1:0] STATUS_MPP,
|
||||
output logic STATUS_SPP, STATUS_TSR, STATUS_TVM,
|
||||
output logic [15:0] MEDELEG_REGW,
|
||||
output logic [`XLEN-1:0] SATP_REGW,
|
||||
output logic [P.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 [`PA_BITS-3:0] PMPADDR_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0],
|
||||
output var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW[P.PMP_ENTRIES-1:0],
|
||||
output logic [2:0] FRM_REGW,
|
||||
//
|
||||
output logic [`XLEN-1:0] CSRReadValW, // value read from CSR
|
||||
output logic [`XLEN-1:0] UnalignedPCNextF, // Next PC, accounting for traps and returns
|
||||
output logic [P.XLEN-1:0] CSRReadValW, // value read from CSR
|
||||
output logic [P.XLEN-1:0] UnalignedPCNextF, // Next PC, accounting for traps and returns
|
||||
output logic IllegalCSRAccessM, // Illegal CSR access: CSR doesn't exist or is inaccessible at this privilege level
|
||||
output logic BigEndianM // memory access is big-endian based on privilege mode and STATUS register endian fields
|
||||
);
|
||||
|
||||
logic [`XLEN-1:0] CSRMReadValM, CSRSReadValM, CSRUReadValM, CSRCReadValM;
|
||||
logic [`XLEN-1:0] CSRReadValM;
|
||||
logic [`XLEN-1:0] CSRSrcM;
|
||||
logic [`XLEN-1:0] CSRRWM, CSRRSM, CSRRCM;
|
||||
logic [`XLEN-1:0] CSRWriteValM;
|
||||
logic [`XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, MSTATUSH_REGW;
|
||||
logic [`XLEN-1:0] STVEC_REGW, MTVEC_REGW;
|
||||
logic [`XLEN-1:0] MEPC_REGW, SEPC_REGW;
|
||||
logic [P.XLEN-1:0] CSRMReadValM, CSRSReadValM, CSRUReadValM, CSRCReadValM;
|
||||
logic [P.XLEN-1:0] CSRReadValM;
|
||||
logic [P.XLEN-1:0] CSRSrcM;
|
||||
logic [P.XLEN-1:0] CSRRWM, CSRRSM, CSRRCM;
|
||||
logic [P.XLEN-1:0] CSRWriteValM;
|
||||
logic [P.XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, MSTATUSH_REGW;
|
||||
logic [P.XLEN-1:0] STVEC_REGW, MTVEC_REGW;
|
||||
logic [P.XLEN-1:0] MEPC_REGW, SEPC_REGW;
|
||||
logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW;
|
||||
logic WriteMSTATUSM, WriteMSTATUSHM, WriteSSTATUSM;
|
||||
logic CSRMWriteM, CSRSWriteM, CSRUWriteM;
|
||||
logic UngatedCSRMWriteM;
|
||||
logic WriteFRMM, WriteFFLAGSM;
|
||||
logic [`XLEN-1:0] UnalignedNextEPCM, NextEPCM, NextMtvalM;
|
||||
logic [P.XLEN-1:0] UnalignedNextEPCM, NextEPCM, NextMtvalM;
|
||||
logic [4:0] NextCauseM;
|
||||
logic [11:0] CSRAdrM;
|
||||
logic IllegalCSRCAccessM, IllegalCSRMAccessM, IllegalCSRSAccessM, IllegalCSRUAccessM;
|
||||
logic InsufficientCSRPrivilegeM;
|
||||
logic IllegalCSRMWriteReadonlyM;
|
||||
logic [`XLEN-1:0] CSRReadVal2M;
|
||||
logic [P.XLEN-1:0] CSRReadVal2M;
|
||||
logic [11:0] MIP_REGW_writeable;
|
||||
logic [`XLEN-1:0] TVecM, TrapVectorM, NextFaultMtvalM;
|
||||
logic [P.XLEN-1:0] TVecM, TrapVectorM, NextFaultMtvalM;
|
||||
logic MTrapM, STrapM;
|
||||
logic [`XLEN-1:0] EPC;
|
||||
logic [P.XLEN-1:0] EPC;
|
||||
logic RetM;
|
||||
logic SelMtvecM;
|
||||
logic [`XLEN-1:0] TVecAlignedM;
|
||||
logic [P.XLEN-1:0] TVecAlignedM;
|
||||
logic InstrValidNotFlushedM;
|
||||
logic STimerInt;
|
||||
|
||||
@ -136,7 +132,7 @@ module csr #(parameter
|
||||
if (InterruptM) NextFaultMtvalM = 0;
|
||||
else case (CauseM)
|
||||
12, 1, 3: NextFaultMtvalM = PCM; // Instruction page/access faults, breakpoint
|
||||
2: NextFaultMtvalM = {{(`XLEN-32){1'b0}}, InstrOrigM}; // Illegal instruction fault
|
||||
2: NextFaultMtvalM = {{(P.XLEN-32){1'b0}}, InstrOrigM}; // 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
|
||||
@ -146,17 +142,17 @@ module csr #(parameter
|
||||
///////////////////////////////////////////
|
||||
|
||||
// Select trap vector from STVEC or MTVEC and word-align
|
||||
assign SelMtvecM = (NextPrivilegeModeM == `M_MODE);
|
||||
mux2 #(`XLEN) tvecmux(STVEC_REGW, MTVEC_REGW, SelMtvecM, TVecM);
|
||||
assign TVecAlignedM = {TVecM[`XLEN-1:2], 2'b00};
|
||||
assign SelMtvecM = (NextPrivilegeModeM == P.M_MODE);
|
||||
mux2 #(P.XLEN) tvecmux(STVEC_REGW, MTVEC_REGW, SelMtvecM, TVecM);
|
||||
assign TVecAlignedM = {TVecM[P.XLEN-1:2], 2'b00};
|
||||
|
||||
// Support vectored interrupts
|
||||
if(`VECTORED_INTERRUPTS_SUPPORTED) begin:vec
|
||||
if(P.VECTORED_INTERRUPTS_SUPPORTED) begin:vec
|
||||
logic VectoredM;
|
||||
logic [`XLEN-1:0] TVecPlusCauseM;
|
||||
logic [P.XLEN-1:0] TVecPlusCauseM;
|
||||
assign VectoredM = InterruptM & (TVecM[1:0] == 2'b01);
|
||||
assign TVecPlusCauseM = {TVecAlignedM[`XLEN-1:6], CauseM, 2'b00}; // 64-byte alignment allows concatenation rather than addition
|
||||
mux2 #(`XLEN) trapvecmux(TVecAlignedM, TVecPlusCauseM, VectoredM, TrapVectorM);
|
||||
assign TVecPlusCauseM = {TVecAlignedM[P.XLEN-1:6], CauseM, 2'b00}; // 64-byte alignment allows concatenation rather than addition
|
||||
mux2 #(P.XLEN) trapvecmux(TVecAlignedM, TVecPlusCauseM, VectoredM, TrapVectorM);
|
||||
end else
|
||||
assign TrapVectorM = TVecAlignedM; // unvectored interrupt handler can be at any word-aligned address. This is called Sstvecd
|
||||
|
||||
@ -164,8 +160,8 @@ module csr #(parameter
|
||||
// A trap sets the PC to TrapVector
|
||||
// A return sets the PC to MEPC or SEPC
|
||||
assign RetM = mretM | sretM;
|
||||
mux2 #(`XLEN) epcmux(SEPC_REGW, MEPC_REGW, mretM, EPC);
|
||||
mux3 #(`XLEN) pcmux3(PC2NextF, EPC, TrapVectorM, {TrapM, RetM}, UnalignedPCNextF);
|
||||
mux2 #(P.XLEN) epcmux(SEPC_REGW, MEPC_REGW, mretM, EPC);
|
||||
mux3 #(P.XLEN) pcmux3(PC2NextF, EPC, TrapVectorM, {TrapM, RetM}, UnalignedPCNextF);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// CSRWriteValM
|
||||
@ -173,10 +169,10 @@ module csr #(parameter
|
||||
|
||||
always_comb begin
|
||||
// Choose either rs1 or uimm[4:0] as source
|
||||
CSRSrcM = InstrM[14] ? {{(`XLEN-5){1'b0}}, InstrM[19:15]} : SrcAM;
|
||||
CSRSrcM = InstrM[14] ? {{(P.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};
|
||||
if (CSRAdrM == MIP | CSRAdrM == SIP) CSRReadVal2M = {{(P.XLEN-12){1'b0}}, MIP_REGW_writeable};
|
||||
else CSRReadVal2M = CSRReadValM;
|
||||
|
||||
// Compute AND/OR modification
|
||||
@ -197,26 +193,26 @@ module csr #(parameter
|
||||
|
||||
assign CSRAdrM = InstrM[31:20];
|
||||
assign UnalignedNextEPCM = TrapM ? ((wfiM & IntPendingM) ? 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 ? {InterruptM, CauseM}: {CSRWriteValM[`XLEN-1], CSRWriteValM[3:0]};
|
||||
assign NextEPCM = P.C_SUPPORTED ? {UnalignedNextEPCM[P.XLEN-1:1], 1'b0} : {UnalignedNextEPCM[P.XLEN-1:2], 2'b00}; // 3.1.15 alignment
|
||||
assign NextCauseM = TrapM ? {InterruptM, CauseM}: {CSRWriteValM[P.XLEN-1], CSRWriteValM[3:0]};
|
||||
assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValM;
|
||||
assign UngatedCSRMWriteM = CSRWriteM & (PrivilegeModeW == `M_MODE);
|
||||
assign UngatedCSRMWriteM = CSRWriteM & (PrivilegeModeW == P.M_MODE);
|
||||
assign CSRMWriteM = UngatedCSRMWriteM & InstrValidNotFlushedM;
|
||||
assign CSRSWriteM = CSRWriteM & (|PrivilegeModeW) & InstrValidNotFlushedM;
|
||||
assign CSRUWriteM = CSRWriteM & InstrValidNotFlushedM;
|
||||
assign MTrapM = TrapM & (NextPrivilegeModeM == `M_MODE);
|
||||
assign STrapM = TrapM & (NextPrivilegeModeM == `S_MODE) & `S_SUPPORTED;
|
||||
assign MTrapM = TrapM & (NextPrivilegeModeM == P.M_MODE);
|
||||
assign STrapM = TrapM & (NextPrivilegeModeM == P.S_MODE) & P.S_SUPPORTED;
|
||||
|
||||
///////////////////////////////////////////
|
||||
// CSRs
|
||||
///////////////////////////////////////////
|
||||
|
||||
csri csri(.clk, .reset,
|
||||
csri #(P) csri(.clk, .reset,
|
||||
.CSRMWriteM, .CSRSWriteM, .CSRWriteValM, .CSRAdrM,
|
||||
.MExtInt, .SExtInt, .MTimerInt, .STimerInt, .MSwInt,
|
||||
.MIDELEG_REGW, .MIP_REGW, .MIE_REGW, .MIP_REGW_writeable);
|
||||
|
||||
csrsr csrsr(.clk, .reset, .StallW,
|
||||
csrsr #(P) csrsr(.clk, .reset, .StallW,
|
||||
.WriteMSTATUSM, .WriteMSTATUSHM, .WriteSSTATUSM,
|
||||
.TrapM, .FRegWriteM, .NextPrivilegeModeM, .PrivilegeModeW,
|
||||
.mretM, .sretM, .WriteFRMM, .WriteFFLAGSM, .CSRWriteValM, .SelHPTW,
|
||||
@ -225,7 +221,7 @@ module csr #(parameter
|
||||
.STATUS_MIE, .STATUS_SIE, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_TVM,
|
||||
.STATUS_FS, .BigEndianM);
|
||||
|
||||
csrm csrm(.clk, .reset,
|
||||
csrm #(P) csrm(.clk, .reset,
|
||||
.UngatedCSRMWriteM, .CSRMWriteM, .MTrapM, .CSRAdrM,
|
||||
.NextEPCM, .NextCauseM, .NextMtvalM, .MSTATUS_REGW, .MSTATUSH_REGW,
|
||||
.CSRWriteValM, .CSRMReadValM, .MTVEC_REGW,
|
||||
@ -235,8 +231,8 @@ module csr #(parameter
|
||||
.IllegalCSRMAccessM, .IllegalCSRMWriteReadonlyM);
|
||||
|
||||
|
||||
if (`S_SUPPORTED) begin:csrs
|
||||
csrs csrs(.clk, .reset,
|
||||
if (P.S_SUPPORTED) begin:csrs
|
||||
csrs #(P) csrs(.clk, .reset,
|
||||
.CSRSWriteM, .STrapM, .CSRAdrM,
|
||||
.NextEPCM, .NextCauseM, .NextMtvalM, .SSTATUS_REGW,
|
||||
.STATUS_TVM, .MCOUNTEREN_TM(MCOUNTEREN_REGW[1]),
|
||||
@ -256,8 +252,8 @@ module csr #(parameter
|
||||
end
|
||||
|
||||
// Floating Point CSRs in User Mode only needed if Floating Point is supported
|
||||
if (`F_SUPPORTED | `D_SUPPORTED) begin:csru
|
||||
csru csru(.clk, .reset, .InstrValidNotFlushedM,
|
||||
if (P.F_SUPPORTED | P.D_SUPPORTED) begin:csru
|
||||
csru #(P) csru(.clk, .reset, .InstrValidNotFlushedM,
|
||||
.CSRUWriteM, .CSRAdrM, .CSRWriteValM, .STATUS_FS, .CSRUReadValM,
|
||||
.SetFflagsM, .FRM_REGW, .WriteFRMM, .WriteFFLAGSM,
|
||||
.IllegalCSRUAccessM);
|
||||
@ -267,8 +263,8 @@ module csr #(parameter
|
||||
assign IllegalCSRUAccessM = 1;
|
||||
end
|
||||
|
||||
if (`ZICOUNTERS_SUPPORTED) begin:counters
|
||||
csrc counters(.clk, .reset, .StallE, .StallM, .FlushM,
|
||||
if (P.ZICOUNTERS_SUPPORTED) begin:counters
|
||||
csrc #(P) counters(.clk, .reset, .StallE, .StallM, .FlushM,
|
||||
.InstrValidNotFlushedM, .LoadStallD, .StoreStallD, .CSRWriteM, .CSRMWriteM,
|
||||
.BPDirPredWrongM, .BTAWrongM, .RASPredPCWrongM, .IClassWrongM, .BPWrongM,
|
||||
.InstrClassM, .DCacheMiss, .DCacheAccess, .ICacheMiss, .ICacheAccess, .sfencevmaM,
|
||||
@ -283,11 +279,11 @@ module csr #(parameter
|
||||
|
||||
// merge CSR Reads
|
||||
assign CSRReadValM = CSRUReadValM | CSRSReadValM | CSRMReadValM | CSRCReadValM;
|
||||
flopenrc #(`XLEN) CSRValWReg(clk, reset, FlushW, ~StallW, CSRReadValM, CSRReadValW);
|
||||
flopenrc #(P.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 InsufficientCSRPrivilegeM = (CSRAdrM[9:8] == 2'b11 & PrivilegeModeW != P.M_MODE) |
|
||||
(CSRAdrM[9:8] == 2'b01 & PrivilegeModeW == P.U_MODE);
|
||||
assign IllegalCSRAccessM = ((IllegalCSRCAccessM & IllegalCSRMAccessM &
|
||||
IllegalCSRSAccessM & IllegalCSRUAccessM |
|
||||
InsufficientCSRPrivilegeM) & CSRReadM) | IllegalCSRMWriteReadonlyM;
|
||||
|
@ -30,8 +30,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
module csrc #(parameter
|
||||
module csrc import cvw::*; #(parameter cvw_t P,
|
||||
MHPMCOUNTERBASE = 12'hB00,
|
||||
MTIME = 12'hB01, // this is a memory-mapped register; no such CSR exists, and access should fault
|
||||
MHPMCOUNTERHBASE = 12'hB80,
|
||||
@ -67,22 +66,22 @@ module csrc #(parameter
|
||||
input logic FDivBusyE, // floating point divide busy
|
||||
input logic [11:0] CSRAdrM,
|
||||
input logic [1:0] PrivilegeModeW,
|
||||
input logic [`XLEN-1:0] CSRWriteValM,
|
||||
input logic [P.XLEN-1:0] CSRWriteValM,
|
||||
input logic [31:0] MCOUNTINHIBIT_REGW, MCOUNTEREN_REGW, SCOUNTEREN_REGW,
|
||||
input logic [63:0] MTIME_CLINT,
|
||||
output logic [`XLEN-1:0] CSRCReadValM,
|
||||
output logic [P.XLEN-1:0] CSRCReadValM,
|
||||
output logic IllegalCSRCAccessM
|
||||
);
|
||||
|
||||
logic [4:0] CounterNumM;
|
||||
logic [`XLEN-1:0] HPMCOUNTER_REGW[`COUNTERS-1:0];
|
||||
logic [`XLEN-1:0] HPMCOUNTERH_REGW[`COUNTERS-1:0];
|
||||
logic [P.XLEN-1:0] HPMCOUNTER_REGW[P.COUNTERS-1:0];
|
||||
logic [P.XLEN-1:0] HPMCOUNTERH_REGW[P.COUNTERS-1:0];
|
||||
logic LoadStallE, LoadStallM;
|
||||
logic StoreStallE, StoreStallM;
|
||||
logic [`COUNTERS-1:0] WriteHPMCOUNTERM;
|
||||
logic [`COUNTERS-1:0] CounterEvent;
|
||||
logic [63:0] HPMCOUNTERPlusM[`COUNTERS-1:0];
|
||||
logic [`XLEN-1:0] NextHPMCOUNTERM[`COUNTERS-1:0];
|
||||
logic [P.COUNTERS-1:0] WriteHPMCOUNTERM;
|
||||
logic [P.COUNTERS-1:0] CounterEvent;
|
||||
logic [63:0] HPMCOUNTERPlusM[P.COUNTERS-1:0];
|
||||
logic [P.XLEN-1:0] NextHPMCOUNTERM[P.COUNTERS-1:0];
|
||||
genvar i;
|
||||
|
||||
// Interface signals
|
||||
@ -93,8 +92,8 @@ module csrc #(parameter
|
||||
assign CounterEvent[0] = 1'b1; // MCYCLE always increments
|
||||
assign CounterEvent[1] = 1'b0; // Counter 1 doesn't exist
|
||||
assign CounterEvent[2] = InstrValidNotFlushedM; // MINSTRET instructions retired
|
||||
if(`QEMU) begin: cevent // No other performance counters in QEMU
|
||||
assign CounterEvent[`COUNTERS-1:3] = 0;
|
||||
if(P.QEMU) begin: cevent // No other performance counters in QEMU
|
||||
assign CounterEvent[P.COUNTERS-1:3] = 0;
|
||||
end else begin: cevent // User-defined counters
|
||||
assign CounterEvent[3] = InstrClassM[0] & InstrValidNotFlushedM; // branch instruction
|
||||
assign CounterEvent[4] = InstrClassM[1] & ~InstrClassM[2] & InstrValidNotFlushedM; // jump and not return instructions
|
||||
@ -121,26 +120,26 @@ module csrc #(parameter
|
||||
// DivBusyE will never be assert high since this configuration uses the FPU to do integer division
|
||||
assign CounterEvent[24] = DivBusyE | FDivBusyE; // division cycles *** RT: might need to be delay until the next cycle
|
||||
// coverage on
|
||||
assign CounterEvent[`COUNTERS-1:25] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
|
||||
assign CounterEvent[P.COUNTERS-1:25] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
|
||||
end
|
||||
|
||||
// Counter update and write logic
|
||||
for (i = 0; i < `COUNTERS; i = i+1) begin:cntr
|
||||
for (i = 0; i < P.COUNTERS; i = i+1) begin:cntr
|
||||
assign WriteHPMCOUNTERM[i] = CSRMWriteM & (CSRAdrM == MHPMCOUNTERBASE + i);
|
||||
assign NextHPMCOUNTERM[i][`XLEN-1:0] = WriteHPMCOUNTERM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][`XLEN-1:0];
|
||||
assign NextHPMCOUNTERM[i][P.XLEN-1:0] = WriteHPMCOUNTERM[i] ? CSRWriteValM : HPMCOUNTERPlusM[i][P.XLEN-1:0];
|
||||
always_ff @(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];
|
||||
if (reset) HPMCOUNTER_REGW[i][P.XLEN-1:0] <= #1 0;
|
||||
else HPMCOUNTER_REGW[i][P.XLEN-1:0] <= #1 NextHPMCOUNTERM[i];
|
||||
|
||||
if (`XLEN==32) begin // write high and low separately
|
||||
logic [`COUNTERS-1:0] WriteHPMCOUNTERHM;
|
||||
logic [`XLEN-1:0] NextHPMCOUNTERHM[`COUNTERS-1:0];
|
||||
if (P.XLEN==32) begin // write high and low separately
|
||||
logic [P.COUNTERS-1:0] WriteHPMCOUNTERHM;
|
||||
logic [P.XLEN-1:0] NextHPMCOUNTERHM[P.COUNTERS-1:0];
|
||||
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_ff @(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];
|
||||
if (reset) HPMCOUNTERH_REGW[i][P.XLEN-1:0] <= #1 0;
|
||||
else HPMCOUNTERH_REGW[i][P.XLEN-1:0] <= #1 NextHPMCOUNTERHM[i];
|
||||
end else begin // XLEN=64; write entire register
|
||||
assign HPMCOUNTERPlusM[i] = HPMCOUNTER_REGW[i] + {63'b0, CounterEvent[i] & ~MCOUNTINHIBIT_REGW[i]};
|
||||
end
|
||||
@ -149,17 +148,17 @@ module csrc #(parameter
|
||||
// Read Counters, or cause excepiton if insufficient privilege in light of COUNTEREN flags
|
||||
assign CounterNumM = CSRAdrM[4:0]; // which counter to read?
|
||||
always_comb
|
||||
if (PrivilegeModeW == `M_MODE |
|
||||
MCOUNTEREN_REGW[CounterNumM] & (!`S_SUPPORTED | PrivilegeModeW == `S_MODE | SCOUNTEREN_REGW[CounterNumM])) begin
|
||||
if (PrivilegeModeW == P.M_MODE |
|
||||
MCOUNTEREN_REGW[CounterNumM] & (!P.S_SUPPORTED | PrivilegeModeW == P.S_MODE | SCOUNTEREN_REGW[CounterNumM])) begin
|
||||
IllegalCSRCAccessM = 0;
|
||||
if (`XLEN==64) begin // 64-bit counter reads
|
||||
if (P.XLEN==64) begin // 64-bit counter reads
|
||||
// Veri lator doesn't realize this only occurs for XLEN=64
|
||||
/* verilator lint_off WIDTH */
|
||||
if (CSRAdrM == TIME) CSRCReadValM = MTIME_CLINT; // TIME register is a shadow of the memory-mapped MTIME from the CLINT
|
||||
/* verilator lint_on WIDTH */
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+`COUNTERS & CSRAdrM != MTIME)
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+P.COUNTERS & CSRAdrM != MTIME)
|
||||
CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+`COUNTERS)
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+P.COUNTERS)
|
||||
CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else begin
|
||||
CSRCReadValM = 0;
|
||||
@ -171,13 +170,13 @@ module csrc #(parameter
|
||||
if (CSRAdrM == TIME) CSRCReadValM = MTIME_CLINT[31:0];// TIME register is a shadow of the memory-mapped MTIME from the CLINT
|
||||
else if (CSRAdrM == TIMEH) CSRCReadValM = MTIME_CLINT[63:32];
|
||||
/* verilator lint_on WIDTH */
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+`COUNTERS & CSRAdrM != MTIME)
|
||||
else if (CSRAdrM >= MHPMCOUNTERBASE & CSRAdrM < MHPMCOUNTERBASE+P.COUNTERS & CSRAdrM != MTIME)
|
||||
CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+`COUNTERS)
|
||||
else if (CSRAdrM >= HPMCOUNTERBASE & CSRAdrM < HPMCOUNTERBASE+P.COUNTERS)
|
||||
CSRCReadValM = HPMCOUNTER_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= MHPMCOUNTERHBASE & CSRAdrM < MHPMCOUNTERHBASE+`COUNTERS & CSRAdrM != MTIMEH)
|
||||
else if (CSRAdrM >= MHPMCOUNTERHBASE & CSRAdrM < MHPMCOUNTERHBASE+P.COUNTERS & CSRAdrM != MTIMEH)
|
||||
CSRCReadValM = HPMCOUNTERH_REGW[CounterNumM];
|
||||
else if (CSRAdrM >= HPMCOUNTERHBASE & CSRAdrM < HPMCOUNTERHBASE+`COUNTERS)
|
||||
else if (CSRAdrM >= HPMCOUNTERHBASE & CSRAdrM < HPMCOUNTERHBASE+P.COUNTERS)
|
||||
CSRCReadValM = HPMCOUNTERH_REGW[CounterNumM];
|
||||
else begin
|
||||
CSRCReadValM = 0;
|
||||
|
@ -27,16 +27,14 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module csri #(parameter
|
||||
module csri import cvw::*; #(parameter cvw_t P,
|
||||
MIE = 12'h304,
|
||||
MIP = 12'h344,
|
||||
SIE = 12'h104,
|
||||
SIP = 12'h144) (
|
||||
input logic clk, reset,
|
||||
input logic CSRMWriteM, CSRSWriteM,
|
||||
input logic [`XLEN-1:0] CSRWriteValM,
|
||||
input logic [P.XLEN-1:0] CSRWriteValM,
|
||||
input logic [11:0] CSRAdrM,
|
||||
input logic MExtInt, SExtInt, MTimerInt, STimerInt, MSwInt,
|
||||
input logic [11:0] MIDELEG_REGW,
|
||||
@ -58,8 +56,8 @@ module csri #(parameter
|
||||
// MEIP, MTIP, MSIP are read-only
|
||||
// SEIP, STIP, SSIP is writable in MIP if S mode exists
|
||||
// SSIP is writable in SIP if S mode exists
|
||||
if (`S_SUPPORTED) begin:mask
|
||||
if (`SSTC_SUPPORTED) begin
|
||||
if (P.S_SUPPORTED) begin:mask
|
||||
if (P.SSTC_SUPPORTED) begin
|
||||
assign MIP_WRITE_MASK = 12'h202; // SEIP and SSIP are writable, but STIP is not writable when STIMECMP is implemented (see SSTC spec)
|
||||
assign STIP = STimerInt;
|
||||
end else begin
|
||||
|
@ -31,9 +31,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module csrm #(parameter
|
||||
module csrm import cvw::*; #(parameter cvw_t P,
|
||||
// Machine CSRs
|
||||
MVENDORID = 12'hF11,
|
||||
MARCHID = 12'hF12,
|
||||
@ -68,52 +66,52 @@ module csrm #(parameter
|
||||
DSCRATCH0 = 12'h7B2,
|
||||
DSCRATCH1 = 12'h7B3,
|
||||
// Constants
|
||||
ZERO = {(`XLEN){1'b0}},
|
||||
ZERO = {(P.XLEN){1'b0}},
|
||||
MEDELEG_MASK = 16'hB3FF,
|
||||
MIDELEG_MASK = 12'h222 // we choose to not make machine interrupts delegable
|
||||
) (
|
||||
input logic clk, reset,
|
||||
input logic UngatedCSRMWriteM, CSRMWriteM, MTrapM,
|
||||
input logic [11:0] CSRAdrM,
|
||||
input logic [`XLEN-1:0] NextEPCM, NextMtvalM, MSTATUS_REGW, MSTATUSH_REGW,
|
||||
input logic [P.XLEN-1:0] NextEPCM, NextMtvalM, MSTATUS_REGW, MSTATUSH_REGW,
|
||||
input logic [4:0] NextCauseM,
|
||||
input logic [`XLEN-1:0] CSRWriteValM,
|
||||
input logic [P.XLEN-1:0] CSRWriteValM,
|
||||
input logic [11:0] MIP_REGW, MIE_REGW,
|
||||
output logic [`XLEN-1:0] CSRMReadValM, MTVEC_REGW,
|
||||
output logic [`XLEN-1:0] MEPC_REGW,
|
||||
output logic [P.XLEN-1:0] CSRMReadValM, MTVEC_REGW,
|
||||
output logic [P.XLEN-1:0] MEPC_REGW,
|
||||
output logic [31:0] MCOUNTEREN_REGW, MCOUNTINHIBIT_REGW,
|
||||
output logic [15:0] MEDELEG_REGW,
|
||||
output logic [11:0] MIDELEG_REGW,
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
output var logic [`PA_BITS-3:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0],
|
||||
output var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW [P.PMP_ENTRIES-1:0],
|
||||
output logic WriteMSTATUSM, WriteMSTATUSHM,
|
||||
output logic IllegalCSRMAccessM, IllegalCSRMWriteReadonlyM
|
||||
);
|
||||
|
||||
logic [`XLEN-1:0] MISA_REGW, MHARTID_REGW;
|
||||
logic [`XLEN-1:0] MSCRATCH_REGW, MTVAL_REGW, MCAUSE_REGW;
|
||||
logic [P.XLEN-1:0] MISA_REGW, MHARTID_REGW;
|
||||
logic [P.XLEN-1:0] MSCRATCH_REGW, MTVAL_REGW, MCAUSE_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
|
||||
if (P.PMP_ENTRIES > 0) begin:pmp
|
||||
logic [P.PMP_ENTRIES-1:0] WritePMPCFGM;
|
||||
logic [P.PMP_ENTRIES-1:0] WritePMPADDRM ;
|
||||
logic [P.PMP_ENTRIES-1:0] ADDRLocked, CFGLocked;
|
||||
for(i=0; i<P.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)
|
||||
if (i == P.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))) & ~ADDRLocked[i];
|
||||
flopenr #(`PA_BITS-2) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM[`PA_BITS-3:0], PMPADDR_ARRAY_REGW[i]);
|
||||
if (`XLEN==64) begin
|
||||
flopenr #(P.PA_BITS-2) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM[P.PA_BITS-3:0], PMPADDR_ARRAY_REGW[i]);
|
||||
if (P.XLEN==64) begin
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+2*(i/8)))) & ~CFGLocked[i];
|
||||
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%8)*8+7:(i%8)*8], PMPCFG_ARRAY_REGW[i]);
|
||||
end else begin
|
||||
@ -123,17 +121,17 @@ module csrm #(parameter
|
||||
end
|
||||
end
|
||||
|
||||
localparam MISA_26 = (`MISA) & 32'h03ffffff;
|
||||
localparam MISA_26 = (P.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]};
|
||||
assign MISA_REGW = {(P.XLEN == 32 ? 2'b01 : 2'b10), {(P.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);
|
||||
assign WriteMSTATUSHM = CSRMWriteM & (CSRAdrM == MSTATUSH)& (`XLEN==32);
|
||||
assign WriteMSTATUSHM = CSRMWriteM & (CSRAdrM == MSTATUSH)& (P.XLEN==32);
|
||||
assign WriteMTVECM = CSRMWriteM & (CSRAdrM == MTVEC);
|
||||
assign WriteMEDELEGM = CSRMWriteM & (CSRAdrM == MEDELEG);
|
||||
assign WriteMIDELEGM = CSRMWriteM & (CSRAdrM == MIDELEG);
|
||||
@ -147,19 +145,19 @@ module csrm #(parameter
|
||||
assign IllegalCSRMWriteReadonlyM = UngatedCSRMWriteM & (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) begin:deleg // DELEG registers should exist
|
||||
flopenr #(P.XLEN) MTVECreg(clk, reset, WriteMTVECM, {CSRWriteValM[P.XLEN-1:2], 1'b0, CSRWriteValM[0]}, MTVEC_REGW);
|
||||
if (P.S_SUPPORTED) begin:deleg // DELEG registers should exist
|
||||
flopenr #(16) MEDELEGreg(clk, reset, WriteMEDELEGM, CSRWriteValM[15:0] & MEDELEG_MASK, MEDELEG_REGW);
|
||||
flopenr #(12) MIDELEGreg(clk, reset, WriteMIDELEGM, CSRWriteValM[11:0] & MIDELEG_MASK, 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[4], {(`XLEN-5){1'b0}}, NextCauseM[3:0]}, MCAUSE_REGW);
|
||||
if(`QEMU) assign MTVAL_REGW = `XLEN'b0; // MTVAL tied to 0 in QEMU configuration
|
||||
else flopenr #(`XLEN) MTVALreg(clk, reset, WriteMTVALM, NextMtvalM, MTVAL_REGW);
|
||||
flopenr #(P.XLEN) MSCRATCHreg(clk, reset, WriteMSCRATCHM, CSRWriteValM, MSCRATCH_REGW);
|
||||
flopenr #(P.XLEN) MEPCreg(clk, reset, WriteMEPCM, NextEPCM, MEPC_REGW);
|
||||
flopenr #(P.XLEN) MCAUSEreg(clk, reset, WriteMCAUSEM, {NextCauseM[4], {(P.XLEN-5){1'b0}}, NextCauseM[3:0]}, MCAUSE_REGW);
|
||||
if(P.QEMU) assign MTVAL_REGW = '0; // MTVAL tied to 0 in QEMU configuration
|
||||
else flopenr #(P.XLEN) MTVALreg(clk, reset, WriteMTVALM, NextMtvalM, MTVAL_REGW);
|
||||
flopenr #(32) MCOUNTINHIBITreg(clk, reset, WriteMCOUNTINHIBITM, CSRWriteValM[31:0], MCOUNTINHIBIT_REGW);
|
||||
if (`U_SUPPORTED) begin: mcounteren // MCOUNTEREN only exists when user mode is supported
|
||||
if (P.U_SUPPORTED) begin: mcounteren // MCOUNTEREN only exists when user mode is supported
|
||||
flopenr #(32) MCOUNTERENreg(clk, reset, WriteMCOUNTERENM, CSRWriteValM[31:0], MCOUNTEREN_REGW);
|
||||
end else assign MCOUNTEREN_REGW = '0;
|
||||
|
||||
@ -168,12 +166,12 @@ module csrm #(parameter
|
||||
logic [5:0] entry;
|
||||
always_comb begin
|
||||
entry = '0;
|
||||
IllegalCSRMAccessM = !(`S_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 = {{(`XLEN-(`PA_BITS-2)){1'b0}}, PMPADDR_ARRAY_REGW[CSRAdrM - PMPADDR0]};
|
||||
else if (CSRAdrM >= PMPCFG0 & CSRAdrM < PMPCFG0 + `PMP_ENTRIES/4 & (`XLEN==32 | CSRAdrM[0] == 0)) begin
|
||||
IllegalCSRMAccessM = !(P.S_SUPPORTED) & (CSRAdrM == MEDELEG | CSRAdrM == MIDELEG); // trap on DELEG register access when no S or N-mode
|
||||
if (CSRAdrM >= PMPADDR0 & CSRAdrM < PMPADDR0 + P.PMP_ENTRIES) // reading a PMP entry
|
||||
CSRMReadValM = {{(P.XLEN-(P.PA_BITS-2)){1'b0}}, PMPADDR_ARRAY_REGW[CSRAdrM - PMPADDR0]};
|
||||
else if (CSRAdrM >= PMPCFG0 & CSRAdrM < PMPCFG0 + P.PMP_ENTRIES/4 & (P.XLEN==32 | CSRAdrM[0] == 0)) begin
|
||||
// only odd-numbered PMPCFG entries exist in RV64
|
||||
if (`XLEN==64) begin
|
||||
if (P.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]};
|
||||
@ -186,23 +184,23 @@ module csrm #(parameter
|
||||
MISA_ADR: CSRMReadValM = MISA_REGW;
|
||||
MVENDORID: CSRMReadValM = 0;
|
||||
MARCHID: CSRMReadValM = 0;
|
||||
MIMPID: CSRMReadValM = `XLEN'h100; // pipelined implementation
|
||||
MIMPID: CSRMReadValM = {{P.XLEN-12{1'b0}}, 12'h100}; // pipelined implementation
|
||||
MHARTID: CSRMReadValM = MHARTID_REGW; // hardwired to 0
|
||||
MCONFIGPTR: CSRMReadValM = 0; // hardwired to 0
|
||||
MSTATUS: CSRMReadValM = MSTATUS_REGW;
|
||||
MSTATUSH: CSRMReadValM = MSTATUSH_REGW;
|
||||
MTVEC: CSRMReadValM = MTVEC_REGW;
|
||||
MEDELEG: CSRMReadValM = {{(`XLEN-16){1'b0}}, MEDELEG_REGW};
|
||||
MIDELEG: CSRMReadValM = {{(`XLEN-12){1'b0}}, MIDELEG_REGW};
|
||||
MIP: CSRMReadValM = {{(`XLEN-12){1'b0}}, MIP_REGW};
|
||||
MIE: CSRMReadValM = {{(`XLEN-12){1'b0}}, MIE_REGW};
|
||||
MEDELEG: CSRMReadValM = {{(P.XLEN-16){1'b0}}, MEDELEG_REGW};
|
||||
MIDELEG: CSRMReadValM = {{(P.XLEN-12){1'b0}}, MIDELEG_REGW};
|
||||
MIP: CSRMReadValM = {{(P.XLEN-12){1'b0}}, MIP_REGW};
|
||||
MIE: CSRMReadValM = {{(P.XLEN-12){1'b0}}, MIE_REGW};
|
||||
MSCRATCH: CSRMReadValM = MSCRATCH_REGW;
|
||||
MEPC: CSRMReadValM = MEPC_REGW;
|
||||
MCAUSE: CSRMReadValM = MCAUSE_REGW;
|
||||
MTVAL: CSRMReadValM = MTVAL_REGW;
|
||||
MTINST: CSRMReadValM = 0; // implemented as trivial zero
|
||||
MCOUNTEREN:CSRMReadValM = {{(`XLEN-32){1'b0}}, MCOUNTEREN_REGW};
|
||||
MCOUNTINHIBIT:CSRMReadValM = {{(`XLEN-32){1'b0}}, MCOUNTINHIBIT_REGW};
|
||||
MCOUNTEREN:CSRMReadValM = {{(P.XLEN-32){1'b0}}, MCOUNTEREN_REGW};
|
||||
MCOUNTINHIBIT:CSRMReadValM = {{(P.XLEN-32){1'b0}}, MCOUNTINHIBIT_REGW};
|
||||
|
||||
default: begin
|
||||
CSRMReadValM = 0;
|
||||
|
@ -28,9 +28,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module csrs #(parameter
|
||||
module csrs import cvw::*; #(parameter cvw_t P,
|
||||
// Supervisor CSRs
|
||||
SSTATUS = 12'h100,
|
||||
SIE = 12'h104,
|
||||
@ -47,16 +45,16 @@ module csrs #(parameter
|
||||
input logic clk, reset,
|
||||
input logic CSRSWriteM, STrapM,
|
||||
input logic [11:0] CSRAdrM,
|
||||
input logic [`XLEN-1:0] NextEPCM, NextMtvalM, SSTATUS_REGW,
|
||||
input logic [P.XLEN-1:0] NextEPCM, NextMtvalM, SSTATUS_REGW,
|
||||
input logic [4:0] NextCauseM,
|
||||
input logic STATUS_TVM,
|
||||
input logic MCOUNTEREN_TM, // TM bit (1) of MCOUNTEREN; cause illegal instruction when trying to access STIMECMP if clear
|
||||
input logic [`XLEN-1:0] CSRWriteValM,
|
||||
input logic [P.XLEN-1:0] CSRWriteValM,
|
||||
input logic [1:0] PrivilegeModeW,
|
||||
output logic [`XLEN-1:0] CSRSReadValM, STVEC_REGW,
|
||||
output logic [`XLEN-1:0] SEPC_REGW,
|
||||
output logic [P.XLEN-1:0] CSRSReadValM, STVEC_REGW,
|
||||
output logic [P.XLEN-1:0] SEPC_REGW,
|
||||
output logic [31:0] SCOUNTEREN_REGW,
|
||||
output logic [`XLEN-1:0] SATP_REGW,
|
||||
output logic [P.XLEN-1:0] SATP_REGW,
|
||||
input logic [11:0] MIP_REGW, MIE_REGW, MIDELEG_REGW,
|
||||
input logic [63:0] MTIME_CLINT,
|
||||
output logic WriteSSTATUSM,
|
||||
@ -65,14 +63,14 @@ module csrs #(parameter
|
||||
);
|
||||
|
||||
// Constants
|
||||
localparam ZERO = {(`XLEN){1'b0}};
|
||||
localparam SEDELEG_MASK = ~(ZERO | `XLEN'b111 << 9);
|
||||
localparam ZERO = {(P.XLEN){1'b0}};
|
||||
localparam SEDELEG_MASK = ~(ZERO | {{P.XLEN-3{1'b0}}, 3'b111} << 9);
|
||||
|
||||
logic WriteSTVECM;
|
||||
logic WriteSSCRATCHM, WriteSEPCM;
|
||||
logic WriteSCAUSEM, WriteSTVALM, WriteSATPM, WriteSCOUNTERENM;
|
||||
logic WriteSTIMECMPM, WriteSTIMECMPHM;
|
||||
logic [`XLEN-1:0] SSCRATCH_REGW, STVAL_REGW, SCAUSE_REGW;
|
||||
logic [P.XLEN-1:0] SSCRATCH_REGW, STVAL_REGW, SCAUSE_REGW;
|
||||
logic [63:0] STIMECMP_REGW;
|
||||
|
||||
// write enables
|
||||
@ -82,34 +80,34 @@ module csrs #(parameter
|
||||
assign WriteSEPCM = STrapM | (CSRSWriteM & (CSRAdrM == SEPC));
|
||||
assign WriteSCAUSEM = STrapM | (CSRSWriteM & (CSRAdrM == SCAUSE));
|
||||
assign WriteSTVALM = STrapM | (CSRSWriteM & (CSRAdrM == STVAL));
|
||||
assign WriteSATPM = CSRSWriteM & (CSRAdrM == SATP) & (PrivilegeModeW == `M_MODE | ~STATUS_TVM);
|
||||
assign WriteSATPM = CSRSWriteM & (CSRAdrM == SATP) & (PrivilegeModeW == P.M_MODE | ~STATUS_TVM);
|
||||
assign WriteSCOUNTERENM = CSRSWriteM & (CSRAdrM == SCOUNTEREN);
|
||||
assign WriteSTIMECMPM = CSRSWriteM & (CSRAdrM == STIMECMP) & (PrivilegeModeW == `M_MODE | MCOUNTEREN_TM);
|
||||
assign WriteSTIMECMPHM = CSRSWriteM & (CSRAdrM == STIMECMPH) & (PrivilegeModeW == `M_MODE | MCOUNTEREN_TM) & (`XLEN == 32);
|
||||
assign WriteSTIMECMPM = CSRSWriteM & (CSRAdrM == STIMECMP) & (PrivilegeModeW == P.M_MODE | MCOUNTEREN_TM);
|
||||
assign WriteSTIMECMPHM = CSRSWriteM & (CSRAdrM == STIMECMPH) & (PrivilegeModeW == P.M_MODE | MCOUNTEREN_TM) & (P.XLEN == 32);
|
||||
|
||||
// CSRs
|
||||
flopenr #(`XLEN) STVECreg(clk, reset, WriteSTVECM, {CSRWriteValM[`XLEN-1:2], 1'b0, CSRWriteValM[0]}, STVEC_REGW);
|
||||
flopenr #(`XLEN) SSCRATCHreg(clk, reset, WriteSSCRATCHM, CSRWriteValM, SSCRATCH_REGW);
|
||||
flopenr #(`XLEN) SEPCreg(clk, reset, WriteSEPCM, NextEPCM, SEPC_REGW);
|
||||
flopenr #(`XLEN) SCAUSEreg(clk, reset, WriteSCAUSEM, {NextCauseM[4], {(`XLEN-5){1'b0}}, NextCauseM[3:0]}, SCAUSE_REGW);
|
||||
flopenr #(`XLEN) STVALreg(clk, reset, WriteSTVALM, NextMtvalM, STVAL_REGW);
|
||||
if (`VIRTMEM_SUPPORTED)
|
||||
flopenr #(`XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW);
|
||||
flopenr #(P.XLEN) STVECreg(clk, reset, WriteSTVECM, {CSRWriteValM[P.XLEN-1:2], 1'b0, CSRWriteValM[0]}, STVEC_REGW);
|
||||
flopenr #(P.XLEN) SSCRATCHreg(clk, reset, WriteSSCRATCHM, CSRWriteValM, SSCRATCH_REGW);
|
||||
flopenr #(P.XLEN) SEPCreg(clk, reset, WriteSEPCM, NextEPCM, SEPC_REGW);
|
||||
flopenr #(P.XLEN) SCAUSEreg(clk, reset, WriteSCAUSEM, {NextCauseM[4], {(P.XLEN-5){1'b0}}, NextCauseM[3:0]}, SCAUSE_REGW);
|
||||
flopenr #(P.XLEN) STVALreg(clk, reset, WriteSTVALM, NextMtvalM, STVAL_REGW);
|
||||
if (P.VIRTMEM_SUPPORTED)
|
||||
flopenr #(P.XLEN) SATPreg(clk, reset, WriteSATPM, CSRWriteValM, SATP_REGW);
|
||||
else
|
||||
assign SATP_REGW = 0; // hardwire to zero if virtual memory not supported
|
||||
flopenr #(32) SCOUNTERENreg(clk, reset, WriteSCOUNTERENM, CSRWriteValM[31:0], SCOUNTEREN_REGW);
|
||||
if (`SSTC_SUPPORTED) begin : sstc
|
||||
if (`XLEN == 64) begin : sstc64
|
||||
flopenl #(`XLEN) STIMECMPreg(clk, reset, WriteSTIMECMPM, CSRWriteValM, 64'hFFFFFFFFFFFFFFFF, STIMECMP_REGW);
|
||||
if (P.SSTC_SUPPORTED) begin : sstc
|
||||
if (P.XLEN == 64) begin : sstc64
|
||||
flopenl #(P.XLEN) STIMECMPreg(clk, reset, WriteSTIMECMPM, CSRWriteValM, 64'hFFFFFFFFFFFFFFFF, STIMECMP_REGW);
|
||||
end else begin : sstc32
|
||||
flopenl #(`XLEN) STIMECMPreg(clk, reset, WriteSTIMECMPM, CSRWriteValM, 32'hFFFFFFFF, STIMECMP_REGW[31:0]);
|
||||
flopenl #(`XLEN) STIMECMPHreg(clk, reset, WriteSTIMECMPHM, CSRWriteValM, 32'hFFFFFFFF, STIMECMP_REGW[63:32]);
|
||||
flopenl #(P.XLEN) STIMECMPreg(clk, reset, WriteSTIMECMPM, CSRWriteValM, 32'hFFFFFFFF, STIMECMP_REGW[31:0]);
|
||||
flopenl #(P.XLEN) STIMECMPHreg(clk, reset, WriteSTIMECMPHM, CSRWriteValM, 32'hFFFFFFFF, STIMECMP_REGW[63:32]);
|
||||
end
|
||||
end else assign STIMECMP_REGW = 0;
|
||||
|
||||
// Supervisor timer interrupt logic
|
||||
// Spec is a bit peculiar - Machine timer interrupts are produced in CLINT, while Supervisor timer interrupts are in CSRs
|
||||
if (`SSTC_SUPPORTED)
|
||||
if (P.SSTC_SUPPORTED)
|
||||
assign STimerInt = ({1'b0, MTIME_CLINT} >= {1'b0, STIMECMP_REGW}); // unsigned comparison
|
||||
else
|
||||
assign STimerInt = 0;
|
||||
@ -120,24 +118,24 @@ module csrs #(parameter
|
||||
case (CSRAdrM)
|
||||
SSTATUS: CSRSReadValM = SSTATUS_REGW;
|
||||
STVEC: CSRSReadValM = STVEC_REGW;
|
||||
SIP: CSRSReadValM = {{(`XLEN-12){1'b0}}, MIP_REGW & 12'h222 & MIDELEG_REGW}; // only read supervisor fields
|
||||
SIE: CSRSReadValM = {{(`XLEN-12){1'b0}}, MIE_REGW & 12'h222 & MIDELEG_REGW}; // only read supervisor fields
|
||||
SIP: CSRSReadValM = {{(P.XLEN-12){1'b0}}, MIP_REGW & 12'h222 & MIDELEG_REGW}; // only read supervisor fields
|
||||
SIE: CSRSReadValM = {{(P.XLEN-12){1'b0}}, MIE_REGW & 12'h222 & MIDELEG_REGW}; // only read supervisor fields
|
||||
SSCRATCH: CSRSReadValM = SSCRATCH_REGW;
|
||||
SEPC: CSRSReadValM = SEPC_REGW;
|
||||
SCAUSE: CSRSReadValM = SCAUSE_REGW;
|
||||
STVAL: CSRSReadValM = STVAL_REGW;
|
||||
SATP: if (`VIRTMEM_SUPPORTED & (PrivilegeModeW == `M_MODE | ~STATUS_TVM)) CSRSReadValM = SATP_REGW;
|
||||
SATP: if (P.VIRTMEM_SUPPORTED & (PrivilegeModeW == P.M_MODE | ~STATUS_TVM)) CSRSReadValM = SATP_REGW;
|
||||
else begin
|
||||
CSRSReadValM = 0;
|
||||
IllegalCSRSAccessM = 1;
|
||||
end
|
||||
SCOUNTEREN:CSRSReadValM = {{(`XLEN-32){1'b0}}, SCOUNTEREN_REGW};
|
||||
STIMECMP: if (`SSTC_SUPPORTED & (PrivilegeModeW == `M_MODE | MCOUNTEREN_TM)) CSRSReadValM = STIMECMP_REGW[`XLEN-1:0];
|
||||
SCOUNTEREN:CSRSReadValM = {{(P.XLEN-32){1'b0}}, SCOUNTEREN_REGW};
|
||||
STIMECMP: if (P.SSTC_SUPPORTED & (PrivilegeModeW == P.M_MODE | MCOUNTEREN_TM)) CSRSReadValM = STIMECMP_REGW[P.XLEN-1:0];
|
||||
else begin
|
||||
CSRSReadValM = 0;
|
||||
IllegalCSRSAccessM = 1;
|
||||
end
|
||||
STIMECMPH: if (`SSTC_SUPPORTED & (`XLEN == 32) & (PrivilegeModeW == `M_MODE | MCOUNTEREN_TM)) CSRSReadValM[31:0] = STIMECMP_REGW[63:32];
|
||||
STIMECMPH: if (P.SSTC_SUPPORTED & (P.XLEN == 32) & (PrivilegeModeW == P.M_MODE | MCOUNTEREN_TM)) CSRSReadValM[31:0] = STIMECMP_REGW[63:32];
|
||||
else begin // not supported for RV64
|
||||
CSRSReadValM = 0;
|
||||
IllegalCSRSAccessM = 1;
|
||||
|
@ -27,18 +27,16 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module csrsr (
|
||||
module csrsr import cvw::*; #(parameter cvw_t P) (
|
||||
input logic clk, reset, StallW,
|
||||
input logic WriteMSTATUSM, WriteMSTATUSHM, WriteSSTATUSM,
|
||||
input logic TrapM, FRegWriteM,
|
||||
input logic [1:0] NextPrivilegeModeM, PrivilegeModeW,
|
||||
input logic mretM, sretM,
|
||||
input logic WriteFRMM, WriteFFLAGSM,
|
||||
input logic [`XLEN-1:0] CSRWriteValM,
|
||||
input logic [P.XLEN-1:0] CSRWriteValM,
|
||||
input logic SelHPTW,
|
||||
output logic [`XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, MSTATUSH_REGW,
|
||||
output logic [P.XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, MSTATUSH_REGW,
|
||||
output logic [1:0] STATUS_MPP,
|
||||
output logic STATUS_SPP, STATUS_TSR, STATUS_TW,
|
||||
output logic STATUS_MIE, STATUS_SIE,
|
||||
@ -57,13 +55,13 @@ module csrsr (
|
||||
// See Privileged Spec Section 3.1.6
|
||||
// Lower privilege status registers are a subset of the full status register
|
||||
// *** consider adding MBE, SBE, UBE fields, parameterized to be fixed or adjustable
|
||||
if (`XLEN==64) begin: csrsr64 // RV64
|
||||
if (P.XLEN==64) begin: csrsr64 // RV64
|
||||
assign MSTATUS_REGW = {STATUS_SD, 25'b0, STATUS_MBE, STATUS_SBE, STATUS_SXL, STATUS_UXL, 9'b0,
|
||||
STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
STATUS_XS, STATUS_FS, STATUS_MPP, 2'b0,
|
||||
STATUS_SPP, STATUS_MPIE, STATUS_UBE, STATUS_SPIE, 1'b0,
|
||||
STATUS_MIE, 1'b0, STATUS_SIE, 1'b0};
|
||||
assign SSTATUS_REGW = {STATUS_SD, /*27'b0, */ 29'b0, /*STATUS_SXL, */ {`QEMU ? 2'b0 : STATUS_UXL}, /*9'b0, */ 12'b0,
|
||||
assign SSTATUS_REGW = {STATUS_SD, /*27'b0, */ 29'b0, /*STATUS_SXL, */ {P.QEMU ? 2'b0 : STATUS_UXL}, /*9'b0, */ 12'b0,
|
||||
/*STATUS_TSR, STATUS_TW, STATUS_TVM, */STATUS_MXR, STATUS_SUM, /* STATUS_MPRV, */ 1'b0,
|
||||
STATUS_XS, STATUS_FS, /*STATUS_MPP, 2'b0*/ 4'b0,
|
||||
STATUS_SPP, /*STATUS_MPIE*/ 1'b0, STATUS_UBE, STATUS_SPIE,
|
||||
@ -83,54 +81,54 @@ module csrsr (
|
||||
end
|
||||
|
||||
// extract values to write to upper status register on 64/32-bit access
|
||||
if (`XLEN==64) begin:upperstatus
|
||||
assign nextMBE = CSRWriteValM[37] & `BIGENDIAN_SUPPORTED;
|
||||
assign nextSBE = CSRWriteValM[36] & `S_SUPPORTED & `BIGENDIAN_SUPPORTED;
|
||||
if (P.XLEN==64) begin:upperstatus
|
||||
assign nextMBE = CSRWriteValM[37] & P.BIGENDIAN_SUPPORTED;
|
||||
assign nextSBE = CSRWriteValM[36] & P.S_SUPPORTED & P.BIGENDIAN_SUPPORTED;
|
||||
end else begin:upperstatus
|
||||
assign nextMBE = STATUS_MBE;
|
||||
assign nextSBE = STATUS_SBE;
|
||||
end
|
||||
|
||||
// harwired STATUS bits
|
||||
assign STATUS_TSR = `S_SUPPORTED & STATUS_TSR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_TW = (`S_SUPPORTED | `U_SUPPORTED) & STATUS_TW_INT; // override register with 0 if only machine mode supported
|
||||
assign STATUS_TVM = `S_SUPPORTED & STATUS_TVM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MXR = `S_SUPPORTED & STATUS_MXR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_TSR = P.S_SUPPORTED & STATUS_TSR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_TW = (P.S_SUPPORTED | P.U_SUPPORTED) & STATUS_TW_INT; // override register with 0 if only machine mode supported
|
||||
assign STATUS_TVM = P.S_SUPPORTED & STATUS_TVM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MXR = P.S_SUPPORTED & STATUS_MXR_INT; // override reigster with 0 if supervisor mode not supported
|
||||
/* assign STATUS_UBE = 0; // little-endian
|
||||
assign STATUS_SBE = 0; // little-endian
|
||||
assign STATUS_MBE = 0; // little-endian */
|
||||
// SXL and UXL bits only matter for RV64. Set to 10 for RV64 if mode is supported, or 0 if not
|
||||
assign STATUS_SXL = `S_SUPPORTED ? 2'b10 : 2'b00; // 10 if supervisor mode supported
|
||||
assign STATUS_UXL = `U_SUPPORTED ? 2'b10 : 2'b00; // 10 if user mode supported
|
||||
assign STATUS_SUM = `S_SUPPORTED & `VIRTMEM_SUPPORTED & STATUS_SUM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MPRV = `U_SUPPORTED & STATUS_MPRV_INT; // override with 0 if user mode not supported
|
||||
assign STATUS_FS = (`S_SUPPORTED & (`F_SUPPORTED | `D_SUPPORTED)) ? STATUS_FS_INT : 2'b00; // off if no FP
|
||||
assign STATUS_SXL = P.S_SUPPORTED ? 2'b10 : 2'b00; // 10 if supervisor mode supported
|
||||
assign STATUS_UXL = P.U_SUPPORTED ? 2'b10 : 2'b00; // 10 if user mode supported
|
||||
assign STATUS_SUM = P.S_SUPPORTED & P.VIRTMEM_SUPPORTED & STATUS_SUM_INT; // override reigster with 0 if supervisor mode not supported
|
||||
assign STATUS_MPRV = P.U_SUPPORTED & STATUS_MPRV_INT; // override with 0 if user mode not supported
|
||||
assign STATUS_FS = (P.S_SUPPORTED & (P.F_SUPPORTED | P.D_SUPPORTED)) ? STATUS_FS_INT : 2'b00; // off if no FP
|
||||
assign STATUS_SD = (STATUS_FS == 2'b11) | (STATUS_XS == 2'b11); // dirty state logic
|
||||
assign STATUS_XS = 2'b00; // No additional user-mode state to be dirty
|
||||
|
||||
always_comb
|
||||
if (CSRWriteValM[12:11] == `U_MODE & `U_SUPPORTED) STATUS_MPP_NEXT = `U_MODE;
|
||||
else if (CSRWriteValM[12:11] == `S_MODE & `S_SUPPORTED) STATUS_MPP_NEXT = `S_MODE;
|
||||
else STATUS_MPP_NEXT = `M_MODE;
|
||||
if (CSRWriteValM[12:11] == P.U_MODE & P.U_SUPPORTED) STATUS_MPP_NEXT = P.U_MODE;
|
||||
else if (CSRWriteValM[12:11] == P.S_MODE & P.S_SUPPORTED) STATUS_MPP_NEXT = P.S_MODE;
|
||||
else STATUS_MPP_NEXT = P.M_MODE;
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Endianness logic Privileged Spec 3.1.6.4
|
||||
///////////////////////////////////////////
|
||||
|
||||
if (`BIGENDIAN_SUPPORTED) begin: endianmux
|
||||
if (P.BIGENDIAN_SUPPORTED) begin: endianmux
|
||||
// determine whether big endian accesses should be made
|
||||
logic [1:0] EndiannessPrivMode;
|
||||
always_comb begin
|
||||
if (SelHPTW) EndiannessPrivMode = `S_MODE;
|
||||
if (SelHPTW) EndiannessPrivMode = P.S_MODE;
|
||||
//coverage off -item c 1 -feccondrow 1
|
||||
// status.MPRV always gets reset upon leaving machine mode, so MPRV will never be high when out of machine mode
|
||||
else if (PrivilegeModeW == `M_MODE & STATUS_MPRV) EndiannessPrivMode = STATUS_MPP;
|
||||
else if (PrivilegeModeW == P.M_MODE & STATUS_MPRV) EndiannessPrivMode = STATUS_MPP;
|
||||
//coverage on
|
||||
else EndiannessPrivMode = PrivilegeModeW;
|
||||
|
||||
case (EndiannessPrivMode)
|
||||
`M_MODE: BigEndianM = STATUS_MBE;
|
||||
`S_MODE: BigEndianM = STATUS_SBE;
|
||||
P.M_MODE: BigEndianM = STATUS_MBE;
|
||||
P.S_MODE: BigEndianM = STATUS_SBE;
|
||||
default: BigEndianM = STATUS_UBE;
|
||||
endcase
|
||||
end
|
||||
@ -148,7 +146,7 @@ module csrsr (
|
||||
STATUS_MXR_INT <= #1 0;
|
||||
STATUS_SUM_INT <= #1 0;
|
||||
STATUS_MPRV_INT <= #1 0; // Per Priv 3.3
|
||||
STATUS_FS_INT <= #1 `F_SUPPORTED ? 2'b00 : 2'b00; // leave floating-point off until activated, even if F_SUPPORTED
|
||||
STATUS_FS_INT <= #1 P.F_SUPPORTED ? 2'b00 : 2'b00; // leave floating-point off until activated, even if F_SUPPORTED
|
||||
STATUS_MPP <= #1 0;
|
||||
STATUS_SPP <= #1 0;
|
||||
STATUS_MPIE <= #1 0;
|
||||
@ -164,7 +162,7 @@ module csrsr (
|
||||
// y = PrivilegeModeW
|
||||
// x = NextPrivilegeModeM
|
||||
// Modes: 11 = Machine, 01 = Supervisor, 00 = User
|
||||
if (NextPrivilegeModeM == `M_MODE) begin
|
||||
if (NextPrivilegeModeM == P.M_MODE) begin
|
||||
STATUS_MPIE <= #1 STATUS_MIE;
|
||||
STATUS_MIE <= #1 0;
|
||||
STATUS_MPP <= #1 PrivilegeModeW;
|
||||
@ -176,11 +174,11 @@ module csrsr (
|
||||
end else if (mretM) begin // Privileged 3.1.6.1
|
||||
STATUS_MIE <= #1 STATUS_MPIE; // restore global interrupt enable
|
||||
STATUS_MPIE <= #1 1; //
|
||||
STATUS_MPP <= #1 `U_SUPPORTED ? `U_MODE : `M_MODE; // set MPP to lowest supported privilege level
|
||||
STATUS_MPRV_INT <= #1 STATUS_MPRV_INT & (STATUS_MPP == `M_MODE); // page 21 of privileged spec.
|
||||
STATUS_MPP <= #1 P.U_SUPPORTED ? P.U_MODE : P.M_MODE; // set MPP to lowest supported privilege level
|
||||
STATUS_MPRV_INT <= #1 STATUS_MPRV_INT & (STATUS_MPP == P.M_MODE); // page 21 of privileged spec.
|
||||
end else if (sretM) begin
|
||||
STATUS_SIE <= #1 STATUS_SPIE; // restore global interrupt enable
|
||||
STATUS_SPIE <= #1 `S_SUPPORTED;
|
||||
STATUS_SPIE <= #1 P.S_SUPPORTED;
|
||||
STATUS_SPP <= #1 0; // set SPP to lowest supported privilege level to catch bugs
|
||||
STATUS_MPRV_INT <= #1 0; // always clear MPRV
|
||||
end else if (WriteMSTATUSM) begin
|
||||
@ -192,28 +190,28 @@ module csrsr (
|
||||
STATUS_MPRV_INT <= #1 CSRWriteValM[17];
|
||||
STATUS_FS_INT <= #1 CSRWriteValM[14:13];
|
||||
STATUS_MPP <= #1 STATUS_MPP_NEXT;
|
||||
STATUS_SPP <= #1 `S_SUPPORTED & CSRWriteValM[8];
|
||||
STATUS_SPP <= #1 P.S_SUPPORTED & CSRWriteValM[8];
|
||||
STATUS_MPIE <= #1 CSRWriteValM[7];
|
||||
STATUS_SPIE <= #1 `S_SUPPORTED & CSRWriteValM[5];
|
||||
STATUS_SPIE <= #1 P.S_SUPPORTED & CSRWriteValM[5];
|
||||
STATUS_MIE <= #1 CSRWriteValM[3];
|
||||
STATUS_SIE <= #1 `S_SUPPORTED & CSRWriteValM[1];
|
||||
STATUS_UBE <= #1 CSRWriteValM[6] & `U_SUPPORTED & `BIGENDIAN_SUPPORTED;
|
||||
STATUS_SIE <= #1 P.S_SUPPORTED & CSRWriteValM[1];
|
||||
STATUS_UBE <= #1 CSRWriteValM[6] & P.U_SUPPORTED & P.BIGENDIAN_SUPPORTED;
|
||||
STATUS_MBE <= #1 nextMBE;
|
||||
STATUS_SBE <= #1 nextSBE;
|
||||
// coverage off
|
||||
// MSTATUSH only exists in 32-bit configurations, will not be hit on rv64gc
|
||||
end else if (WriteMSTATUSHM) begin
|
||||
STATUS_MBE <= #1 CSRWriteValM[5] & `BIGENDIAN_SUPPORTED;
|
||||
STATUS_SBE <= #1 CSRWriteValM[4] & `S_SUPPORTED & `BIGENDIAN_SUPPORTED;
|
||||
STATUS_MBE <= #1 CSRWriteValM[5] & P.BIGENDIAN_SUPPORTED;
|
||||
STATUS_SBE <= #1 CSRWriteValM[4] & P.S_SUPPORTED & P.BIGENDIAN_SUPPORTED;
|
||||
// coverage on
|
||||
end else if (WriteSSTATUSM) begin // write a subset of the STATUS bits
|
||||
STATUS_MXR_INT <= #1 CSRWriteValM[19];
|
||||
STATUS_SUM_INT <= #1 CSRWriteValM[18];
|
||||
STATUS_FS_INT <= #1 CSRWriteValM[14:13];
|
||||
STATUS_SPP <= #1 `S_SUPPORTED & CSRWriteValM[8];
|
||||
STATUS_SPIE <= #1 `S_SUPPORTED & CSRWriteValM[5];
|
||||
STATUS_SIE <= #1 `S_SUPPORTED & CSRWriteValM[1];
|
||||
STATUS_UBE <= #1 CSRWriteValM[6] & `U_SUPPORTED & `BIGENDIAN_SUPPORTED;
|
||||
STATUS_SPP <= #1 P.S_SUPPORTED & CSRWriteValM[8];
|
||||
STATUS_SPIE <= #1 P.S_SUPPORTED & CSRWriteValM[5];
|
||||
STATUS_SIE <= #1 P.S_SUPPORTED & CSRWriteValM[1];
|
||||
STATUS_UBE <= #1 CSRWriteValM[6] & P.U_SUPPORTED & P.BIGENDIAN_SUPPORTED;
|
||||
end else if (FRegWriteM | WriteFRMM | WriteFFLAGSM) STATUS_FS_INT <= #1 2'b11;
|
||||
end
|
||||
endmodule
|
||||
|
@ -26,9 +26,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module csru #(parameter
|
||||
module csru import cvw::*; #(parameter cvw_t P,
|
||||
FFLAGS = 12'h001,
|
||||
FRM = 12'h002,
|
||||
FCSR = 12'h003) (
|
||||
@ -36,9 +34,9 @@ module csru #(parameter
|
||||
input logic InstrValidNotFlushedM,
|
||||
input logic CSRUWriteM,
|
||||
input logic [11:0] CSRAdrM,
|
||||
input logic [`XLEN-1:0] CSRWriteValM,
|
||||
input logic [P.XLEN-1:0] CSRWriteValM,
|
||||
input logic [1:0] STATUS_FS,
|
||||
output logic [`XLEN-1:0] CSRUReadValM,
|
||||
output logic [P.XLEN-1:0] CSRUReadValM,
|
||||
input logic [4:0] SetFflagsM,
|
||||
output logic [2:0] FRM_REGW,
|
||||
output logic WriteFRMM, WriteFFLAGSM,
|
||||
@ -71,9 +69,9 @@ module csru #(parameter
|
||||
end else begin
|
||||
IllegalCSRUAccessM = 0;
|
||||
case (CSRAdrM)
|
||||
FFLAGS: CSRUReadValM = {{(`XLEN-5){1'b0}}, FFLAGS_REGW};
|
||||
FRM: CSRUReadValM = {{(`XLEN-3){1'b0}}, FRM_REGW};
|
||||
FCSR: CSRUReadValM = {{(`XLEN-8){1'b0}}, FRM_REGW, FFLAGS_REGW};
|
||||
FFLAGS: CSRUReadValM = {{(P.XLEN-5){1'b0}}, FFLAGS_REGW};
|
||||
FRM: CSRUReadValM = {{(P.XLEN-3){1'b0}}, FRM_REGW};
|
||||
FCSR: CSRUReadValM = {{(P.XLEN-8){1'b0}}, FRM_REGW, FFLAGS_REGW};
|
||||
default: begin
|
||||
CSRUReadValM = 0;
|
||||
IllegalCSRUAccessM = 1;
|
||||
|
@ -27,9 +27,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module privdec (
|
||||
module privdec import cvw::*; #(parameter cvw_t P) (
|
||||
input logic clk, reset,
|
||||
input logic StallM,
|
||||
input logic [31:20] InstrM, // privileged instruction function field
|
||||
@ -52,26 +50,26 @@ module privdec (
|
||||
// Decode privileged instructions
|
||||
///////////////////////////////////////////
|
||||
|
||||
assign sretM = PrivilegedM & (InstrM[31:20] == 12'b000100000010) & `S_SUPPORTED &
|
||||
(PrivilegeModeW == `M_MODE | PrivilegeModeW == `S_MODE & ~STATUS_TSR);
|
||||
assign mretM = PrivilegedM & (InstrM[31:20] == 12'b001100000010) & (PrivilegeModeW == `M_MODE);
|
||||
assign sretM = PrivilegedM & (InstrM[31:20] == 12'b000100000010) & P.S_SUPPORTED &
|
||||
(PrivilegeModeW == P.M_MODE | PrivilegeModeW == P.S_MODE & ~STATUS_TSR);
|
||||
assign mretM = PrivilegedM & (InstrM[31:20] == 12'b001100000010) & (PrivilegeModeW == P.M_MODE);
|
||||
assign ecallM = PrivilegedM & (InstrM[31:20] == 12'b000000000000);
|
||||
assign ebreakM = PrivilegedM & (InstrM[31:20] == 12'b000000000001);
|
||||
assign wfiM = PrivilegedM & (InstrM[31:20] == 12'b000100000101);
|
||||
assign sfencevmaM = PrivilegedM & (InstrM[31:25] == 7'b0001001) &
|
||||
(PrivilegeModeW == `M_MODE | (PrivilegeModeW == `S_MODE & ~STATUS_TVM));
|
||||
(PrivilegeModeW == P.M_MODE | (PrivilegeModeW == P.S_MODE & ~STATUS_TVM));
|
||||
|
||||
///////////////////////////////////////////
|
||||
// WFI timeout Privileged Spec 3.1.6.5
|
||||
///////////////////////////////////////////
|
||||
|
||||
if (`U_SUPPORTED) begin:wfi
|
||||
logic [`WFI_TIMEOUT_BIT:0] WFICount, WFICountPlus1;
|
||||
if (P.U_SUPPORTED) begin:wfi
|
||||
logic [P.WFI_TIMEOUT_BIT:0] WFICount, WFICountPlus1;
|
||||
assign WFICountPlus1 = WFICount + 1;
|
||||
floprc #(`WFI_TIMEOUT_BIT+1) wficountreg(clk, reset, ~wfiM, WFICountPlus1, WFICount); // count while in WFI
|
||||
floprc #(P.WFI_TIMEOUT_BIT+1) wficountreg(clk, reset, ~wfiM, WFICountPlus1, WFICount); // count while in WFI
|
||||
// coverage off -item e 1 -fecexprrow 1
|
||||
// WFI Timout trap will not occur when STATUS_TW is low while in supervisor mode, so the system gets stuck waiting for an interrupt and triggers a watchdog timeout.
|
||||
assign WFITimeoutM = ((STATUS_TW & PrivilegeModeW != `M_MODE) | (`S_SUPPORTED & PrivilegeModeW == `U_MODE)) & WFICount[`WFI_TIMEOUT_BIT];
|
||||
assign WFITimeoutM = ((STATUS_TW & PrivilegeModeW != P.M_MODE) | (P.S_SUPPORTED & PrivilegeModeW == P.U_MODE)) & WFICount[P.WFI_TIMEOUT_BIT];
|
||||
// coverage on
|
||||
end else assign WFITimeoutM = 0;
|
||||
|
||||
|
@ -27,19 +27,17 @@
|
||||
// SOFTWARE.
|
||||
///////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module privileged (
|
||||
module privileged import cvw::*; #(parameter cvw_t P) (
|
||||
input logic clk, reset,
|
||||
input logic StallD, StallE, StallM, StallW,
|
||||
input logic FlushD, FlushE, FlushM, FlushW,
|
||||
// CSR Reads and Writes, and values needed for traps
|
||||
input logic CSRReadM, CSRWriteM, // Read or write CSRs
|
||||
input logic [`XLEN-1:0] SrcAM, // GPR register to write
|
||||
input logic [P.XLEN-1:0] SrcAM, // GPR register to write
|
||||
input logic [31:0] InstrM, // Instruction
|
||||
input logic [31:0] InstrOrigM, // Original compressed or uncompressed instruction in Memory stage for Illegal Instruction MTVAL
|
||||
input logic [`XLEN-1:0] IEUAdrM, // address from IEU
|
||||
input logic [`XLEN-1:0] PCM, PC2NextF, // program counter, next PC going to trap/return PC logic
|
||||
input logic [P.XLEN-1:0] IEUAdrM, // address from IEU
|
||||
input logic [P.XLEN-1:0] PCM, PC2NextF, // program counter, next PC going to trap/return PC logic
|
||||
// control signals
|
||||
input logic InstrValidM, // Current instruction is valid (not flushed)
|
||||
input logic CommittedM, CommittedF, // current instruction is using bus; don't interrupt
|
||||
@ -76,16 +74,16 @@ module privileged (
|
||||
input logic [4:0] SetFflagsM, // set FCSR flags from FPU
|
||||
input logic SelHPTW, // HPTW in use. Causes system to use S-mode endianness for accesses
|
||||
// CSR outputs
|
||||
output logic [`XLEN-1:0] CSRReadValW, // Value read from CSR
|
||||
output logic [P.XLEN-1:0] CSRReadValW, // Value read from CSR
|
||||
output logic [1:0] PrivilegeModeW, // current privilege mode
|
||||
output logic [`XLEN-1:0] SATP_REGW, // supervisor address translation register
|
||||
output logic [P.XLEN-1:0] SATP_REGW, // supervisor address translation register
|
||||
output logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, // status register bits
|
||||
output logic [1:0] STATUS_MPP, STATUS_FS, // status register bits
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0], // PMP configuration entries to MMU
|
||||
output var logic [`PA_BITS-3:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0], // PMP address entries to MMU
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0], // PMP configuration entries to MMU
|
||||
output var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW [P.PMP_ENTRIES-1:0], // PMP address entries to MMU
|
||||
output logic [2:0] FRM_REGW, // FPU rounding mode
|
||||
// PC logic output in privileged unit
|
||||
output logic [`XLEN-1:0] UnalignedPCNextF, // Next PC from trap/return PC logic
|
||||
output logic [P.XLEN-1:0] UnalignedPCNextF, // Next PC from trap/return PC logic
|
||||
// control outputs
|
||||
output logic RetM, TrapM, // return instruction, or trap
|
||||
output logic sfencevmaM, // sfence.vma instruction
|
||||
@ -116,17 +114,17 @@ module privileged (
|
||||
|
||||
|
||||
// track the current privilege level
|
||||
privmode privmode(.clk, .reset, .StallW, .TrapM, .mretM, .sretM, .DelegateM,
|
||||
privmode #(P) privmode(.clk, .reset, .StallW, .TrapM, .mretM, .sretM, .DelegateM,
|
||||
.STATUS_MPP, .STATUS_SPP, .NextPrivilegeModeM, .PrivilegeModeW);
|
||||
|
||||
// decode privileged instructions
|
||||
privdec pmd(.clk, .reset, .StallM, .InstrM(InstrM[31:20]),
|
||||
privdec #(P) pmd(.clk, .reset, .StallM, .InstrM(InstrM[31:20]),
|
||||
.PrivilegedM, .IllegalIEUFPUInstrM, .IllegalCSRAccessM,
|
||||
.PrivilegeModeW, .STATUS_TSR, .STATUS_TVM, .STATUS_TW, .IllegalInstrFaultM,
|
||||
.EcallFaultM, .BreakpointFaultM, .sretM, .mretM, .wfiM, .sfencevmaM);
|
||||
|
||||
// Control and Status Registers
|
||||
csr csr(.clk, .reset, .FlushM, .FlushW, .StallE, .StallM, .StallW,
|
||||
csr #(P) csr(.clk, .reset, .FlushM, .FlushW, .StallE, .StallM, .StallW,
|
||||
.InstrM, .InstrOrigM, .PCM, .SrcAM, .IEUAdrM, .PC2NextF,
|
||||
.CSRReadM, .CSRWriteM, .TrapM, .mretM, .sretM, .wfiM, .IntPendingM, .InterruptM,
|
||||
.MTimerInt, .MExtInt, .SExtInt, .MSwInt,
|
||||
@ -148,7 +146,7 @@ module privileged (
|
||||
.InstrPageFaultM, .InstrAccessFaultM, .HPTWInstrAccessFaultM, .IllegalIEUFPUInstrM);
|
||||
|
||||
// trap logic
|
||||
trap trap(.reset,
|
||||
trap #(P) trap(.reset,
|
||||
.InstrMisalignedFaultM, .InstrAccessFaultM, .HPTWInstrAccessFaultM, .IllegalInstrFaultM,
|
||||
.BreakpointFaultM, .LoadMisalignedFaultM, .StoreAmoMisalignedFaultM,
|
||||
.LoadAccessFaultM, .StoreAmoAccessFaultM, .EcallFaultM, .InstrPageFaultM,
|
||||
|
@ -26,9 +26,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module privmode (
|
||||
module privmode import cvw::*; #(parameter cvw_t P) (
|
||||
input logic clk, reset,
|
||||
input logic StallW,
|
||||
input logic TrapM, // Trap
|
||||
@ -40,20 +38,20 @@ module privmode (
|
||||
output logic [1:0] PrivilegeModeW // current privilege mode
|
||||
);
|
||||
|
||||
if (`U_SUPPORTED) begin:privmode
|
||||
if (P.U_SUPPORTED) begin:privmode
|
||||
// PrivilegeMode FSM
|
||||
always_comb begin
|
||||
if (TrapM) begin // Change privilege based on DELEG registers (see 3.1.8)
|
||||
if (`S_SUPPORTED & DelegateM) NextPrivilegeModeM = `S_MODE;
|
||||
else NextPrivilegeModeM = `M_MODE;
|
||||
if (P.S_SUPPORTED & DelegateM) NextPrivilegeModeM = P.S_MODE;
|
||||
else NextPrivilegeModeM = P.M_MODE;
|
||||
end else if (mretM) NextPrivilegeModeM = STATUS_MPP;
|
||||
else if (sretM) NextPrivilegeModeM = {1'b0, STATUS_SPP};
|
||||
else NextPrivilegeModeM = PrivilegeModeW;
|
||||
end
|
||||
|
||||
flopenl #(2) privmodereg(clk, reset, ~StallW, NextPrivilegeModeM, `M_MODE, PrivilegeModeW);
|
||||
flopenl #(2) privmodereg(clk, reset, ~StallW, NextPrivilegeModeM, P.M_MODE, PrivilegeModeW);
|
||||
end else begin // only machine mode supported
|
||||
assign NextPrivilegeModeM = `M_MODE;
|
||||
assign PrivilegeModeW = `M_MODE;
|
||||
assign NextPrivilegeModeM = P.M_MODE;
|
||||
assign PrivilegeModeW = P.M_MODE;
|
||||
end
|
||||
endmodule
|
||||
endmodule
|
||||
|
@ -26,8 +26,6 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module privpiperegs (
|
||||
input logic clk, reset,
|
||||
input logic StallD, StallE, StallM,
|
||||
|
@ -26,9 +26,7 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module trap (
|
||||
module trap import cvw::*; #(parameter cvw_t P) (
|
||||
input logic reset,
|
||||
input logic InstrMisalignedFaultM, InstrAccessFaultM, HPTWInstrAccessFaultM, IllegalInstrFaultM,
|
||||
input logic BreakpointFaultM, LoadMisalignedFaultM, StoreAmoMisalignedFaultM,
|
||||
@ -63,16 +61,16 @@ module trap (
|
||||
// & with ~CommittedM to make sure MEPC isn't chosen so as to rerun the same instr twice
|
||||
///////////////////////////////////////////
|
||||
|
||||
assign MIntGlobalEnM = (PrivilegeModeW != `M_MODE) | STATUS_MIE; // if M ints enabled or lower priv 3.1.9
|
||||
assign SIntGlobalEnM = (PrivilegeModeW == `U_MODE) | ((PrivilegeModeW == `S_MODE) & STATUS_SIE); // if in lower priv mode, or if S ints enabled and not in higher priv mode 3.1.9
|
||||
assign MIntGlobalEnM = (PrivilegeModeW != P.M_MODE) | STATUS_MIE; // if M ints enabled or lower priv 3.1.9
|
||||
assign SIntGlobalEnM = (PrivilegeModeW == P.U_MODE) | ((PrivilegeModeW == P.S_MODE) & STATUS_SIE); // if in lower priv mode, or if S ints enabled and not in higher priv mode 3.1.9
|
||||
assign PendingIntsM = MIP_REGW & MIE_REGW;
|
||||
assign IntPendingM = |PendingIntsM;
|
||||
assign Committed = CommittedM | CommittedF;
|
||||
assign EnabledIntsM = ({12{MIntGlobalEnM}} & PendingIntsM & ~MIDELEG_REGW | {12{SIntGlobalEnM}} & PendingIntsM & MIDELEG_REGW);
|
||||
assign ValidIntsM = {12{~Committed}} & EnabledIntsM;
|
||||
assign InterruptM = (|ValidIntsM) & InstrValidM; // suppress interrupt if the memory system has partially processed a request.
|
||||
assign DelegateM = `S_SUPPORTED & (InterruptM ? MIDELEG_REGW[CauseM] : MEDELEG_REGW[CauseM]) &
|
||||
(PrivilegeModeW == `U_MODE | PrivilegeModeW == `S_MODE);
|
||||
assign DelegateM = P.S_SUPPORTED & (InterruptM ? MIDELEG_REGW[CauseM] : MEDELEG_REGW[CauseM]) &
|
||||
(PrivilegeModeW == P.U_MODE | PrivilegeModeW == P.S_MODE);
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Trigger Traps and RET
|
||||
|
@ -270,7 +270,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
// privileged unit
|
||||
if (P.ZICSR_SUPPORTED) begin:priv
|
||||
privileged priv(
|
||||
privileged #(P) priv(
|
||||
.clk, .reset,
|
||||
.FlushD, .FlushE, .FlushM, .FlushW, .StallD, .StallE, .StallM, .StallW,
|
||||
.CSRReadM, .CSRWriteM, .SrcAM, .PCM, .PC2NextF,
|
||||
|
Loading…
Reference in New Issue
Block a user