Implement PMP checker and revise PMA checker

This commit is contained in:
Thomas Fleming 2021-05-03 17:37:42 -04:00
parent 00c3b5a033
commit 86a93d77b4
6 changed files with 277 additions and 90 deletions

View File

@ -56,6 +56,7 @@ module csr #(parameter
output logic STATUS_MIE, STATUS_SIE,
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,
output logic [2:0] FRM_REGW,

View File

@ -90,7 +90,9 @@ module csrm #(parameter
input logic [`XLEN-1:0] CSRWriteValM,
output logic [`XLEN-1:0] CSRMReadValM, MEPC_REGW, MTVEC_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,
output logic WriteMSTATUSM,
@ -99,7 +101,6 @@ module csrm #(parameter
logic [`XLEN-1:0] MISA_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 WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM;
logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM;

View File

@ -47,47 +47,83 @@ module pmachecker (
);
// 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;
logic PreHSELUART;
// Attributes of memory region accessed
logic Executable, Readable, Writable;
logic ExecutableRegion, ReadableRegion, WritableRegion;
logic Empty;
logic Fault;
// 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);
attributes attributes(.Address(HADDR), .*);
// *** Should this fault?
assign HSELUART = PreHSELUART && (HSIZE == 3'b000); // only byte writes to UART are supported
// Unswizzle region bits
assign {BootTim, Tim, CLINT, GPIO, UART, PLIC} = Regions;
assign ValidBootTim = '1;
assign ValidTim = '1;
assign ValidCLINT = ~ExecuteAccessF && (HSIZE == 3'b010);
assign ValidGPIO = ~ExecuteAccessF && (HSIZE == 3'b010);
assign ValidUART = ~ExecuteAccessF && (HSIZE == 3'b000);
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};
// Only RAM memory regions are cacheable
assign Cacheable = HSELBootTim | HSELTim;
assign Fault = ~|HSELRegions;
// *** Temporarily assume only RAM regions are idempotent -- likely wrong
assign Idempotent = HSELBootTim | HSELTim;
assign PMAInstrAccessFaultF = ExecuteAccessF && Fault;
assign PMALoadAccessFaultM = ReadAccessM && Fault;
assign PMAStoreAccessFaultM = WriteAccessM && Fault;
// *** Temporarily assume only RAM regions allow full atomic operations -- likely wrong
assign AtomicAllowed = HSELBootTim | HSELTim;
assign ExecutableRegion = HSELBootTim | HSELTim;
assign ReadableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC;
assign WritableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC;
assign Empty = ~|HSELRegions;
assign PMAInstrAccessFaultF = ExecuteAccessF && (Empty || ~ExecutableRegion);
assign PMALoadAccessFaultM = ReadAccessM && (Empty || ~ReadableRegion);
assign PMAStoreAccessFaultM = WriteAccessM && (Empty || ~WritableRegion);
//assign PMASquashBusAccess = PMAInstrAccessFaultF || PMALoadAccessFaultM || PMAStoreAccessFaultM;
assign PMASquashBusAccess = 0;
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

@ -29,76 +29,104 @@
`include "wally-config.vh"
module pmpchecker (
input logic clk, reset,
input logic clk, reset,
input logic [31:0] HADDR,
input logic [31:0] HADDR,
input logic [1:0] PrivilegeModeW,
input logic [1:0] PrivilegeModeW,
input logic [1:0] STATUS_MPP,
input logic STATUS_MPRV,
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,
input logic ExecuteAccessF, WriteAccessM, ReadAccessM,
output logic PMPSquashBusAccess,
output logic PMPSquashBusAccess,
output logic PMPInstrAccessFaultF,
output logic PMPLoadAccessFaultM,
output logic PMPStoreAccessFaultM
output logic PMPInstrAccessFaultF,
output logic PMPLoadAccessFaultM,
output logic PMPStoreAccessFaultM
);
assign PMPSquashBusAccess = '0;
assign PMPInstrAccessFaultF = '0;
assign PMPLoadAccessFaultM = '0;
assign PMPStoreAccessFaultM = '0;
// 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;
/*
// Signals are high if the memory access is within the given region
logic HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC;
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.
*/
logic PreHSELUART;
logic ExecutableRegion, ReadableRegion, WritableRegion;
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);
// *** Should this fault?
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 ExecutableRegion = HSELBootTim | HSELTim;
assign ReadableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC;
assign WritableRegion = HSELBootTim | HSELTim | HSELCLINT | HSELGPIO | HSELUART | HSELPLIC;
assign Empty = ~|HSELRegions;
assign InstrAccessFaultF = ExecuteAccessF && (Empty || ~ExecutableRegion);
assign LoadAccessFaultM = ReadAccessM && (Empty || ~ReadableRegion);
assign StoreAccessFaultM = WriteAccessM && (Empty || ~WritableRegion);
assign SquashBusAccess = InstrAccessFaultF || LoadAccessFaultM || StoreAccessFaultM;
*/
assign PMPSquashBusAccess = PMPInstrAccessFaultF || PMPLoadAccessFaultM || PMPStoreAccessFaultM;
endmodule

View File

@ -96,6 +96,7 @@ module privileged (
logic [11:0] MIP_REGW, MIE_REGW;
logic md, sd;
logic [63:0] PMPCFG01_REGW, PMPCFG23_REGW;
logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [0:15];
logic PMASquashBusAccess, PMPSquashBusAccess;