Skip to content

Commit

Permalink
Merge pull request #1212 from davidharrishmc/dev
Browse files Browse the repository at this point in the history
Fixed PMP WARL field so regression works; added Zmmul coverage support
  • Loading branch information
jordancarlin authored Dec 31, 2024
2 parents 08cf6cc + c40450c commit 548350d
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 24 deletions.
2 changes: 2 additions & 0 deletions config/rv32gc/coverage.svh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
`include "ZfhD_coverage.svh"
// Note: Zfhmin is a subset of Zfh, so usually only one or the other would be used. When Zfhmin and D are supported, ZfhD should also be enabled
`include "Zfhmin_coverage.svh"
// Note: Zmmul is a subset of M, so usually only one or the other would be used.
`include "Zmmul_coverage.svh"
`include "Zicond_coverage.svh"
`include "Zca_coverage.svh"
`include "Zcb_coverage.svh"
Expand Down
2 changes: 2 additions & 0 deletions config/rv64gc/coverage.svh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
`include "Zfh_coverage.svh"
// Note: Zfhmin is a subset of Zfh, so usually only one or the other would be used. When Zfhmin and D are supported, ZfhD should also be enabled
`include "Zfhmin_coverage.svh"
// Note: Zmmul is a subset of M, so usually only one or the other would be used.
`include "Zmmul_coverage.svh"
`include "Zicond_coverage.svh"
`include "Zca_coverage.svh"
`include "Zcb_coverage.svh"
Expand Down
4 changes: 2 additions & 2 deletions src/mmu/mmu.sv
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
if (P.PMP_ENTRIES > 0) begin : pmp
pmpchecker #(P) pmpchecker(.PhysicalAddress, .PrivilegeModeW,
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,
.ExecuteAccessF, .WriteAccessM, .ReadAccessM, .CMOpM,
.ExecuteAccessF, .WriteAccessM, .ReadAccessM, .Size, .CMOpM,
.PMPInstrAccessFaultF, .PMPLoadAccessFaultM, .PMPStoreAmoAccessFaultM);
end else begin
assign PMPInstrAccessFaultF = 1'b0;
Expand All @@ -131,7 +131,7 @@ module mmu import cvw::*; #(parameter cvw_t P,

// Misaligned faults
always_comb // exclusion-tag: immu-wordaccess
case(Size[1:0])
case(Size)
2'b00: DataMisalignedM = 1'b0; // lb, sb, lbu
2'b01: DataMisalignedM = VAdr[0]; // lh, sh, lhu
2'b10: DataMisalignedM = VAdr[1] | VAdr[0]; // lw, sw, flw, fsw, lwu
Expand Down
19 changes: 12 additions & 7 deletions src/mmu/pmpadrdec.sv
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ module pmpadrdec import cvw::*; #(parameter cvw_t P) (
input logic [P.PA_BITS-1:0] PhysicalAddress,
input logic [7:0] PMPCfg,
input logic [P.PA_BITS-3:0] PMPAdr,
input logic FirstMatch,
input logic PAgePMPAdrIn,
output logic PAgePMPAdrOut,
output logic Match,
output logic [P.PA_BITS-1:0] PMPTop,
output logic L, X, W, R
);

Expand All @@ -50,7 +52,8 @@ module pmpadrdec import cvw::*; #(parameter cvw_t P) (
logic PAltPMPAdr;
logic [P.PA_BITS-1:0] CurrentAdrFull;
logic [1:0] AdrMode;

logic [P.PA_BITS-1:0] PMPTop1;

assign AdrMode = PMPCfg[4:3];

// The two lsb of the physical address don't matter for this checking.
Expand All @@ -71,20 +74,22 @@ module pmpadrdec import cvw::*; #(parameter cvw_t P) (
assign NAMask[P.PA_BITS-1:2] = (PMPAdr + {{(P.PA_BITS-3){1'b0}}, (AdrMode == NAPOT)}) ^ PMPAdr;
// form a mask where the bottom k bits are 1, corresponding to a size of 2^k bytes for this memory region.
// This assumes we're using at least an NA4 region, but works for any size NAPOT region.
assign NABase = {(PMPAdr & ~NAMask[P.PA_BITS-1:2]), 2'b00}; // base physical address of the pmp.

assign NABase = {(PMPAdr & ~NAMask[P.PA_BITS-1:2]), 2'b00}; // base physical address of the pmp region
assign NAMatch = &((NABase ~^ PhysicalAddress) | NAMask); // check if upper bits of base address match, ignore lower bits correspoonding to inside the memory range

// finally pick the appropriate match for the access type
assign Match = (AdrMode == TOR) ? TORMatch :
(AdrMode == NA4 | AdrMode == NAPOT) ? NAMatch :
1'b0;

// Report top of region for first matching region
assign PMPTop1 = {PMPAdr,2'b00} | NAMask; // top of the pmp region. All 1s in the lower bits. Used to check the address doesn't pass the top
assign PMPTop = FirstMatch ? PMPTop1 : '0; // AND portion of distributed AND-OR mux (OR portion in pmpchhecker)

// PMP should match but fail if the size is too big (8-byte accesses spanning to TOR or NA4 region)
assign L = PMPCfg[7];
assign X = PMPCfg[2];
assign W = PMPCfg[1];
assign R = PMPCfg[0];

// known bug: The size of the access is not yet checked. For example, if an NA4 entry matches 0xC-0xF and the system
// attempts an 8-byte access to 0x8, the access should fail (see page 60 of privileged specification 20211203). This
// implementation will not detect the failure.
endmodule
endmodule
45 changes: 36 additions & 9 deletions src/mmu/pmpchecker.sv
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) (
input var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0],
input var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW [P.PMP_ENTRIES-1:0],
input logic ExecuteAccessF, WriteAccessM, ReadAccessM,
input logic [1:0] Size,
input logic [3:0] CMOpM,
output logic PMPInstrAccessFaultF,
output logic PMPLoadAccessFaultM,
Expand All @@ -55,29 +56,55 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) (
logic [P.PMP_ENTRIES-1:0] FirstMatch; // onehot encoding for the first pmpaddr to match the current address.
logic [P.PMP_ENTRIES-1:0] L, X, W, R; // PMP matches and has flag set
logic [P.PMP_ENTRIES-1:0] PAgePMPAdr; // for TOR PMP matching, PhysicalAddress > PMPAdr[i]
logic [P.PA_BITS-1:0] PMPTop[P.PMP_ENTRIES-1:0]; // Upper end of each region, for checking that the access is fully within the region
logic PMPCMOAccessFault, PMPCBOMAccessFault, PMPCBOZAccessFault;

logic [2:0] SizeBytesMinus1;
logic MatchingR, MatchingW, MatchingX, MatchingL;
logic [P.PA_BITS-1:0] MatchingPMPTop, PhysicalAddressTop;
logic TooBig;

if (P.PMP_ENTRIES > 0) begin: pmp // prevent complaints about array of no elements when PMP_ENTRIES = 0
pmpadrdec #(P) pmpadrdecs[P.PMP_ENTRIES-1:0](
.PhysicalAddress,
.PMPCfg(PMPCFG_ARRAY_REGW),
.PMPAdr(PMPADDR_ARRAY_REGW),
.FirstMatch,
.PAgePMPAdrIn({PAgePMPAdr[P.PMP_ENTRIES-2:0], 1'b1}),
.PAgePMPAdrOut(PAgePMPAdr),
.Match, .L, .X, .W, .R);
.Match, .PMPTop, .L, .X, .W, .R);
end

priorityonehot #(P.PMP_ENTRIES) pmppriority(.a(Match), .y(FirstMatch)); // combine the match signal from all the adress decoders to find the first one that matches.

// Distributed AND-OR mux to select the first matching results
// If the access does not match all bytes of the PMP region, it is too big and the matches are disabled
assign MatchingR = |(R & FirstMatch) & ~TooBig;
assign MatchingW = |(W & FirstMatch) & ~TooBig;
assign MatchingX = |(X & FirstMatch) & ~TooBig;
assign MatchingL = |(L & FirstMatch);
or_rows #(P.PMP_ENTRIES, P.PA_BITS) PTEOr(PMPTop, MatchingPMPTop);

// Matching PMP entry must match all bytes of an access, or the access fails (Priv Spec 3.7.1.3)
// First find the size of the access in terms of the offset to the most significant byte
always_comb
case (Size)
2'b00: SizeBytesMinus1 = 3'd0;
2'b01: SizeBytesMinus1 = 3'd1;
2'b10: SizeBytesMinus1 = 3'd3;
2'b11: SizeBytesMinus1 = 3'd7;
endcase
// Then find the top of the access and see if it is beyond the top of the region
assign PhysicalAddressTop = PhysicalAddress + {{P.PA_BITS-3{1'b0}}, SizeBytesMinus1}; // top of the access range
assign TooBig = PhysicalAddressTop > MatchingPMPTop; // check if the access goes beyond the top of the PMP region

// Only enforce PMP checking for S and U modes or in Machine mode when L bit is set in selected region
assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | (|(L & FirstMatch));
assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | MatchingL;

assign PMPCBOMAccessFault = EnforcePMP & (|CMOpM[2:0]) & ~|((R|W) & FirstMatch) ; // exclusion-tag: immu-pmpcbom
assign PMPCBOZAccessFault = EnforcePMP & CMOpM[3] & ~|(W & FirstMatch) ; // exclusion-tag: immu-pmpcboz
assign PMPCBOMAccessFault = EnforcePMP & (|CMOpM[2:0]) & ~MatchingR ; // checking R is sufficient because W implies R in PMP // exclusion-tag: immu-pmpcbom
assign PMPCBOZAccessFault = EnforcePMP & CMOpM[3] & ~MatchingW ; // exclusion-tag: immu-pmpcboz
assign PMPCMOAccessFault = PMPCBOZAccessFault | PMPCBOMAccessFault; // exclusion-tag: immu-pmpcboaccess
assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|(X & FirstMatch) ;
assign PMPStoreAmoAccessFaultM = (EnforcePMP & WriteAccessM & ~|(W & FirstMatch)) | PMPCMOAccessFault; // exclusion-tag: immu-pmpstoreamoaccessfault
assign PMPLoadAccessFaultM = EnforcePMP & ReadAccessM & ~WriteAccessM & ~|(R & FirstMatch) ;

assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~MatchingX ;
assign PMPStoreAmoAccessFaultM = (EnforcePMP & WriteAccessM & ~MatchingW) | PMPCMOAccessFault; // exclusion-tag: immu-pmpstoreamoaccessfault
assign PMPLoadAccessFaultM = EnforcePMP & ReadAccessM & ~WriteAccessM & ~MatchingR;
endmodule
8 changes: 4 additions & 4 deletions src/mmu/tlb/tlbcontrol.sv
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
logic TLBAccess;
logic ImproperPrivilege;
logic BadPBMT, BadNAPOT, BadReserved;
logic ReservedEncoding;
logic ReservedRW;
logic InvalidAccess;
logic PreUpdateDA, PrePageFault;

Expand Down Expand Up @@ -89,15 +89,15 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
assign BadPBMT = ((PTE_PBMT != 0) & ~(P.SVPBMT_SUPPORTED & ENVCFG_PBMTE)) | PTE_PBMT == 3; // PBMT must be zero if not supported; value of 3 is reserved
assign BadNAPOT = PTE_N & (~P.SVNAPOT_SUPPORTED | ~NAPOT4); // N must be be 0 if CVNAPOT is not supported or not 64 KiB contiguous region
assign BadReserved = PTE_RESERVED; // Reserved bits must be zero
assign ReservedEncoding = PTE_W & ~PTE_R; // fault on reserved encoding with R=0, W=1 to match ImperasDV behavior
assign ReservedRW = PTE_W & ~PTE_R; // page fault on reserved encoding with R=0, W=1 per Privileged Spec 10.3.1

// Check whether the access is allowed, page faulting if not.
if (ITLB == 1) begin:itlb // Instruction TLB fault checking
// User mode may only execute user mode pages, and supervisor mode may
// only execute non-user mode pages.
assign ImproperPrivilege = ((PrivilegeModeW == P.U_MODE) & ~PTE_U) | ((PrivilegeModeW == P.S_MODE) & PTE_U);
assign PreUpdateDA = ~PTE_A;
assign InvalidAccess = ~PTE_X | ReservedEncoding;
assign InvalidAccess = ~PTE_X | ReservedRW;
end else begin:dtlb // Data TLB fault checking
logic InvalidRead, InvalidWrite;
logic InvalidCBOM, InvalidCBOZ;
Expand All @@ -114,7 +114,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
assign InvalidWrite = WriteAccess & ~PTE_W;
assign InvalidCBOM = (|CMOpM[2:0]) & (~PTE_R & (~STATUS_MXR | ~PTE_X));
assign InvalidCBOZ = CMOpM[3] & ~PTE_W;
assign InvalidAccess = InvalidRead | InvalidWrite | InvalidCBOM | InvalidCBOZ | ReservedEncoding;
assign InvalidAccess = InvalidRead | InvalidWrite | InvalidCBOM | InvalidCBOZ | ReservedRW;
assign PreUpdateDA = ~PTE_A | WriteAccess & ~PTE_D;
end

Expand Down
4 changes: 2 additions & 2 deletions src/privileged/csrm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ module csrm import cvw::*; #(parameter cvw_t P) (
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 #(P.PA_BITS-2) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM[P.PA_BITS-3:0], PMPADDR_ARRAY_REGW[i]);
if (P.XLEN==64) begin
Expand All @@ -134,7 +134,7 @@ module csrm import cvw::*; #(parameter cvw_t P) (

assign CSRPMPWRLegalizedWriteValM[i] = {(CSRPMPWriteValM[i][1] & CSRPMPWriteValM[i][0]), CSRPMPWriteValM[i][0]}; // legalize WR fields (reserved 10 written as 00)
assign CSRPMPLegalizedWriteValM[i] = {CSRPMPWriteValM[i][7], 2'b00, CSRPMPWriteValM[i][4:2], CSRPMPWRLegalizedWriteValM[i]};
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRPMPWriteValM[i], PMPCFG_ARRAY_REGW[i]);
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRPMPLegalizedWriteValM[i], PMPCFG_ARRAY_REGW[i]);
end
end

Expand Down

0 comments on commit 548350d

Please sign in to comment.