mirror of
https://github.com/openhwgroup/cvw.git
synced 2025-06-27 17:01:20 -04:00
commit
6a525d3461
16 changed files with 111 additions and 115 deletions
9
src/cache/cache.sv
vendored
9
src/cache/cache.sv
vendored
|
@ -79,8 +79,8 @@ module cache import cvw::*; #(parameter cvw_t P,
|
|||
logic [LINELEN-1:0] ReadDataLineWay [NUMWAYS-1:0];
|
||||
logic [NUMWAYS-1:0] HitWay, ValidWay;
|
||||
logic CacheHit;
|
||||
logic [NUMWAYS-1:0] VictimWay, DirtyWay;
|
||||
logic LineDirty;
|
||||
logic [NUMWAYS-1:0] VictimWay, DirtyWay, HitWayDirtyWay;
|
||||
logic LineDirty, HitWayLineDirty;
|
||||
logic [TAGLEN-1:0] TagWay [NUMWAYS-1:0];
|
||||
logic [TAGLEN-1:0] Tag;
|
||||
logic [SETLEN-1:0] FlushAdr, NextFlushAdr, FlushAdrP1;
|
||||
|
@ -116,7 +116,7 @@ module cache import cvw::*; #(parameter cvw_t P,
|
|||
cacheway #(P, PA_BITS, XLEN, NUMLINES, LINELEN, TAGLEN, OFFSETLEN, SETLEN, READ_ONLY_CACHE) CacheWays[NUMWAYS-1:0](
|
||||
.clk, .reset, .CacheEn, .CacheSet, .PAdr, .LineWriteData, .LineByteMask, .SelWay,
|
||||
.SetValid, .ClearValid, .SetDirty, .ClearDirty, .VictimWay,
|
||||
.FlushWay, .SelFlush, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .TagWay, .FlushStage, .InvalidateCache);
|
||||
.FlushWay, .SelFlush, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .HitWayDirtyWay, .TagWay, .FlushStage, .InvalidateCache);
|
||||
|
||||
// Select victim way for associative caches
|
||||
if(NUMWAYS > 1) begin:vict
|
||||
|
@ -128,6 +128,7 @@ module cache import cvw::*; #(parameter cvw_t P,
|
|||
|
||||
assign CacheHit = |HitWay;
|
||||
assign LineDirty = |DirtyWay;
|
||||
assign HitWayLineDirty = |HitWayDirtyWay;
|
||||
|
||||
// ReadDataLineWay is a 2d array of cache line len by number of ways.
|
||||
// Need to OR together each way in a bitwise manner.
|
||||
|
@ -218,7 +219,7 @@ module cache import cvw::*; #(parameter cvw_t P,
|
|||
|
||||
cachefsm #(P, READ_ONLY_CACHE) cachefsm(.clk, .reset, .CacheBusRW, .CacheBusAck,
|
||||
.FlushStage, .CacheRW, .Stall,
|
||||
.CacheHit, .LineDirty, .CacheStall, .CacheCommitted,
|
||||
.CacheHit, .LineDirty, .HitWayLineDirty, .CacheStall, .CacheCommitted,
|
||||
.CacheMiss, .CacheAccess, .SelAdr, .SelWay,
|
||||
.ClearDirty, .SetDirty, .SetValid, .ClearValid, .SelWriteback, .SelFlush,
|
||||
.FlushAdrCntEn, .FlushWayCntEn, .FlushCntRst,
|
||||
|
|
27
src/cache/cachefsm.sv
vendored
27
src/cache/cachefsm.sv
vendored
|
@ -51,6 +51,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
|||
// cache internals
|
||||
input logic CacheHit, // Exactly 1 way hits
|
||||
input logic LineDirty, // The selected line and way is dirty
|
||||
input logic HitWayLineDirty, // The cache hit way is dirty
|
||||
input logic FlushAdrFlag, // On last set of a cache flush
|
||||
input logic FlushWayFlag, // On the last way for any set of a cache flush
|
||||
output logic SelAdr, // [0] SRAM reads from NextAdr, [1] SRAM reads from PAdr
|
||||
|
@ -94,7 +95,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
|||
assign AnyMiss = (CacheRW[0] | CacheRW[1]) & ~CacheHit & ~InvalidateCache; // exclusion-tag: cache AnyMiss
|
||||
assign AnyUpdateHit = (CacheRW[0]) & CacheHit; // exclusion-tag: icache storeAMO1
|
||||
assign AnyHit = AnyUpdateHit | (CacheRW[1] & CacheHit); // exclusion-tag: icache AnyUpdateHit
|
||||
assign CMOWritebackHit = (CMOp[1] | CMOp[2]) & CacheHit;
|
||||
assign CMOWritebackHit = (CMOp[1] | CMOp[2]) & CacheHit & HitWayLineDirty;
|
||||
assign CMOZeroNoEviction = CMOp[3] & ~LineDirty; // (hit or miss) with no writeback store zeros now
|
||||
assign CMOZeroEviction = CMOp[3] & LineDirty; // (hit or miss) with writeback dirty line
|
||||
assign CMOWriteback = CMOWritebackHit | CMOZeroEviction;
|
||||
|
@ -129,8 +130,8 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
|||
STATE_READ_HOLD: if(Stall) NextState = STATE_READ_HOLD;
|
||||
else NextState = STATE_READY;
|
||||
// exclusion-tag-start: icache case
|
||||
STATE_WRITEBACK: if(CacheBusAck & ~CMOp[3]) NextState = STATE_FETCH;
|
||||
else if(CacheBusAck) NextState = STATE_READ_HOLD;
|
||||
STATE_WRITEBACK: if(CacheBusAck & ~(|CMOp[3:1])) NextState = STATE_FETCH;
|
||||
else if(CacheBusAck) NextState = STATE_READ_HOLD; // Read_hold lowers CacheStall
|
||||
else NextState = STATE_WRITEBACK;
|
||||
// eviction needs a delay as the bus fsm does not correctly handle sending the write command at the same time as getting back the bus ack.
|
||||
STATE_FLUSH: if(LineDirty) NextState = STATE_FLUSH_WRITEBACK;
|
||||
|
@ -154,24 +155,24 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
|||
(CurrState == STATE_FLUSH_WRITEBACK);
|
||||
// write enables internal to cache
|
||||
assign SetValid = CurrState == STATE_WRITE_LINE |
|
||||
(P.ZICBOZ_SUPPORTED & CurrState == STATE_READY & CMOZeroNoEviction) |
|
||||
(P.ZICBOZ_SUPPORTED & CurrState == STATE_WRITEBACK & CacheBusAck & CMOp[3]);
|
||||
assign ClearValid = P.ZICBOM_SUPPORTED & ((CurrState == STATE_READY & CMOp[0] & CacheHit) |
|
||||
(CurrState == STATE_WRITEBACK & CMOp[2] & CacheBusAck));
|
||||
(CurrState == STATE_READY & CMOZeroNoEviction) |
|
||||
(CurrState == STATE_WRITEBACK & CacheBusAck & CMOp[3]);
|
||||
assign ClearValid = (CurrState == STATE_READY & CMOp[0]) |
|
||||
(CurrState == STATE_WRITEBACK & CMOp[2] & CacheBusAck);
|
||||
// coverage off -item e 1 -fecexprrow 8
|
||||
assign LRUWriteEn = (((CurrState == STATE_READY & (AnyHit | CMOZeroNoEviction)) |
|
||||
(CurrState == STATE_WRITE_LINE)) & ~FlushStage) |
|
||||
(P.ZICBOZ_SUPPORTED & CurrState == STATE_WRITEBACK & CMOp[3] & CacheBusAck);
|
||||
(CurrState == STATE_WRITEBACK & CMOp[3] & CacheBusAck);
|
||||
// exclusion-tag-start: icache flushdirtycontrols
|
||||
assign SetDirty = (CurrState == STATE_READY & (AnyUpdateHit | CMOZeroNoEviction)) | // exclusion-tag: icache SetDirty
|
||||
(CurrState == STATE_WRITE_LINE & (CacheRW[0])) |
|
||||
(P.ZICBOZ_SUPPORTED & CurrState == STATE_WRITEBACK & (CMOp[3] & CacheBusAck));
|
||||
(CurrState == STATE_WRITEBACK & (CMOp[3] & CacheBusAck));
|
||||
assign ClearDirty = (CurrState == STATE_WRITE_LINE & ~(CacheRW[0])) | // exclusion-tag: icache ClearDirty
|
||||
(CurrState == STATE_FLUSH & LineDirty) | // This is wrong in a multicore snoop cache protocal. Dirty must be cleared concurrently and atomically with writeback. For single core cannot clear after writeback on bus ack and change flushadr. Clears the wrong set.
|
||||
// Flush and eviction controls
|
||||
(P.ZICBOM_SUPPORTED & CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2]) & CacheBusAck);
|
||||
assign SelWay = (CurrState == STATE_WRITEBACK & ((~CacheBusAck & ~(CMOp[1] | CMOp[2])) | (P.ZICBOZ_SUPPORTED & CacheBusAck & CMOp[3]))) |
|
||||
(CurrState == STATE_READY & ((AnyMiss & LineDirty) | (P.ZICBOZ_SUPPORTED & CMOZeroNoEviction & ~CacheHit))) |
|
||||
CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2]) & CacheBusAck;
|
||||
assign SelWay = (CurrState == STATE_WRITEBACK & ((~CacheBusAck & ~(CMOp[1] | CMOp[2])) | (CacheBusAck & CMOp[3]))) |
|
||||
(CurrState == STATE_READY & ((AnyMiss & LineDirty) | (CMOZeroNoEviction & ~CacheHit))) |
|
||||
(CurrState == STATE_WRITE_LINE);
|
||||
assign SelWriteback = (CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2] | ~CacheBusAck)) |
|
||||
(CurrState == STATE_READY & AnyMiss & LineDirty);
|
||||
|
@ -194,7 +195,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
|||
assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) | // exclusion-tag: icache CacheBusW
|
||||
(CurrState == STATE_WRITEBACK & ~CacheBusAck) |
|
||||
(CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck) |
|
||||
(P.ZICBOM_SUPPORTED & CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2]) & ~CacheBusAck);
|
||||
(CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2]) & ~CacheBusAck);
|
||||
|
||||
assign SelAdr = (CurrState == STATE_READY & (CacheRW[0] | AnyMiss | (|CMOp))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed
|
||||
(CurrState == STATE_FETCH) |
|
||||
|
|
6
src/cache/cacheway.sv
vendored
6
src/cache/cacheway.sv
vendored
|
@ -51,7 +51,8 @@ module cacheway import cvw::*; #(parameter cvw_t P,
|
|||
output logic [LINELEN-1:0] ReadDataLineWay,// This way's read data if valid
|
||||
output logic HitWay, // This way hits
|
||||
output logic ValidWay, // This way is valid
|
||||
output logic DirtyWay, // This way is dirty
|
||||
output logic HitWayDirtyWay, // The hit way is dirty
|
||||
output logic DirtyWay , // The selected way is dirty
|
||||
output logic [TAGLEN-1:0] TagWay); // This way's tag if valid
|
||||
|
||||
localparam WORDSPERLINE = LINELEN/XLEN;
|
||||
|
@ -117,7 +118,8 @@ module cacheway import cvw::*; #(parameter cvw_t P,
|
|||
|
||||
// AND portion of distributed tag multiplexer
|
||||
assign TagWay = SelData ? ReadTag : '0; // AND part of AOMux
|
||||
assign DirtyWay = SelDirty & Dirty & ValidWay;
|
||||
assign HitWayDirtyWay = Dirty & ValidWay;
|
||||
assign DirtyWay = SelDirty & HitWayDirtyWay;
|
||||
assign HitWay = ValidWay & (ReadTag == PAdr[PA_BITS-1:OFFSETLEN+INDEXLEN]);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -66,6 +66,7 @@ module ahbcacheinterface #(
|
|||
input logic [LLEN-1:0] WriteDataM, // IEU write data for uncached store
|
||||
input logic [1:0] BusRW, // Uncached memory operation read/write control: 10: read, 01: write
|
||||
input logic [2:0] Funct3, // Size of uncached memory operation
|
||||
input logic BusCMOZero, // Uncached cbo.zero must write zero to full sized cacheline without going through the cache
|
||||
|
||||
// lsu/ifu interface
|
||||
input logic Stall, // Core pipeline is stalled
|
||||
|
@ -80,6 +81,7 @@ module ahbcacheinterface #(
|
|||
logic CaptureEn; // Enable updating the Fetch buffer with valid data from HRDATA
|
||||
logic [AHBW/8-1:0] BusByteMaskM; // Byte enables within a word. For cache request all 1s
|
||||
logic [AHBW-1:0] PreHWDATA; // AHB Address phase write data
|
||||
logic [PA_BITS-1:0] PAdrZero;
|
||||
|
||||
genvar index;
|
||||
|
||||
|
@ -91,10 +93,11 @@ module ahbcacheinterface #(
|
|||
.q(FetchBuffer[(index+1)*AHBW-1:index*AHBW]));
|
||||
end
|
||||
|
||||
mux2 #(PA_BITS) localadrmux(PAdr, CacheBusAdr, Cacheable, LocalHADDR);
|
||||
assign PAdrZero = BusCMOZero ? {PAdr[PA_BITS-1:$clog2(LINELEN/8)], {$clog2(LINELEN/8){1'b0}}} : PAdr;
|
||||
mux2 #(PA_BITS) localadrmux(PAdrZero, CacheBusAdr, Cacheable, LocalHADDR);
|
||||
assign HADDR = ({{PA_BITS-AHBWLOGBWPL{1'b0}}, BeatCount} << $clog2(AHBW/8)) + LocalHADDR;
|
||||
|
||||
mux2 #(3) sizemux(.d0(Funct3), .d1(AHBW == 32 ? 3'b010 : 3'b011), .s(Cacheable), .y(HSIZE));
|
||||
mux2 #(3) sizemux(.d0(Funct3), .d1(AHBW == 32 ? 3'b010 : 3'b011), .s(Cacheable | BusCMOZero), .y(HSIZE));
|
||||
|
||||
// When AHBW is less than LLEN need extra muxes to select the subword from cache's read data.
|
||||
logic [AHBW-1:0] CacheReadDataWordAHB;
|
||||
|
@ -119,6 +122,6 @@ module ahbcacheinterface #(
|
|||
|
||||
buscachefsm #(BeatCountThreshold, AHBWLOGBWPL, READ_ONLY_CACHE) AHBBuscachefsm(
|
||||
.HCLK, .HRESETn, .Flush, .BusRW, .Stall, .BusCommitted, .BusStall, .CaptureEn, .SelBusBeat,
|
||||
.CacheBusRW, .CacheBusAck, .BeatCount, .BeatCountDelayed,
|
||||
.CacheBusRW, .BusCMOZero, .CacheBusAck, .BeatCount, .BeatCountDelayed,
|
||||
.HREADY, .HTRANS, .HWRITE, .HBURST);
|
||||
endmodule
|
||||
|
|
|
@ -42,6 +42,7 @@ module buscachefsm #(
|
|||
input logic Stall, // Core pipeline is stalled
|
||||
input logic Flush, // Pipeline stage flush. Prevents bus transaction from starting
|
||||
input logic [1:0] BusRW, // Uncached memory operation read/write control: 10: read, 01: write
|
||||
input logic BusCMOZero, // Uncached cbo.zero must write zero to full sized cacheline without going through the cache
|
||||
output logic BusStall, // Bus is busy with an in flight memory operation
|
||||
output logic BusCommitted, // Bus is busy with an in flight memory operation and it is not safe to take an interrupt
|
||||
|
||||
|
@ -75,6 +76,9 @@ module buscachefsm #(
|
|||
logic BeatCntEn;
|
||||
logic BeatCntReset;
|
||||
logic CacheAccess;
|
||||
logic BusWrite;
|
||||
|
||||
assign BusWrite = CacheBusRW[0] | BusCMOZero;
|
||||
|
||||
always_ff @(posedge HCLK)
|
||||
if (~HRESETn | Flush) CurrState <= #1 ADR_PHASE;
|
||||
|
@ -83,18 +87,18 @@ module buscachefsm #(
|
|||
always_comb begin
|
||||
case(CurrState)
|
||||
ADR_PHASE: if (HREADY & |BusRW) NextState = DATA_PHASE;
|
||||
else if (HREADY & CacheBusRW[0]) NextState = CACHE_WRITEBACK;
|
||||
else if (HREADY & BusWrite) NextState = CACHE_WRITEBACK;
|
||||
else if (HREADY & CacheBusRW[1]) NextState = CACHE_FETCH;
|
||||
else NextState = ADR_PHASE;
|
||||
DATA_PHASE: if(HREADY) NextState = MEM3;
|
||||
else NextState = DATA_PHASE;
|
||||
MEM3: if(Stall) NextState = MEM3;
|
||||
else NextState = ADR_PHASE;
|
||||
CACHE_FETCH: if(HREADY & FinalBeatCount & CacheBusRW[0]) NextState = CACHE_WRITEBACK;
|
||||
CACHE_FETCH: if(HREADY & FinalBeatCount & BusWrite) NextState = CACHE_WRITEBACK;
|
||||
else if(HREADY & FinalBeatCount & CacheBusRW[1]) NextState = CACHE_FETCH;
|
||||
else if(HREADY & FinalBeatCount & ~|CacheBusRW) NextState = ADR_PHASE;
|
||||
else NextState = CACHE_FETCH;
|
||||
CACHE_WRITEBACK: if(HREADY & FinalBeatCount & CacheBusRW[0]) NextState = CACHE_WRITEBACK;
|
||||
CACHE_WRITEBACK: if(HREADY & FinalBeatCount & BusWrite) NextState = CACHE_WRITEBACK;
|
||||
else if(HREADY & FinalBeatCount & CacheBusRW[1]) NextState = CACHE_FETCH;
|
||||
else if(HREADY & FinalBeatCount & ~|CacheBusRW) NextState = ADR_PHASE;
|
||||
else NextState = CACHE_WRITEBACK;
|
||||
|
@ -128,7 +132,7 @@ module buscachefsm #(
|
|||
(CacheAccess & FinalBeatCount & |CacheBusRW & HREADY & ~Flush) ? AHB_NONSEQ : // if we have a pipelined request
|
||||
(CacheAccess & |BeatCount) ? (`BURST_EN ? AHB_SEQ : AHB_NONSEQ) : AHB_IDLE;
|
||||
|
||||
assign HWRITE = (BusRW[0] | CacheBusRW[0] & ~Flush) | (CurrState == CACHE_WRITEBACK & |BeatCount);
|
||||
assign HWRITE = (BusRW[0] | BusWrite & ~Flush) | (CurrState == CACHE_WRITEBACK & |BeatCount);
|
||||
assign HBURST = `BURST_EN & ((|CacheBusRW & ~Flush) | (CacheAccess & |BeatCount)) ? LocalBurstType : 3'b0;
|
||||
|
||||
always_comb begin
|
||||
|
@ -142,8 +146,8 @@ module buscachefsm #(
|
|||
end
|
||||
|
||||
// communication to cache
|
||||
assign CacheBusAck = (CacheAccess & HREADY & FinalBeatCount);
|
||||
assign SelBusBeat = (CurrState == ADR_PHASE & (BusRW[0] | CacheBusRW[0])) |
|
||||
assign CacheBusAck = (CacheAccess & HREADY & FinalBeatCount & ~BusCMOZero);
|
||||
assign SelBusBeat = (CurrState == ADR_PHASE & (BusRW[0] | BusWrite)) |
|
||||
(CurrState == DATA_PHASE & BusRW[0]) |
|
||||
(CurrState == CACHE_WRITEBACK) |
|
||||
(CurrState == CACHE_FETCH);
|
||||
|
|
|
@ -357,8 +357,10 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
|||
// Cache Management instructions
|
||||
always_comb begin
|
||||
CMOpD = 4'b0000; // default: not a cbo instruction
|
||||
if ((P.ZICBOM_SUPPORTED | P.ZICBOZ_SUPPORTED) & CMOD) begin
|
||||
if ((P.ZICBOZ_SUPPORTED) & CMOD) begin
|
||||
CMOpD[3] = (InstrD[31:20] == 12'd4); // cbo.zero
|
||||
end
|
||||
if ((P.ZICBOM_SUPPORTED) & CMOD) begin
|
||||
CMOpD[2] = (InstrD[31:20] == 12'd2); // cbo.clean
|
||||
CMOpD[1] = (InstrD[31:20] == 12'd1) | ((InstrD[31:20] == 12'd0) & (ENVCFG_CBE[1:0] == 2'b01)); // cbo.flush
|
||||
CMOpD[0] = (InstrD[31:20] == 12'd0) & (ENVCFG_CBE[1:0] == 2'b11); // cbo.inval
|
||||
|
@ -425,6 +427,5 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
|||
// a cache cannot read or write immediately after a write
|
||||
// atomic operations are also detected as MemRWD[1]
|
||||
//assign StoreStallD = MemRWE[0] & ((MemRWD[1] | (MemRWD[0] & P.DCACHE_SUPPORTED)));
|
||||
// *** RT: Modify for ZICBOZ
|
||||
assign StoreStallD = (MemRWE[0] | (|CMOpE & P.ZICBOM_SUPPORTED)) & ((MemRWD[1] | (MemRWD[0] & P.DCACHE_SUPPORTED) | (|CMOpD & P.ZICBOM_SUPPORTED)));
|
||||
assign StoreStallD = (MemRWE[0] | (|CMOpE)) & ((MemRWD[1] | (MemRWD[0] & P.DCACHE_SUPPORTED) | (|CMOpD)));
|
||||
endmodule
|
||||
|
|
|
@ -252,7 +252,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
|
|||
ahbcacheinterface #(P.AHBW, P.LLEN, P.PA_BITS, WORDSPERLINE, LOGBWPL, LINELEN, LLENPOVERAHBW, 1)
|
||||
ahbcacheinterface(.HCLK(clk), .HRESETn(~reset),
|
||||
.HRDATA,
|
||||
.Flush(FlushD), .CacheBusRW, .HSIZE(IFUHSIZE), .HBURST(IFUHBURST), .HTRANS(IFUHTRANS), .HWSTRB(),
|
||||
.Flush(FlushD), .CacheBusRW, .BusCMOZero(1'b0), .HSIZE(IFUHSIZE), .HBURST(IFUHBURST), .HTRANS(IFUHTRANS), .HWSTRB(),
|
||||
.Funct3(3'b010), .HADDR(IFUHADDR), .HREADY(IFUHREADY), .HWRITE(IFUHWRITE), .CacheBusAdr(ICacheBusAdr),
|
||||
.BeatCount(), .Cacheable(CacheableF), .SelBusBeat(), .WriteDataM('0),
|
||||
.CacheBusAck(ICacheBusAck), .HWDATA(), .CacheableOrFlushCacheM(1'b0), .CacheReadDataWordM('0),
|
||||
|
|
|
@ -37,11 +37,8 @@ module align import cvw::*; #(parameter cvw_t P) (
|
|||
input logic [P.XLEN-1:0] IEUAdrE, // The next IEUAdrM
|
||||
input logic [2:0] Funct3M, // Size of memory operation
|
||||
input logic [1:0] MemRWM,
|
||||
input logic CacheableM,
|
||||
input logic [P.LLEN*2-1:0] DCacheReadDataWordM, // Instruction from the IROM, I$, or bus. Used to check if the instruction if compressed
|
||||
input logic CacheBusHPWTStall, // I$ or bus are stalled. Transition to second fetch of spill after the first is fetched
|
||||
input logic DTLBMissM, // ITLB miss, ignore memory request
|
||||
input logic DataUpdateDAM, // ITLB miss, ignore memory request
|
||||
input logic SelHPTW,
|
||||
|
||||
input logic [(P.LLEN-1)/8:0] ByteMaskM,
|
||||
|
@ -54,7 +51,6 @@ module align import cvw::*; #(parameter cvw_t P) (
|
|||
output logic [P.XLEN-1:0] IEUAdrSpillE, // The next PCF for one of the two memory addresses of the spill
|
||||
output logic [P.XLEN-1:0] IEUAdrSpillM, // IEUAdrM for one of the two memory addresses of the spill
|
||||
output logic SelSpillE, // During the transition between the two spill operations, the IFU should stall the pipeline
|
||||
output logic [1:0] MemRWSpillM,
|
||||
output logic SelStoreDelay, //*** this is bad. really don't like moving this outside
|
||||
output logic [P.LLEN-1:0] DCacheReadDataWordSpillM, // The final 32 bit instruction after merging the two spilled fetches into 1 instruction
|
||||
output logic SpillStallM);
|
||||
|
@ -65,26 +61,19 @@ module align import cvw::*; #(parameter cvw_t P) (
|
|||
typedef enum logic [1:0] {STATE_READY, STATE_SPILL, STATE_STORE_DELAY} statetype;
|
||||
|
||||
statetype CurrState, NextState;
|
||||
logic TakeSpillM;
|
||||
logic SpillM;
|
||||
logic ValidSpillM;
|
||||
logic SelSpillM;
|
||||
logic SpillSaveM;
|
||||
logic [P.LLEN-1:0] ReadDataWordFirstHalfM;
|
||||
logic [P.LLEN-1:0] ReadDataWordFirstHalfM;
|
||||
logic MisalignedM;
|
||||
logic [P.LLEN*2-1:0] ReadDataWordSpillAllM;
|
||||
logic [P.LLEN*2-1:0] ReadDataWordSpillShiftedM;
|
||||
|
||||
logic [P.XLEN-1:0] IEUAdrIncrementM;
|
||||
logic [P.XLEN-1:0] IEUAdrIncrementM;
|
||||
|
||||
logic [(P.LLEN-1)*2/8:0] ByteMaskSaveM;
|
||||
logic [(P.LLEN-1)*2/8:0] ByteMaskMuxM;
|
||||
logic SaveByteMask;
|
||||
logic HalfMisalignedM, WordMisalignedM;
|
||||
logic [OFFSET_BIT_POS-1:$clog2(LLENINBYTES)] WordOffsetM;
|
||||
logic [$clog2(LLENINBYTES)-1:0] ByteOffsetM;
|
||||
logic HalfSpillM, WordSpillM;
|
||||
logic [$clog2(LLENINBYTES)-1:0] AccessByteOffsetM;
|
||||
logic ValidAccess;
|
||||
logic [$clog2(LLENINBYTES)-1:0] AccessByteOffsetM;
|
||||
logic [$clog2(LLENINBYTES)+2:0] ShiftAmount;
|
||||
logic PotentialSpillM;
|
||||
|
||||
/* verilator lint_off WIDTHEXPAND */
|
||||
assign IEUAdrIncrementM = IEUAdrM + LLENINBYTES;
|
||||
|
@ -101,40 +90,26 @@ module align import cvw::*; #(parameter cvw_t P) (
|
|||
// 2) offset
|
||||
// 3) access location within the cacheline
|
||||
|
||||
assign {WordOffsetM, ByteOffsetM} = IEUAdrM[OFFSET_BIT_POS-1:0];
|
||||
|
||||
// compute misalignement
|
||||
always_comb begin
|
||||
case (Funct3M[1:0])
|
||||
2'b00: AccessByteOffsetM = '0; // byte access
|
||||
2'b01: AccessByteOffsetM = {2'b00, ByteOffsetM[0]}; // half access
|
||||
2'b10: AccessByteOffsetM = {1'b0, ByteOffsetM[1:0]}; // word access
|
||||
2'b11: AccessByteOffsetM = ByteOffsetM; // double access
|
||||
default: AccessByteOffsetM = ByteOffsetM;
|
||||
2'b01: AccessByteOffsetM = {2'b00, IEUAdrM[0]}; // half access
|
||||
2'b10: AccessByteOffsetM = {1'b0, IEUAdrM[1:0]}; // word access
|
||||
2'b11: AccessByteOffsetM = IEUAdrM[2:0]; // double access
|
||||
default: AccessByteOffsetM = IEUAdrM[2:0];
|
||||
endcase
|
||||
case (Funct3M[1:0])
|
||||
2'b00: PotentialSpillM = '0; // byte access
|
||||
2'b01: PotentialSpillM = IEUAdrM[OFFSET_BIT_POS-1:1] == '1; // half access
|
||||
2'b10: PotentialSpillM = IEUAdrM[OFFSET_BIT_POS-1:2] == '1; // word access
|
||||
2'b11: PotentialSpillM = IEUAdrM[OFFSET_BIT_POS-1:3] == '1; // double access
|
||||
default: PotentialSpillM = '0;
|
||||
endcase
|
||||
end
|
||||
|
||||
// compute misalignement
|
||||
assign HalfMisalignedM = (ByteOffsetM[0] != '0) & Funct3M[1:0] == 2'b01;
|
||||
assign WordMisalignedM = (ByteOffsetM[1:0] != '0) & Funct3M[1:0] == 2'b10;
|
||||
assign HalfSpillM = (IEUAdrM[OFFSET_BIT_POS-1:1] == '1) & HalfMisalignedM;
|
||||
assign WordSpillM = (IEUAdrM[OFFSET_BIT_POS-1:2] == '1) & WordMisalignedM;
|
||||
assign ValidAccess = (|MemRWM) & ~SelHPTW;
|
||||
|
||||
if(P.LLEN == 64) begin
|
||||
logic DoubleSpillM;
|
||||
logic DoubleMisalignedM;
|
||||
assign DoubleMisalignedM = (ByteOffsetM[2:0] != '0) & Funct3M[1:0] == 2'b11;
|
||||
assign DoubleSpillM = (IEUAdrM[OFFSET_BIT_POS-1:3] == '1) & DoubleMisalignedM;
|
||||
assign MisalignedM = ValidAccess & (HalfMisalignedM | WordMisalignedM | DoubleMisalignedM);
|
||||
assign SpillM = ValidAccess & CacheableM & (HalfSpillM | WordSpillM | DoubleSpillM);
|
||||
end else begin
|
||||
assign SpillM = ValidAccess & CacheableM & (HalfSpillM | WordSpillM);
|
||||
assign MisalignedM = ValidAccess & (HalfMisalignedM | WordMisalignedM);
|
||||
end
|
||||
assign MisalignedM = (|MemRWM) & (AccessByteOffsetM != '0);
|
||||
|
||||
// align by shifting
|
||||
// Don't take the spill if there is a stall, TLB miss, or hardware update to the D/A bits
|
||||
assign TakeSpillM = SpillM & ~CacheBusHPWTStall & ~(DTLBMissM | (P.SVADU_SUPPORTED & DataUpdateDAM));
|
||||
assign ValidSpillM = MisalignedM & PotentialSpillM & ~CacheBusHPWTStall; // Don't take the spill if there is a stall
|
||||
|
||||
always_ff @(posedge clk)
|
||||
if (reset | FlushM) CurrState <= #1 STATE_READY;
|
||||
|
@ -142,8 +117,8 @@ module align import cvw::*; #(parameter cvw_t P) (
|
|||
|
||||
always_comb begin
|
||||
case (CurrState)
|
||||
STATE_READY: if (TakeSpillM & ~MemRWM[0]) NextState = STATE_SPILL;
|
||||
else if(TakeSpillM & MemRWM[0])NextState = STATE_STORE_DELAY;
|
||||
STATE_READY: if (ValidSpillM & ~MemRWM[0]) NextState = STATE_SPILL;
|
||||
else if(ValidSpillM & MemRWM[0])NextState = STATE_STORE_DELAY;
|
||||
else NextState = STATE_READY;
|
||||
STATE_SPILL: if(StallM) NextState = STATE_SPILL;
|
||||
else NextState = STATE_READY;
|
||||
|
@ -153,12 +128,10 @@ module align import cvw::*; #(parameter cvw_t P) (
|
|||
end
|
||||
|
||||
assign SelSpillM = (CurrState == STATE_SPILL | CurrState == STATE_STORE_DELAY);
|
||||
assign SelSpillE = (CurrState == STATE_READY & TakeSpillM) | (CurrState == STATE_SPILL & CacheBusHPWTStall) | (CurrState == STATE_STORE_DELAY);
|
||||
assign SaveByteMask = (CurrState == STATE_READY & TakeSpillM);
|
||||
assign SpillSaveM = (CurrState == STATE_READY) & TakeSpillM & ~FlushM;
|
||||
assign SelSpillE = (CurrState == STATE_READY & ValidSpillM) | (CurrState == STATE_SPILL & CacheBusHPWTStall) | (CurrState == STATE_STORE_DELAY);
|
||||
assign SpillSaveM = (CurrState == STATE_READY) & ValidSpillM & ~FlushM;
|
||||
assign SelStoreDelay = (CurrState == STATE_STORE_DELAY); // *** Can this be merged into the PreLSURWM logic?
|
||||
assign SpillStallM = SelSpillE | CurrState == STATE_STORE_DELAY;
|
||||
mux2 #(2) memrwmux(MemRWM, 2'b00, SelStoreDelay, MemRWSpillM);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Merge spilled data
|
||||
|
@ -173,21 +146,20 @@ module align import cvw::*; #(parameter cvw_t P) (
|
|||
|
||||
// shifter (4:1 mux for 32 bit, 8:1 mux for 64 bit)
|
||||
// 8 * is for shifting by bytes not bits
|
||||
assign ReadDataWordSpillShiftedM = ReadDataWordSpillAllM >> (MisalignedM ? 8 * AccessByteOffsetM : '0);
|
||||
assign ShiftAmount = MisalignedM & ~SelHPTW ? {AccessByteOffsetM, 3'b0} : '0; // AND gate
|
||||
assign ReadDataWordSpillShiftedM = ReadDataWordSpillAllM >> ShiftAmount;
|
||||
assign DCacheReadDataWordSpillM = ReadDataWordSpillShiftedM[P.LLEN-1:0];
|
||||
|
||||
// write path. Also has the 8:1 shifter muxing for the byteoffset
|
||||
// then it also has the mux to select when a spill occurs
|
||||
logic [P.LLEN*3-1:0] LSUWriteDataShiftedExtM; // *** RT: Find a better way. I've extending in both directions so we don't shift in zeros. The cache expects the writedata to not have any zero data, but instead replicated data.
|
||||
|
||||
assign LSUWriteDataShiftedExtM = {LSUWriteDataM, LSUWriteDataM, LSUWriteDataM} << (MisalignedM ? 8 * AccessByteOffsetM : '0);
|
||||
assign LSUWriteDataShiftedExtM = {LSUWriteDataM, LSUWriteDataM, LSUWriteDataM} << ShiftAmount;
|
||||
assign LSUWriteDataSpillM = LSUWriteDataShiftedExtM[P.LLEN*3-1:P.LLEN];
|
||||
|
||||
mux3 #(2*P.LLEN/8) bytemaskspillmux(ByteMaskMuxM, // no spill
|
||||
mux3 #(2*P.LLEN/8) bytemaskspillmux({ByteMaskExtendedM, ByteMaskM}, // no spill
|
||||
{{{P.LLEN/8}{1'b0}}, ByteMaskM}, // spill, first half
|
||||
{{{P.LLEN/8}{1'b0}}, ByteMaskMuxM[P.LLEN*2/8-1:P.LLEN/8]}, // spill, second half
|
||||
{{{P.LLEN/8}{1'b0}}, ByteMaskExtendedM}, // spill, second half
|
||||
{SelSpillM, SelSpillE}, ByteMaskSpillM);
|
||||
|
||||
flopenr #(P.LLEN*2/8) bytemaskreg(clk, reset, SaveByteMask, {ByteMaskExtendedM, ByteMaskM}, ByteMaskSaveM);
|
||||
mux2 #(P.LLEN*2/8) bytemasksavemux({ByteMaskExtendedM, ByteMaskM}, ByteMaskSaveM, SelSpillM, ByteMaskMuxM);
|
||||
endmodule
|
||||
|
|
|
@ -159,10 +159,10 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
|||
if(MISALIGN_SUPPORT) begin : ziccslm_align
|
||||
logic [P.XLEN-1:0] IEUAdrSpillE, IEUAdrSpillM;
|
||||
align #(P) align(.clk, .reset, .StallM, .FlushM, .IEUAdrE, .IEUAdrM, .Funct3M,
|
||||
.MemRWM, .CacheableM,
|
||||
.DCacheReadDataWordM, .CacheBusHPWTStall, .DTLBMissM, .DataUpdateDAM, .SelHPTW,
|
||||
.MemRWM,
|
||||
.DCacheReadDataWordM, .CacheBusHPWTStall, .SelHPTW,
|
||||
.ByteMaskM, .ByteMaskExtendedM, .LSUWriteDataM, .ByteMaskSpillM, .LSUWriteDataSpillM,
|
||||
.IEUAdrSpillE, .IEUAdrSpillM, .SelSpillE, .MemRWSpillM, .DCacheReadDataWordSpillM, .SpillStallM,
|
||||
.IEUAdrSpillE, .IEUAdrSpillM, .SelSpillE, .DCacheReadDataWordSpillM, .SpillStallM,
|
||||
.SelStoreDelay);
|
||||
assign IEUAdrExtM = {2'b00, IEUAdrSpillM};
|
||||
assign IEUAdrExtE = {2'b00, IEUAdrSpillE};
|
||||
|
@ -301,12 +301,14 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
|||
logic FlushDCache; // Suppress d cache flush if there is an ITLB miss.
|
||||
logic CacheStall;
|
||||
logic [1:0] CacheBusRWTemp;
|
||||
logic BusCMOZero;
|
||||
|
||||
if(P.ZICBOZ_SUPPORTED) begin
|
||||
assign BusRW = ~CacheableM & ~SelDTIM ? CMOpM[3] ? 2'b01 : LSURWM : '0;
|
||||
assign BusCMOZero = CMOpM[3] & ~CacheableM;
|
||||
end else begin
|
||||
assign BusRW = ~CacheableM & ~SelDTIM ? LSURWM : '0;
|
||||
assign BusCMOZero = '0;
|
||||
end
|
||||
assign BusRW = ~CacheableM & ~SelDTIM ? LSURWM : '0;
|
||||
assign CacheableOrFlushCacheM = CacheableM | FlushDCacheM;
|
||||
assign CacheRWM = CacheableM & ~SelDTIM ? LSURWM : '0;
|
||||
assign FlushDCache = FlushDCacheM & ~(SelHPTW);
|
||||
|
@ -332,7 +334,7 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
|||
.HRDATA, .HWDATA(LSUHWDATA), .HWSTRB(LSUHWSTRB),
|
||||
.HSIZE(LSUHSIZE), .HBURST(LSUHBURST), .HTRANS(LSUHTRANS), .HWRITE(LSUHWRITE), .HREADY(LSUHREADY),
|
||||
.BeatCount, .SelBusBeat, .CacheReadDataWordM(DCacheReadDataWordM[P.LLEN-1:0]), .WriteDataM(LSUWriteDataM),
|
||||
.Funct3(LSUFunct3M), .HADDR(LSUHADDR), .CacheBusAdr(DCacheBusAdr), .CacheBusRW, .CacheableOrFlushCacheM,
|
||||
.Funct3(LSUFunct3M), .HADDR(LSUHADDR), .CacheBusAdr(DCacheBusAdr), .CacheBusRW, .BusCMOZero, .CacheableOrFlushCacheM,
|
||||
.CacheBusAck(DCacheBusAck), .FetchBuffer, .PAdr(PAdrM),
|
||||
.Cacheable(CacheableOrFlushCacheM), .BusRW, .Stall(GatedStallW),
|
||||
.BusStall, .BusCommitted(BusCommittedM));
|
||||
|
|
|
@ -30,18 +30,18 @@
|
|||
|
||||
module adrdecs import cvw::*; #(parameter cvw_t P) (
|
||||
input logic [P.PA_BITS-1:0] PhysicalAddress,
|
||||
input logic AccessRW, AccessRX, AccessRWXZ, AccessRWZ, AccessRXZ,
|
||||
input logic AccessRW, AccessRX, AccessRWXC,
|
||||
input logic [1:0] Size,
|
||||
output logic [11:0] SelRegions
|
||||
);
|
||||
|
||||
localparam logic [3:0] SUPPORTED_SIZE = (P.LLEN == 32 ? 4'b0111 : 4'b1111);
|
||||
// Determine which region of physical memory (if any) is being accessed
|
||||
adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRWZ, Size, SUPPORTED_SIZE, SelRegions[11]);
|
||||
adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRXZ, Size, SUPPORTED_SIZE, SelRegions[10]);
|
||||
adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWXZ, Size, SUPPORTED_SIZE, SelRegions[9]);
|
||||
adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRXZ, Size, SUPPORTED_SIZE, SelRegions[8]);
|
||||
adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWXZ, Size, SUPPORTED_SIZE, SelRegions[7]);
|
||||
adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[11]);
|
||||
adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[10]);
|
||||
adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[9]);
|
||||
adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[8]);
|
||||
adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[7]);
|
||||
adrdec #(P.PA_BITS) clintdec(PhysicalAddress, P.CLINT_BASE[P.PA_BITS-1:0], P.CLINT_RANGE[P.PA_BITS-1:0], P.CLINT_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[6]);
|
||||
adrdec #(P.PA_BITS) gpiodec(PhysicalAddress, P.GPIO_BASE[P.PA_BITS-1:0], P.GPIO_RANGE[P.PA_BITS-1:0], P.GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[5]);
|
||||
adrdec #(P.PA_BITS) uartdec(PhysicalAddress, P.UART_BASE[P.PA_BITS-1:0], P.UART_RANGE[P.PA_BITS-1:0], P.UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[4]);
|
||||
|
|
|
@ -85,7 +85,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
|
|||
.SATP_MODE(SATP_REGW[P.XLEN-1:P.XLEN-P.SVMODE_BITS]),
|
||||
.SATP_ASID(SATP_REGW[P.ASID_BASE+P.ASID_BITS-1:P.ASID_BASE]),
|
||||
.VAdr(VAdr[P.XLEN-1:0]), .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_HADE,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess, .CMOp,
|
||||
.DisableTranslation, .PTE, .PageTypeWriteVal,
|
||||
.TLBWrite, .TLBFlush, .TLBPAdr, .TLBMiss, .TLBHit,
|
||||
.Translate, .TLBPageFault, .UpdateDA, .PBMemoryType);
|
||||
|
@ -115,7 +115,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,
|
||||
.ExecuteAccessF, .WriteAccessM, .ReadAccessM, .CMOp,
|
||||
.PMPInstrAccessFaultF, .PMPLoadAccessFaultM, .PMPStoreAmoAccessFaultM);
|
||||
end else begin
|
||||
assign PMPInstrAccessFaultF = 0;
|
||||
|
|
|
@ -44,20 +44,18 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
|
|||
);
|
||||
|
||||
logic PMAAccessFault;
|
||||
logic AccessRW, AccessRWXZ, AccessRX, AccessRWZ, AccessRXZ;
|
||||
logic AccessRW, AccessRWXC, AccessRX;
|
||||
logic [11:0] SelRegions;
|
||||
logic AtomicAllowed;
|
||||
logic CacheableRegion, IdempotentRegion;
|
||||
|
||||
// Determine what type of access is being made
|
||||
assign AccessRW = ReadAccessM | WriteAccessM;
|
||||
assign AccessRWZ = AccessRW | (P.ZICBOM_SUPPORTED & (|CMOp[2:0]));
|
||||
assign AccessRWXZ = ReadAccessM | WriteAccessM | ExecuteAccessF | (P.ZICBOM_SUPPORTED & (|CMOp[2:0])) | (P.ZICBOZ_SUPPORTED & (CMOp[3]));
|
||||
assign AccessRWXC = ReadAccessM | WriteAccessM | ExecuteAccessF | (|CMOp);
|
||||
assign AccessRX = ReadAccessM | ExecuteAccessF;
|
||||
assign AccessRXZ = AccessRX | (P.ZICBOM_SUPPORTED & (|CMOp[2:0]));
|
||||
|
||||
// Determine which region of physical memory (if any) is being accessed
|
||||
adrdecs #(P) adrdecs(PhysicalAddress, AccessRW, AccessRX, AccessRWXZ, AccessRWZ, AccessRXZ, Size, SelRegions);
|
||||
adrdecs #(P) adrdecs(PhysicalAddress, AccessRW, AccessRX, AccessRWXC, Size, SelRegions);
|
||||
|
||||
// Only non-core RAM/ROM memory regions are cacheable. PBMT can override cachable; NC and IO are uncachable
|
||||
assign CacheableRegion = SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-cachable
|
||||
|
@ -74,8 +72,8 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
|
|||
assign SelTIM = SelRegions[11] | SelRegions[10]; // exclusion-tag: unused-idempotent
|
||||
|
||||
// Detect access faults
|
||||
assign PMAAccessFault = (SelRegions[0]) & AccessRWXZ | AtomicAccessM & ~AtomicAllowed;
|
||||
assign PMAAccessFault = (SelRegions[0]) & AccessRWXC | AtomicAccessM & ~AtomicAllowed;
|
||||
assign PMAInstrAccessFaultF = ExecuteAccessF & PMAAccessFault;
|
||||
assign PMALoadAccessFaultM = ReadAccessM & PMAAccessFault;
|
||||
assign PMAStoreAmoAccessFaultM = WriteAccessM & PMAAccessFault;
|
||||
assign PMAStoreAmoAccessFaultM = (WriteAccessM | (|CMOp)) & PMAAccessFault;
|
||||
endmodule
|
||||
|
|
|
@ -42,6 +42,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 [3:0] CMOp,
|
||||
output logic PMPInstrAccessFaultF,
|
||||
output logic PMPLoadAccessFaultM,
|
||||
output logic PMPStoreAmoAccessFaultM
|
||||
|
@ -53,6 +54,8 @@ 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 PMPCMOAccessFault, PMPCBOMAccessFault, PMPCBOZAccessFault;
|
||||
|
||||
|
||||
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](
|
||||
|
@ -69,7 +72,11 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) (
|
|||
// 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)); // *** switch to this logic when PMP is initialized for non-machine mode
|
||||
|
||||
assign PMPCBOMAccessFault = EnforcePMP & (|CMOp[2:0]) & ~|((R|W) & FirstMatch) ;
|
||||
assign PMPCBOZAccessFault = EnforcePMP & CMOp[3] & ~|(W & FirstMatch) ;
|
||||
assign PMPCMOAccessFault = PMPCBOZAccessFault | PMPCBOMAccessFault;
|
||||
|
||||
assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|(X & FirstMatch) ;
|
||||
assign PMPStoreAmoAccessFaultM = EnforcePMP & WriteAccessM & ~|(W & FirstMatch) ;
|
||||
assign PMPStoreAmoAccessFaultM = (EnforcePMP & WriteAccessM & ~|(W & FirstMatch)) | PMPCMOAccessFault;
|
||||
assign PMPLoadAccessFaultM = EnforcePMP & ReadAccessM & ~|(R & FirstMatch) ;
|
||||
endmodule
|
||||
|
|
|
@ -62,6 +62,7 @@ module tlb import cvw::*; #(parameter cvw_t P,
|
|||
input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor
|
||||
input logic ReadAccess,
|
||||
input logic WriteAccess,
|
||||
input logic [3:0] CMOp,
|
||||
input logic DisableTranslation,
|
||||
input logic [P.XLEN-1:0] VAdr, // address input before translation (could be physical or virtual)
|
||||
input logic [P.XLEN-1:0] PTE, // page table entry to write
|
||||
|
@ -106,7 +107,7 @@ module tlb import cvw::*; #(parameter cvw_t P,
|
|||
assign VPN = VAdr[P.VPN_BITS+11:12];
|
||||
|
||||
tlbcontrol #(P, ITLB) tlbcontrol(.SATP_MODE, .VAdr, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_HADE,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess, .DisableTranslation, .TLBFlush,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess, .CMOp, .DisableTranslation, .TLBFlush,
|
||||
.PTEAccessBits, .CAMHit, .Misaligned,
|
||||
.TLBMiss, .TLBHit, .TLBPageFault,
|
||||
.UpdateDA, .SV39Mode, .Translate, .PTE_N, .PBMemoryType);
|
||||
|
|
|
@ -35,6 +35,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
|||
input logic ENVCFG_HADE, // HPTW A/D Update enable
|
||||
input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor
|
||||
input logic ReadAccess, WriteAccess,
|
||||
input logic [3:0] CMOp,
|
||||
input logic DisableTranslation,
|
||||
input logic TLBFlush, // Invalidate all TLB entries
|
||||
input logic [11:0] PTEAccessBits,
|
||||
|
@ -67,7 +68,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
|||
assign Translate = (SATP_MODE != P.NO_TRANSLATE[P.SVMODE_BITS-1:0]) & (EffectivePrivilegeMode != P.M_MODE) & ~DisableTranslation;
|
||||
|
||||
// Determine whether TLB is being used
|
||||
assign TLBAccess = ReadAccess | WriteAccess;
|
||||
assign TLBAccess = ReadAccess | WriteAccess | (|CMOp);
|
||||
|
||||
// Check that upper bits are legal (all 0s or all 1s)
|
||||
vm64check #(P) vm64check(.SATP_MODE, .VAdr, .SV39Mode, .UpperBitsUnequal);
|
||||
|
@ -98,6 +99,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
|||
assign InvalidAccess = ~PTE_X;
|
||||
end else begin:dtlb // Data TLB fault checking
|
||||
logic InvalidRead, InvalidWrite;
|
||||
logic InvalidCBOM, InvalidCBOZ;
|
||||
|
||||
// User mode may only load/store from user mode pages, and supervisor mode
|
||||
// may only access user mode pages when STATUS_SUM is low.
|
||||
|
@ -110,7 +112,9 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
|||
// Check for write error. Writes are invalid when the page's write bit is
|
||||
// low.
|
||||
assign InvalidWrite = WriteAccess & ~PTE_W;
|
||||
assign InvalidAccess = InvalidRead | InvalidWrite;
|
||||
assign InvalidCBOM = (|CMOp[2:0]) & (~PTE_W | (~PTE_R & (~STATUS_MXR | ~PTE_X)));
|
||||
assign InvalidCBOZ = CMOp[3] & ~PTE_W;
|
||||
assign InvalidAccess = InvalidRead | InvalidWrite | InvalidCBOM | InvalidCBOZ;
|
||||
assign PreUpdateDA = ~PTE_A | WriteAccess & ~PTE_D;
|
||||
end
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ module uncore import cvw::*; #(parameter cvw_t P)(
|
|||
// Determine which region of physical memory (if any) is being accessed
|
||||
// Use a trimmed down portion of the PMA checker - only the address decoders
|
||||
// Set access types to all 1 as don't cares because the MMU has already done access checking
|
||||
adrdecs #(P) adrdecs(HADDR, 1'b1, 1'b1, 1'b1, 1'b1, 1'b1, HSIZE[1:0], HSELRegions);
|
||||
adrdecs #(P) adrdecs(HADDR, 1'b1, 1'b1, 1'b1, HSIZE[1:0], HSELRegions);
|
||||
|
||||
// unswizzle HSEL signals
|
||||
assign {HSELDTIM, HSELIROM, HSELEXT, HSELBootRom, HSELRam, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC, HSELEXTSDC, HSELSPI} = HSELRegions[11:1];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue