This commit is contained in:
David Harris 2021-05-04 01:19:57 -04:00
commit 45b0af497c
14 changed files with 5670 additions and 147 deletions

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,8 @@ vsim workopt -suppress 8852,12070
#do ./wave-dos/peripheral-waves.do #do ./wave-dos/peripheral-waves.do
do ./wave-dos/busybear-waves.do do ./wave-dos/busybear-waves.do
#do busy-mmu.do
#-- Run the Simulation #-- Run the Simulation
run -all run -all
##quit ##quit

View File

@ -21,7 +21,6 @@ add wave -hex /testbench/dut/hart/ifu/InstrRawD
add wave /testbench/CheckInstrD add wave /testbench/CheckInstrD
add wave /testbench/lastCheckInstrD add wave /testbench/lastCheckInstrD
add wave /testbench/speculative add wave /testbench/speculative
add wave /testbench/dut/hart/ifu/bpred/BPPredWrongE
add wave /testbench/lastPC2 add wave /testbench/lastPC2
add wave -divider add wave -divider
add wave -divider add wave -divider

View File

@ -58,7 +58,9 @@ module ahblite (
output logic [`XLEN-1:0] MMUReadPTE, output logic [`XLEN-1:0] MMUReadPTE,
output logic MMUReady, output logic MMUReady,
// Signals from PMA checker // Signals from PMA checker
input logic SquashAHBAccess, input logic SquashBusAccess,
// Signals to PMA checker (metadata of proposed access)
output logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM,
// Return from bus // Return from bus
output logic [`XLEN-1:0] ReadDataW, output logic [`XLEN-1:0] ReadDataW,
// AHB-Lite external signals // AHB-Lite external signals
@ -79,8 +81,7 @@ module ahblite (
output logic HWRITED, output logic HWRITED,
// Stalls // Stalls
output logic /*InstrUpdate, */DataStall, output logic /*InstrUpdate, */DataStall,
output logic MemAckW output logic MemAckW
// *** add a chip-level ready signal as part of handshake
); );
logic GrantData; logic GrantData;
@ -90,9 +91,6 @@ module ahblite (
logic IReady, DReady; logic IReady, DReady;
logic CaptureDataM,CapturedDataAvailable; logic CaptureDataM,CapturedDataAvailable;
// Describes type of access
logic Atomic, Execute, Write, Read;
assign HCLK = clk; assign HCLK = clk;
assign HRESETn = ~reset; assign HRESETn = ~reset;
@ -103,41 +101,54 @@ module ahblite (
// while an instruction read is occuring, the instruction read finishes before // while an instruction read is occuring, the instruction read finishes before
// the data access can take place. // the data access can take place.
import ahbliteState::*; import ahbliteState::*;
statetype BusState, NextBusState; statetype BusState, ProposedNextBusState, NextBusState;
flopenl #(.TYPE(statetype)) busreg(HCLK, ~HRESETn, 1'b1, NextBusState, IDLE, BusState); flopenl #(.TYPE(statetype)) busreg(HCLK, ~HRESETn, 1'b1, NextBusState, IDLE, BusState);
// *** If the SquashAHBAccess signal is high, we need to set NextBusState to IDLE. // This case statement computes the desired next state for the AHBlite,
// We could either have this case statement set a signal ProposedNextBusState, which gets // prioritizing address translations, then atomics, then data accesses, and
// used for NextBusState when we are not squashing. Alternatively, we could add a bunch of // finally instructions. This proposition controls HADDR so the PMA and PMP
// conditional statments below // checkers can determine whether the access is allowed. If not, the actual
// NextWalkerState is set to IDLE.
// *** This ability to squash accesses must be replicated by any bus
// interface that might be used in place of the ahblite.
always_comb always_comb
case (BusState) case (BusState)
IDLE: if (MMUTranslate) NextBusState = MMUTRANSLATE; IDLE: if (MMUTranslate) ProposedNextBusState = MMUTRANSLATE;
else if (AtomicMaskedM[1]) NextBusState = ATOMICREAD; else if (AtomicMaskedM[1]) ProposedNextBusState = ATOMICREAD;
else if (MemReadM) NextBusState = MEMREAD; // Memory has priority over instructions else if (MemReadM) ProposedNextBusState = MEMREAD; // Memory has priority over instructions
else if (MemWriteM) NextBusState = MEMWRITE; else if (MemWriteM) ProposedNextBusState = MEMWRITE;
else if (InstrReadF) NextBusState = INSTRREAD; else if (InstrReadF) ProposedNextBusState = INSTRREAD;
else NextBusState = IDLE; else ProposedNextBusState = IDLE;
MMUTRANSLATE: if (~HREADY) NextBusState = MMUTRANSLATE; MMUTRANSLATE: if (~HREADY) ProposedNextBusState = MMUTRANSLATE;
else NextBusState = IDLE; else ProposedNextBusState = IDLE;
ATOMICREAD: if (~HREADY) NextBusState = ATOMICREAD; ATOMICREAD: if (~HREADY) ProposedNextBusState = ATOMICREAD;
else NextBusState = ATOMICWRITE; else ProposedNextBusState = ATOMICWRITE;
ATOMICWRITE: if (~HREADY) NextBusState = ATOMICWRITE; ATOMICWRITE: if (~HREADY) ProposedNextBusState = ATOMICWRITE;
else if (InstrReadF) NextBusState = INSTRREAD; else if (InstrReadF) ProposedNextBusState = INSTRREAD;
else NextBusState = IDLE; else ProposedNextBusState = IDLE;
MEMREAD: if (~HREADY) NextBusState = MEMREAD; MEMREAD: if (~HREADY) ProposedNextBusState = MEMREAD;
else if (InstrReadF) NextBusState = INSTRREAD; else if (InstrReadF) ProposedNextBusState = INSTRREAD;
else NextBusState = IDLE; else ProposedNextBusState = IDLE;
MEMWRITE: if (~HREADY) NextBusState = MEMWRITE; MEMWRITE: if (~HREADY) ProposedNextBusState = MEMWRITE;
else if (InstrReadF) NextBusState = INSTRREAD; else if (InstrReadF) ProposedNextBusState = INSTRREAD;
else NextBusState = IDLE; else ProposedNextBusState = IDLE;
INSTRREAD: INSTRREAD: if (~HREADY) ProposedNextBusState = INSTRREAD;
if (~HREADY) NextBusState = INSTRREAD; else ProposedNextBusState = IDLE; // if (InstrReadF still high)
else NextBusState = IDLE; // if (InstrReadF still high) default: ProposedNextBusState = IDLE;
default: NextBusState = IDLE;
endcase endcase
// Determine access type (important for determining whether to fault)
assign AtomicAccessM = (ProposedNextBusState == ATOMICREAD) || (ProposedNextBusState == ATOMICWRITE);
assign ExecuteAccessF = (ProposedNextBusState == INSTRREAD);
assign WriteAccessM = (ProposedNextBusState == MEMWRITE) || (ProposedNextBusState == ATOMICWRITE);
assign ReadAccessM = (ProposedNextBusState == MEMREAD) || (ProposedNextBusState == ATOMICREAD) ||
(ProposedNextBusState == MMUTRANSLATE);
// The PMA and PMP checkers can decide to squash the access
assign NextBusState = (SquashBusAccess) ? IDLE : ProposedNextBusState;
// stall signals // stall signals
// Note that we need to extend both stalls when MMUTRANSLATE goes to idle, // Note that we need to extend both stalls when MMUTRANSLATE goes to idle,
// since translation might not be complete. // since translation might not be complete.
@ -148,16 +159,9 @@ module ahblite (
//assign #1 InstrStall = ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC) || //assign #1 InstrStall = ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC) ||
// MMUStall); // MMUStall);
// Determine access type (important for determining whether to fault)
assign Atomic = ((NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE));
assign Execute = ((NextBusState == INSTRREAD));
assign Write = ((NextBusState == MEMWRITE) || (NextBusState == ATOMICWRITE));
assign Read = ((NextBusState == MEMREAD) || (NextBusState == ATOMICREAD) ||
(NextBusState == MMUTRANSLATE));
// bus outputs // bus outputs
assign #1 GrantData = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE) || assign #1 GrantData = (ProposedNextBusState == MEMREAD) || (ProposedNextBusState == MEMWRITE) ||
(NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE); (ProposedNextBusState == ATOMICREAD) || (ProposedNextBusState == ATOMICWRITE);
assign #1 AccessAddress = (GrantData) ? MemPAdrM[31:0] : InstrPAdrF[31:0]; assign #1 AccessAddress = (GrantData) ? MemPAdrM[31:0] : InstrPAdrF[31:0];
assign #1 HADDR = (MMUTranslate) ? MMUPAdr[31:0] : AccessAddress; assign #1 HADDR = (MMUTranslate) ? MMUPAdr[31:0] : AccessAddress;
generate generate
@ -182,7 +186,7 @@ module ahblite (
// Route signals to Instruction and Data Caches // Route signals to Instruction and Data Caches
// *** assumes AHBW = XLEN // *** assumes AHBW = XLEN
assign MMUReady = (BusState == MMUTRANSLATE && NextBusState == IDLE); assign MMUReady = (BusState == MMUTRANSLATE && HREADY);
assign InstrRData = HRDATA; assign InstrRData = HRDATA;
assign InstrAckF = (BusState == INSTRREAD) && (NextBusState != INSTRREAD); assign InstrAckF = (BusState == INSTRREAD) && (NextBusState != INSTRREAD);

View File

@ -1,86 +0,0 @@
///////////////////////////////////////////
// pmachecker.sv
//
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 20 April 2021
// Modified:
//
// Purpose: Examines all physical memory accesses and identifies attributes of
// the memory region accessed.
// Can report illegal accesses to the trap unit and cause a fault.
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// 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 pmachecker (
input logic [31:0] HADDR,
input logic [2:0] HSIZE,
input logic HWRITE,
input logic [2:0] HBURST,
input logic Atomic, Execute, Write, Read,
// *** Add pipeline suffixes
output logic Cacheable, Idempotent, AtomicAllowed,
output logic SquashAHBAccess,
output logic [5:0] HSELRegions,
output logic InstrAccessFaultF,
output logic LoadAccessFaultM,
output logic StoreAccessFaultM
);
// Signals are high if the memory access is within the given region
logic HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC;
logic PreHSELUART;
logic Empty;
// Determine which region of physical memory (if any) is being accessed
adrdec boottimdec(HADDR, `BOOTTIMBASE, `BOOTTIMRANGE, HSELBootTim);
adrdec timdec(HADDR, `TIMBASE, `TIMRANGE, HSELTim);
adrdec clintdec(HADDR, `CLINTBASE, `CLINTRANGE, HSELCLINT);
adrdec gpiodec(HADDR, `GPIOBASE, `GPIORANGE, HSELGPIO);
adrdec uartdec(HADDR, `UARTBASE, `UARTRANGE, PreHSELUART);
adrdec plicdec(HADDR, `PLICBASE, `PLICRANGE, HSELPLIC);
assign HSELUART = PreHSELUART && (HSIZE == 3'b000); // only byte writes to UART are supported
// Swizzle region bits
assign HSELRegions = {HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC};
// Only RAM memory regions are cacheable
assign Cacheable = HSELBootTim | HSELTim;
// *** Temporarily assume only RAM regions are idempotent -- likely wrong
assign Idempotent = HSELBootTim | HSELTim;
// *** Temporarily assume only RAM regions allow full atomic operations -- likely wrong
assign AtomicAllowed = HSELBootTim | HSELTim;
assign Empty = ~|HSELRegions;
assign InstrAccessFaultF = Empty && Execute;
assign LoadAccessFaultM = Empty && Read;
assign StoreAccessFaultM = Empty && Write;
assign SquashAHBAccess = InstrAccessFaultF || LoadAccessFaultM || StoreAccessFaultM;
endmodule

View File

@ -55,6 +55,9 @@ module csr #(parameter
output logic [11:0] MIP_REGW, MIE_REGW, output logic [11:0] MIP_REGW, MIE_REGW,
output logic STATUS_MIE, STATUS_SIE, output logic STATUS_MIE, STATUS_SIE,
output logic STATUS_MXR, STATUS_SUM, output logic STATUS_MXR, STATUS_SUM,
output logic STATUS_MPRV,
output logic [63:0] PMPCFG01_REGW, PMPCFG23_REGW,
output logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15],
input logic [4:0] SetFflagsM, input logic [4:0] SetFflagsM,
output logic [2:0] FRM_REGW, output logic [2:0] FRM_REGW,
// output logic [11:0] MIP_REGW, SIP_REGW, UIP_REGW, MIE_REGW, SIE_REGW, UIE_REGW, // output logic [11:0] MIP_REGW, SIP_REGW, UIP_REGW, MIE_REGW, SIE_REGW, UIE_REGW,

View File

@ -90,7 +90,10 @@ module csrm #(parameter
input logic [`XLEN-1:0] CSRWriteValM, input logic [`XLEN-1:0] CSRWriteValM,
output logic [`XLEN-1:0] CSRMReadValM, MEPC_REGW, MTVEC_REGW, output logic [`XLEN-1:0] CSRMReadValM, MEPC_REGW, MTVEC_REGW,
output logic [31:0] MCOUNTEREN_REGW, MCOUNTINHIBIT_REGW, output logic [31:0] MCOUNTEREN_REGW, MCOUNTINHIBIT_REGW,
output logic [`XLEN-1:0] MEDELEG_REGW, MIDELEG_REGW, output logic [`XLEN-1:0] MEDELEG_REGW, MIDELEG_REGW,
// 64-bit registers in RV64, or two 32-bit registers in RV32
output logic [63:0] PMPCFG01_REGW, PMPCFG23_REGW,
output logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15],
input logic [11:0] MIP_REGW, MIE_REGW, input logic [11:0] MIP_REGW, MIE_REGW,
output logic WriteMSTATUSM, output logic WriteMSTATUSM,
output logic IllegalCSRMAccessM, IllegalCSRMWriteReadonlyM output logic IllegalCSRMAccessM, IllegalCSRMWriteReadonlyM
@ -98,9 +101,6 @@ module csrm #(parameter
logic [`XLEN-1:0] MISA_REGW; logic [`XLEN-1:0] MISA_REGW;
logic [`XLEN-1:0] MSCRATCH_REGW, MCAUSE_REGW, MTVAL_REGW; logic [`XLEN-1:0] MSCRATCH_REGW, MCAUSE_REGW, MTVAL_REGW;
logic [63:0] PMPCFG01_REGW, PMPCFG23_REGW; // 64-bit registers in RV64, or two 32-bit registers in RV32
logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15]; // *** Might have to make 16 individual registers
//logic [`XLEN-1:0] PMPADDR0_REGW;
logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM; logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM;
logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM; logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM;

View File

@ -37,10 +37,11 @@ module csrsr (
output logic [1:0] STATUS_MPP, output logic [1:0] STATUS_MPP,
output logic STATUS_SPP, STATUS_TSR, output logic STATUS_SPP, STATUS_TSR,
output logic STATUS_MIE, STATUS_SIE, output logic STATUS_MIE, STATUS_SIE,
output logic STATUS_MXR, STATUS_SUM output logic STATUS_MXR, STATUS_SUM,
output logic STATUS_MPRV
); );
logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_SUM_INT, STATUS_MPRV, STATUS_MPRV_INT; logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_SUM_INT, STATUS_MPRV_INT;
logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS, STATUS_FS_INT, STATUS_MPP_NEXT; logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS, STATUS_FS_INT, STATUS_MPP_NEXT;
logic STATUS_MPIE, STATUS_SPIE, STATUS_UPIE, STATUS_UIE; logic STATUS_MPIE, STATUS_SPIE, STATUS_UPIE, STATUS_UIE;

View File

@ -0,0 +1,130 @@
///////////////////////////////////////////
// pmachecker.sv
//
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 20 April 2021
// Modified:
//
// Purpose: Examines all physical memory accesses and identifies attributes of
// the memory region accessed.
// Can report illegal accesses to the trap unit and cause a fault.
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// 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 pmachecker (
input logic clk, reset,
input logic [31:0] HADDR,
input logic [2:0] HSIZE,
input logic [2:0] HBURST,
input logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM,
output logic Cacheable, Idempotent, AtomicAllowed,
output logic PMASquashBusAccess,
output logic [5:0] HSELRegions,
output logic PMAInstrAccessFaultF,
output logic PMALoadAccessFaultM,
output logic PMAStoreAccessFaultM
);
// Signals are high if the memory access is within the given region
logic BootTim, Tim, CLINT, GPIO, UART, PLIC;
logic [5:0] Regions;
// Actual HSEL signals sent to uncore
logic HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC;
logic ValidBootTim, ValidTim, ValidCLINT, ValidGPIO, ValidUART, ValidPLIC;
// Attributes of memory region accessed
logic Executable, Readable, Writable;
logic Fault;
attributes attributes(.Address(HADDR), .*);
// Unswizzle region bits
assign {BootTim, Tim, CLINT, GPIO, UART, PLIC} = Regions;
assign ValidBootTim = '1;
assign ValidTim = '1;
assign ValidCLINT = ~ExecuteAccessF && ((HSIZE == 3'b011) || (HSIZE == 3'b010));
assign ValidGPIO = ~ExecuteAccessF && (HSIZE == 3'b010);
assign ValidUART = ~ExecuteAccessF && (HSIZE == 3'b000);
assign ValidPLIC = ~ExecuteAccessF && (HSIZE == 3'b010);
assign HSELBootTim = BootTim && ValidBootTim;
assign HSELTim = Tim && ValidTim;
assign HSELCLINT = CLINT && ValidCLINT;
assign HSELGPIO = GPIO && ValidGPIO;
assign HSELUART = UART && ValidUART; // only byte writes to UART are supported
assign HSELPLIC = PLIC && ValidPLIC;
// Swizzle region bits
assign HSELRegions = {HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC};
assign Fault = ~|HSELRegions;
assign PMAInstrAccessFaultF = ExecuteAccessF && Fault;
assign PMALoadAccessFaultM = ReadAccessM && Fault;
assign PMAStoreAccessFaultM = WriteAccessM && Fault;
assign PMASquashBusAccess = PMAInstrAccessFaultF || PMALoadAccessFaultM || PMAStoreAccessFaultM;
endmodule
module attributes (
input logic clk, reset,
input logic [31:0] Address,
output logic [5:0] Regions,
output logic Cacheable, Idempotent, AtomicAllowed,
output logic Executable, Readable, Writable
);
// Signals are high if the memory access is within the given region
logic BootTim, Tim, CLINT, GPIO, UART, PLIC;
// Determine which region of physical memory (if any) is being accessed
adrdec boottimdec(Address, `BOOTTIMBASE, `BOOTTIMRANGE, BootTim);
adrdec timdec(Address, `TIMBASE, `TIMRANGE, Tim);
adrdec clintdec(Address, `CLINTBASE, `CLINTRANGE, CLINT);
adrdec gpiodec(Address, `GPIOBASE, `GPIORANGE, GPIO);
adrdec uartdec(Address, `UARTBASE, `UARTRANGE, UART);
adrdec plicdec(Address, `PLICBASE, `PLICRANGE, PLIC);
// Swizzle region bits
assign Regions = {BootTim, Tim, CLINT, GPIO, UART, PLIC};
// Only RAM memory regions are cacheable
assign Cacheable = BootTim | Tim;
assign Idempotent = BootTim | Tim;
assign AtomicAllowed = BootTim | Tim;
assign Executable = BootTim | Tim;
assign Readable = BootTim | Tim | CLINT | GPIO | UART | PLIC;
assign Writable = BootTim | Tim | CLINT | GPIO | UART | PLIC;
endmodule

View File

@ -0,0 +1,120 @@
///////////////////////////////////////////
// pmpadrdec.sv
//
// Written: tfleming@hmc.edu 28 April 2021
// Modified:
//
// Purpose: Address decoder for the PMP checker. Decides whether a given address
// falls within the PMP range for each address-matching mode
// (top-of-range/TOR, naturally aligned four-byte region/NA4, and
// naturally aligned power-of-two region/NAPOT), then selects the
// output based on which mode is input.
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// 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"
`include "wally-constants.vh"
module pmpadrdec (
input logic [31:0] HADDR,
input logic [1:0] AdrMode,
input logic [`XLEN-1:0] PreviousPMPAdr, CurrentPMPAdr,
output logic Match
);
localparam TOR = 2'b01;
localparam NA4 = 2'b10;
localparam NAPOT = 2'b11;
logic TORMatch, NA4Match, NAPOTMatch;
logic [31:0] PreviousAdrFull, CurrentAdrFull;
logic [33:0] Range;
assign PreviousAdrFull = {PreviousPMPAdr[29:0], 2'b00};
assign CurrentAdrFull = {CurrentPMPAdr[29:0], 2'b00};
// Top-of-range (TOR)
// *** Check if this synthesizes
// if not, literally do comparison (HADDR - PreviousAdrFull == 0)
assign TORMatch = HADDR inside {[PreviousAdrFull:CurrentAdrFull]};
// *** cut number of comparators in half (treat entire pmp space as TOR and have 16 comparators)
// Naturally aligned four-byte region
adrdec na4dec(HADDR, CurrentAdrFull, (2**2)-1, NA4Match);
generate
if (`XLEN == 32 || `XLEN == 64) begin
// priority encoder to translate address to range
// *** We'd like to replace this with a
// *** We should not be truncating 64 bit physical addresses to 32 bits...
always_comb
casez (CurrentPMPAdr[31:0])
32'b???????????????????????????????0: Range = (2**3) - 1;
32'b??????????????????????????????01: Range = (2**4) - 1;
32'b?????????????????????????????011: Range = (2**5) - 1;
32'b????????????????????????????0111: Range = (2**6) - 1;
32'b???????????????????????????01111: Range = (2**7) - 1;
32'b??????????????????????????011111: Range = (2**8) - 1;
32'b?????????????????????????0111111: Range = (2**9) - 1;
32'b????????????????????????01111111: Range = (2**10) - 1;
32'b???????????????????????011111111: Range = (2**11) - 1;
32'b??????????????????????0111111111: Range = (2**12) - 1;
32'b?????????????????????01111111111: Range = (2**13) - 1;
32'b????????????????????011111111111: Range = (2**14) - 1;
32'b???????????????????0111111111111: Range = (2**15) - 1;
32'b??????????????????01111111111111: Range = (2**16) - 1;
32'b?????????????????011111111111111: Range = (2**17) - 1;
32'b????????????????0111111111111111: Range = (2**18) - 1;
32'b???????????????01111111111111111: Range = (2**19) - 1;
32'b??????????????011111111111111111: Range = (2**20) - 1;
32'b?????????????0111111111111111111: Range = (2**21) - 1;
32'b????????????01111111111111111111: Range = (2**22) - 1;
32'b???????????011111111111111111111: Range = (2**23) - 1;
32'b??????????0111111111111111111111: Range = (2**24) - 1;
32'b?????????01111111111111111111111: Range = (2**25) - 1;
32'b????????011111111111111111111111: Range = (2**26) - 1;
32'b???????0111111111111111111111111: Range = (2**27) - 1;
32'b??????01111111111111111111111111: Range = (2**28) - 1;
32'b?????011111111111111111111111111: Range = (2**29) - 1;
32'b????0111111111111111111111111111: Range = (2**30) - 1;
32'b???01111111111111111111111111111: Range = (2**31) - 1;
32'b??011111111111111111111111111111: Range = (2**32) - 1;
32'b?0111111111111111111111111111111: Range = (2**33) - 1;
32'b01111111111111111111111111111111: Range = (2**34) - 1;
32'b11111111111111111111111111111111: Range = (2**35) - 1;
default: Range = '0;
endcase
end else begin
assign Range = '0;
end
endgenerate
// *** Range should not be truncated... but our physical address space is
// currently only 32 bits wide.
adrdec napotdec(HADDR, CurrentAdrFull, Range[31:0], NAPOTMatch);
assign Match = (AdrMode == TOR) ? TORMatch :
(AdrMode == NA4) ? NA4Match :
(AdrMode == NAPOT) ? NAPOTMatch :
0;
endmodule

View File

@ -0,0 +1,132 @@
///////////////////////////////////////////
// pmpchecker.sv
//
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 28 April 2021
// Modified:
//
// Purpose: Examines all physical memory accesses and checks them against the
// current values of the physical memory protection (PMP) registers.
// Can raise an access fault on illegal reads, writes, and instruction
// fetches.
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// 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 pmpchecker (
input logic clk, reset,
input logic [31:0] HADDR,
input logic [1:0] PrivilegeModeW,
input logic [1:0] STATUS_MPP,
input logic STATUS_MPRV,
input logic [63:0] PMPCFG01_REGW, PMPCFG23_REGW,
input logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15],
input logic ExecuteAccessF, WriteAccessM, ReadAccessM,
output logic PMPSquashBusAccess,
output logic PMPInstrAccessFaultF,
output logic PMPLoadAccessFaultM,
output logic PMPStoreAccessFaultM
);
// Bit i is high when the address falls in PMP region i
logic [15:0] Regions;
logic [3:0] MatchedRegion;
logic Match;
logic [7:0] PMPCFG [0:15];
logic L_Bit, X_Bit, W_Bit, R_Bit;
logic InvalidExecute, InvalidWrite, InvalidRead;
assign {PMPCFG[15], PMPCFG[14], PMPCFG[13], PMPCFG[12],
PMPCFG[11], PMPCFG[10], PMPCFG[9], PMPCFG[8]} = PMPCFG23_REGW;
assign {PMPCFG[7], PMPCFG[6], PMPCFG[5], PMPCFG[4],
PMPCFG[3], PMPCFG[2], PMPCFG[1], PMPCFG[0]} = PMPCFG01_REGW;
pmpadrdec pmpadrdec0(HADDR, PMPCFG[0][4:3],
'0, PMPADDR_ARRAY_REGW[0],
Regions[0]);
generate
genvar i;
for (i = 1; i < 16; i++) begin
pmpadrdec pmpadrdec(HADDR, PMPCFG[i][4:3],
PMPADDR_ARRAY_REGW[i-1], PMPADDR_ARRAY_REGW[i],
Regions[i]);
end
endgenerate
assign Match = |Regions;
always_comb
casez (Regions)
16'b???????????????1: MatchedRegion = 0;
16'b??????????????10: MatchedRegion = 1;
16'b?????????????100: MatchedRegion = 2;
16'b????????????1000: MatchedRegion = 3;
16'b???????????10000: MatchedRegion = 4;
16'b??????????100000: MatchedRegion = 5;
16'b?????????1000000: MatchedRegion = 6;
16'b????????10000000: MatchedRegion = 7;
16'b???????100000000: MatchedRegion = 8;
16'b??????1000000000: MatchedRegion = 9;
16'b?????10000000000: MatchedRegion = 10;
16'b????100000000000: MatchedRegion = 11;
16'b???1000000000000: MatchedRegion = 12;
16'b??10000000000000: MatchedRegion = 13;
16'b?100000000000000: MatchedRegion = 14;
16'b1000000000000000: MatchedRegion = 15;
default: MatchedRegion = 0; // Should only occur if there is no match
endcase
assign L_Bit = PMPCFG[MatchedRegion][7];
assign X_Bit = PMPCFG[MatchedRegion][2];
assign W_Bit = PMPCFG[MatchedRegion][1];
assign R_Bit = PMPCFG[MatchedRegion][0];
assign InvalidExecute = ExecuteAccessF && ~X_Bit;
assign InvalidWrite = WriteAccessM && ~W_Bit;
assign InvalidRead = ReadAccessM && ~R_Bit;
assign PMPInstrAccessFaultF = (PrivilegeModeW == `M_MODE) ?
Match && L_Bit && InvalidExecute :
~Match || InvalidExecute;
assign PMPStoreAccessFaultM = (PrivilegeModeW == `M_MODE) ?
Match && L_Bit && InvalidWrite :
~Match || InvalidWrite;
assign PMPLoadAccessFaultM = (PrivilegeModeW == `M_MODE) ?
Match && L_Bit && InvalidRead :
~Match || InvalidRead;
/*
If no PMP entry matches an M-mode access, the access succeeds. If no PMP entry matches an
S-mode or U-mode access, but at least one PMP entry is implemented, the access fails.
*/
assign PMPSquashBusAccess = PMPInstrAccessFaultF || PMPLoadAccessFaultM || PMPStoreAccessFaultM;
endmodule

View File

@ -62,9 +62,9 @@ module privileged (
input logic [31:0] HADDR, input logic [31:0] HADDR,
input logic [2:0] HSIZE, HBURST, input logic [2:0] HSIZE, HBURST,
input logic HWRITE, input logic HWRITE,
input logic Atomic, Execute, Write, Read, input logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM,
output logic Cacheable, Idempotent, AtomicAllowed, output logic Cacheable, Idempotent, AtomicAllowed,
output logic SquashAHBAccess, output logic SquashBusAccess,
output logic [5:0] HSELRegions output logic [5:0] HSELRegions
); );
@ -92,9 +92,17 @@ module privileged (
logic [1:0] STATUS_MPP; logic [1:0] STATUS_MPP;
logic STATUS_SPP, STATUS_TSR; logic STATUS_SPP, STATUS_TSR;
logic STATUS_MIE, STATUS_SIE; logic STATUS_MIE, STATUS_SIE;
logic STATUS_MPRV;
logic [11:0] MIP_REGW, MIE_REGW; logic [11:0] MIP_REGW, MIE_REGW;
logic md, sd; logic md, sd;
logic [63:0] PMPCFG01_REGW, PMPCFG23_REGW;
logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15];
logic PMASquashBusAccess, PMPSquashBusAccess;
logic PMAInstrAccessFaultF, PMALoadAccessFaultM, PMAStoreAccessFaultM;
logic PMPInstrAccessFaultF, PMPLoadAccessFaultM, PMPStoreAccessFaultM;
/////////////////////////////////////////// ///////////////////////////////////////////
// track the current privilege level // track the current privilege level
/////////////////////////////////////////// ///////////////////////////////////////////
@ -139,6 +147,7 @@ module privileged (
/////////////////////////////////////////// ///////////////////////////////////////////
pmachecker pmachecker(.*); pmachecker pmachecker(.*);
pmpchecker pmpchecker(.*);
/////////////////////////////////////////// ///////////////////////////////////////////
// Extract exceptions by name and handle them // Extract exceptions by name and handle them
@ -155,6 +164,12 @@ module privileged (
assign LoadPageFaultM = DTLBLoadPageFaultM || WalkerLoadPageFaultM; assign LoadPageFaultM = DTLBLoadPageFaultM || WalkerLoadPageFaultM;
assign StorePageFaultM = DTLBStorePageFaultM || WalkerStorePageFaultM; assign StorePageFaultM = DTLBStorePageFaultM || WalkerStorePageFaultM;
assign InstrAccessFaultF = PMAInstrAccessFaultF || PMPInstrAccessFaultF;
assign LoadAccessFaultM = PMALoadAccessFaultM || PMPLoadAccessFaultM;
assign StoreAccessFaultM = PMAStoreAccessFaultM || PMPStoreAccessFaultM;
assign SquashBusAccess = PMASquashBusAccess || PMPSquashBusAccess;
// pipeline fault signals // pipeline fault signals
flopenrc #(2) faultregD(clk, reset, FlushD, ~StallD, flopenrc #(2) faultregD(clk, reset, FlushD, ~StallD,
{InstrPageFaultF, InstrAccessFaultF}, {InstrPageFaultF, InstrAccessFaultF},

View File

@ -112,9 +112,9 @@ module wallypipelinedhart (
logic [1:0] PageTypeF, PageTypeM; logic [1:0] PageTypeF, PageTypeM;
// PMA checker signals // PMA checker signals
logic Atomic, Execute, Write, Read; logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM;
logic Cacheable, Idempotent, AtomicAllowed; logic Cacheable, Idempotent, AtomicAllowed;
logic SquashAHBAccess; logic SquashBusAccess;
// IMem stalls // IMem stalls
logic ICacheStallF; logic ICacheStallF;

View File

@ -49,7 +49,7 @@ module testbench();
}; };
string tests64mmu[] = '{ string tests64mmu[] = '{
"rv64mmu/WALLY-VIRTUALMEMORY", "5000" "rv64mmu/WALLY-VIRTUALMEMORY", "2000"
}; };
string tests64f[] = '{ string tests64f[] = '{
@ -348,8 +348,8 @@ module testbench();
}; };
string tests64p[] = '{ string tests64p[] = '{
"rv64p/WALLY-MCAUSE", "4000", "rv64p/WALLY-MCAUSE", "3000",
"rv64p/WALLY-SCAUSE", "3000", "rv64p/WALLY-SCAUSE", "2000",
"rv64p/WALLY-MEPC", "5000", "rv64p/WALLY-MEPC", "5000",
"rv64p/WALLY-SEPC", "4000", "rv64p/WALLY-SEPC", "4000",
"rv64p/WALLY-MTVAL", "6000", "rv64p/WALLY-MTVAL", "6000",
@ -419,11 +419,11 @@ module testbench();
// if (`F_SUPPORTED) tests = {tests64f, tests}; // if (`F_SUPPORTED) tests = {tests64f, tests};
// if (`D_SUPPORTED) tests = {tests64d, tests}; // if (`D_SUPPORTED) tests = {tests64d, tests};
if (`A_SUPPORTED) tests = {tests, tests64a}; if (`A_SUPPORTED) tests = {tests, tests64a};
// if (`MEM_VIRTMEM) tests = {tests64mmu, tests}; if (`MEM_VIRTMEM) tests = {tests, tests64mmu};
end end
//tests = {tests64a, tests}; //tests = {tests64a, tests};
//tests = tests64p; tests = tests64p;
end else begin // RV32 end else begin // RV32
// *** add the 32 bit bp tests // *** add the 32 bit bp tests
if (TESTSPERIPH) begin if (TESTSPERIPH) begin
@ -435,7 +435,7 @@ module testbench();
if (`M_SUPPORTED % 2 == 1) tests = {tests, tests32m}; if (`M_SUPPORTED % 2 == 1) tests = {tests, tests32m};
// if (`F_SUPPORTED) tests = {tests32f, tests}; // if (`F_SUPPORTED) tests = {tests32f, tests};
if (`A_SUPPORTED) tests = {tests, tests32a}; if (`A_SUPPORTED) tests = {tests, tests32a};
if (`MEM_VIRTMEM) tests = {tests32mmu, tests}; if (`MEM_VIRTMEM) tests = {tests, tests32mmu};
end end
//tests = tests32p; //tests = tests32p;