diff --git a/tests/custom/zsbl/Makefile b/fpga/zsbl/Makefile similarity index 98% rename from tests/custom/zsbl/Makefile rename to fpga/zsbl/Makefile index 6dec9c797..bd30033fc 100644 --- a/tests/custom/zsbl/Makefile +++ b/fpga/zsbl/Makefile @@ -21,7 +21,7 @@ ROOT := .. LIBRARY_DIRS := LIBRARY_FILES := -MARCH :=-march=rv64imfdc +MARCH :=-march=rv64imfdc_zifencei MABI :=-mabi=lp64d LINK_FLAGS :=$(MARCH) $(MABI) -nostartfiles LINKER :=linker.x diff --git a/tests/custom/zsbl/bios.s b/fpga/zsbl/bios.s similarity index 97% rename from tests/custom/zsbl/bios.s rename to fpga/zsbl/bios.s index ebeadcf59..7954eab7a 100644 --- a/tests/custom/zsbl/bios.s +++ b/fpga/zsbl/bios.s @@ -94,5 +94,5 @@ end_of_bios: .globl _dtb .align 4, 0 _dtb: -.incbin "wally-vcu118.dtb" +#.incbin "wally-vcu118.dtb" diff --git a/tests/custom/zsbl/copyFlash.c b/fpga/zsbl/copyFlash.c similarity index 100% rename from tests/custom/zsbl/copyFlash.c rename to fpga/zsbl/copyFlash.c diff --git a/tests/custom/zsbl/gpt.c b/fpga/zsbl/gpt.c similarity index 100% rename from tests/custom/zsbl/gpt.c rename to fpga/zsbl/gpt.c diff --git a/tests/custom/zsbl/gpt.h b/fpga/zsbl/gpt.h similarity index 100% rename from tests/custom/zsbl/gpt.h rename to fpga/zsbl/gpt.h diff --git a/tests/custom/zsbl/main.c b/fpga/zsbl/main.c similarity index 100% rename from tests/custom/zsbl/main.c rename to fpga/zsbl/main.c diff --git a/tests/custom/zsbl/sdcDriver.c b/fpga/zsbl/sdcDriver.c similarity index 98% rename from tests/custom/zsbl/sdcDriver.c rename to fpga/zsbl/sdcDriver.c index edbe0677d..45caa42fa 100644 --- a/tests/custom/zsbl/sdcDriver.c +++ b/fpga/zsbl/sdcDriver.c @@ -1,7 +1,7 @@ /////////////////////////////////////////// // SDC.sv // -// Written: Ross Thompson September 25, 2021 +// Written: Rose Thompson September 25, 2021 // Modified: // // Purpose: driver for sdc reader. diff --git a/tests/custom/zsbl/sdcDriver.h b/fpga/zsbl/sdcDriver.h similarity index 100% rename from tests/custom/zsbl/sdcDriver.h rename to fpga/zsbl/sdcDriver.h diff --git a/tests/custom/zsbl/smp.h b/fpga/zsbl/smp.h similarity index 100% rename from tests/custom/zsbl/smp.h rename to fpga/zsbl/smp.h diff --git a/tests/custom/zsbl/uart.c b/fpga/zsbl/uart.c similarity index 100% rename from tests/custom/zsbl/uart.c rename to fpga/zsbl/uart.c diff --git a/tests/custom/zsbl/uart.h b/fpga/zsbl/uart.h similarity index 100% rename from tests/custom/zsbl/uart.h rename to fpga/zsbl/uart.h diff --git a/src/cache/cache.sv b/src/cache/cache.sv index 058d160fa..2edf867e2 100644 --- a/src/cache/cache.sv +++ b/src/cache/cache.sv @@ -82,7 +82,7 @@ module cache import cvw::*; #(parameter cvw_t P, logic ClearDirty, SetDirty, SetValid, ClearValid; logic [LINELEN-1:0] ReadDataLineWay [NUMWAYS-1:0]; logic [NUMWAYS-1:0] HitWay, ValidWay; - logic CacheHit; + logic Hit; logic [NUMWAYS-1:0] VictimWay, DirtyWay, HitDirtyWay; logic LineDirty, HitLineDirty; logic [TAGLEN-1:0] TagWay [NUMWAYS-1:0]; @@ -98,7 +98,7 @@ module cache import cvw::*; #(parameter cvw_t P, logic [LINELEN-1:0] ReadDataLine, ReadDataLineCache; logic SelFetchBuffer; logic CacheEn; - logic SelWay; + logic SelVictim; logic [LINELEN/8-1:0] LineByteMask; logic [$clog2(LINELEN/8) - $clog2(MUXINTERVAL/8) - 1:0] WordOffsetAddr; genvar index; @@ -120,7 +120,7 @@ module cache import cvw::*; #(parameter cvw_t P, // Array of cache ways, along with victim, hit, dirty, and read merging logic cacheway #(P, PA_BITS, XLEN, NUMLINES, LINELEN, TAGLEN, OFFSETLEN, SETLEN, READ_ONLY_CACHE) CacheWays[NUMWAYS-1:0]( - .clk, .reset, .CacheEn, .CacheSetData, .CacheSetTag, .PAdr, .LineWriteData, .LineByteMask, .SelWay, + .clk, .reset, .CacheEn, .CacheSetData, .CacheSetTag, .PAdr, .LineWriteData, .LineByteMask, .SelVictim, .SetValid, .ClearValid, .SetDirty, .ClearDirty, .VictimWay, .FlushWay, .FlushCache, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .HitDirtyWay, .TagWay, .FlushStage, .InvalidateCache); @@ -132,7 +132,7 @@ module cache import cvw::*; #(parameter cvw_t P, end else assign VictimWay = 1'b1; // one hot. - assign CacheHit = |HitWay; + assign Hit = |HitWay; assign LineDirty = |DirtyWay; assign HitLineDirty = |HitDirtyWay; @@ -180,14 +180,14 @@ module cache import cvw::*; #(parameter cvw_t P, assign DemuxedByteMask = BlankByteMask << ((MUXINTERVAL/8) * WordOffsetAddr); - assign FetchBufferByteSel = SetValid & ~SetDirty ? '1 : ~DemuxedByteMask; // If load miss set all muxes to 1. + assign FetchBufferByteSel = SetDirty ? ~DemuxedByteMask : '1; // If load miss set all muxes to 1. // Merge write data into fetched cache line for store miss for(index = 0; index < LINELEN/8; index++) begin mux2 #(8) WriteDataMux(.d0(CacheWriteData[(8*index)%WORDLEN+7:(8*index)%WORDLEN]), .d1(FetchBuffer[8*index+7:8*index]), .s(FetchBufferByteSel[index] & ~CMOpM[3]), .y(LineWriteData[8*index+7:8*index])); end - assign LineByteMask = SetValid ? '1 : SetDirty ? DemuxedByteMask : 0; + assign LineByteMask = SetDirty ? DemuxedByteMask : '1; end else begin:WriteSelLogic @@ -226,8 +226,8 @@ module cache import cvw::*; #(parameter cvw_t P, cachefsm #(P, READ_ONLY_CACHE) cachefsm(.clk, .reset, .CacheBusRW, .CacheBusAck, .FlushStage, .CacheRW, .Stall, - .CacheHit, .LineDirty, .HitLineDirty, .CacheStall, .CacheCommitted, - .CacheMiss, .CacheAccess, .SelAdrData, .SelAdrTag, .SelWay, + .Hit, .LineDirty, .HitLineDirty, .CacheStall, .CacheCommitted, + .CacheMiss, .CacheAccess, .SelAdrData, .SelAdrTag, .SelVictim, .ClearDirty, .SetDirty, .SetValid, .ClearValid, .SelWriteback, .FlushAdrCntEn, .FlushWayCntEn, .FlushCntRst, .FlushAdrFlag, .FlushWayFlag, .FlushCache, .SelFetchBuffer, diff --git a/src/cache/cacheLRU.sv b/src/cache/cacheLRU.sv index 2b585aaa5..cdd513547 100644 --- a/src/cache/cacheLRU.sv +++ b/src/cache/cacheLRU.sv @@ -1,7 +1,7 @@ /////////////////////////////////////////// // cacheLRU.sv // -// Written: Ross Thompson ross1728@gmail.com +// Written: Rose Thompson ross1728@gmail.com // Created: 20 July 2021 // Modified: 20 January 2023 // @@ -36,8 +36,8 @@ module cacheLRU input logic CacheEn, // Enable the cache memory arrays. Disable hold read data constant input logic [NUMWAYS-1:0] HitWay, // Which way is valid and matches PAdr's tag input logic [NUMWAYS-1:0] ValidWay, // Which ways for a particular set are valid, ignores tag - input logic [SETLEN-1:0] CacheSetData, // Cache address, the output of the address select mux, NextAdr, PAdr, or FlushAdr - input logic [SETLEN-1:0] CacheSetTag, // Cache address, the output of the address select mux, NextAdr, PAdr, or FlushAdr + input logic [SETLEN-1:0] CacheSetData, // Cache address, the output of the address select mux, NextAdr, PAdr, or FlushAdr + input logic [SETLEN-1:0] CacheSetTag, // Cache address, the output of the address select mux, NextAdr, PAdr, or FlushAdr input logic [SETLEN-1:0] PAdr, // Physical address input logic LRUWriteEn, // Update the LRU state input logic SetValid, // Set the dirty bit in the selected way and set @@ -51,23 +51,27 @@ module cacheLRU logic [NUMWAYS-2:0] LRUMemory [NUMLINES-1:0]; logic [NUMWAYS-2:0] CurrLRU; logic [NUMWAYS-2:0] NextLRU; - logic [NUMWAYS-1:0] Way; - logic [LOGNUMWAYS-1:0] WayEncoded; + logic [LOGNUMWAYS-1:0] HitWayEncoded, Way; logic [NUMWAYS-2:0] WayExpanded; logic AllValid; genvar row; /* verilator lint_off UNOPTFLAT */ - // Ross: For some reason verilator does not like this. I checked and it is not a circular path. + // Rose: For some reason verilator does not like this. I checked and it is not a circular path. logic [NUMWAYS-2:0] LRUUpdate; logic [LOGNUMWAYS-1:0] Intermediate [NUMWAYS-2:0]; /* verilator lint_on UNOPTFLAT */ + logic [NUMWAYS-1:0] FirstZero; + logic [LOGNUMWAYS-1:0] FirstZeroWay; + logic [LOGNUMWAYS-1:0] VictimWayEnc; + + binencoder #(NUMWAYS) hitwayencoder(HitWay, HitWayEncoded); + assign AllValid = &ValidWay; ///// Update replacement bits. - // coverage off // Excluded from coverage b/c it is untestable without varying NUMWAYS. function integer log2 (integer value); @@ -80,8 +84,7 @@ module cacheLRU // coverage on // On a miss we need to ignore HitWay and derive the new replacement bits with the VictimWay. - mux2 #(NUMWAYS) WayMux(HitWay, VictimWay, SetValid, Way); - binencoder #(NUMWAYS) encoder(Way, WayEncoded); + mux2 #(LOGNUMWAYS) WayMuxEnc(HitWayEncoded, VictimWayEnc, SetValid, Way); // bit duplication // expand HitWay as HitWay[3], {{2}{HitWay[2]}}, {{4}{HitWay[1]}, {{8{HitWay[0]}}, ... @@ -89,7 +92,7 @@ module cacheLRU localparam integer DuplicationFactor = 2**(LOGNUMWAYS-row-1); localparam StartIndex = NUMWAYS-2 - DuplicationFactor + 1; localparam EndIndex = NUMWAYS-2 - 2 * DuplicationFactor + 2; - assign WayExpanded[StartIndex : EndIndex] = {{DuplicationFactor}{WayEncoded[row]}}; + assign WayExpanded[StartIndex : EndIndex] = {{DuplicationFactor}{Way[row]}}; end genvar node; @@ -102,14 +105,14 @@ module cacheLRU localparam r = LOGNUMWAYS - ctr_depth; // the child node will be updated if its parent was updated and - // the WayEncoded bit was the correct value. + // the Way bit was the correct value. // The if statement is only there for coverage since LRUUpdate[root] is always 1. if (node == NUMWAYS-2) begin - assign LRUUpdate[lchild] = ~WayEncoded[r]; - assign LRUUpdate[rchild] = WayEncoded[r]; + assign LRUUpdate[lchild] = ~Way[r]; + assign LRUUpdate[rchild] = Way[r]; end else begin - assign LRUUpdate[lchild] = LRUUpdate[node] & ~WayEncoded[r]; - assign LRUUpdate[rchild] = LRUUpdate[node] & WayEncoded[r]; + assign LRUUpdate[lchild] = LRUUpdate[node] & ~Way[r]; + assign LRUUpdate[rchild] = LRUUpdate[node] & Way[r]; end end @@ -129,28 +132,25 @@ module cacheLRU assign Intermediate[node] = CurrLRU[node] ? int1[LOGNUMWAYS-1:0] : int0[LOGNUMWAYS-1:0]; end - logic [NUMWAYS-1:0] FirstZero; - logic [LOGNUMWAYS-1:0] FirstZeroWay; - logic [LOGNUMWAYS-1:0] VictimWayEnc; priorityonehot #(NUMWAYS) FirstZeroEncoder(~ValidWay, FirstZero); binencoder #(NUMWAYS) FirstZeroWayEncoder(FirstZero, FirstZeroWay); mux2 #(LOGNUMWAYS) VictimMux(FirstZeroWay, Intermediate[NUMWAYS-2], AllValid, VictimWayEnc); - //decoder #(LOGNUMWAYS) decoder (Intermediate[NUMWAYS-2], VictimWay); decoder #(LOGNUMWAYS) decoder (VictimWayEnc, VictimWay); // LRU storage must be reset for modelsim to run. However the reset value does not actually matter in practice. // This is a two port memory. // Every cycle must read from CacheSetData and each load/store must write the new LRU. always_ff @(posedge clk) begin - if (reset | (InvalidateCache & ~FlushStage)) for (int set = 0; set < NUMLINES; set++) LRUMemory[set] <= 0; + if (reset | (InvalidateCache & ~FlushStage)) + for (int set = 0; set < NUMLINES; set++) LRUMemory[set] <= 0; // exclusion-tag: initialize if(CacheEn) begin if(LRUWriteEn) LRUMemory[PAdr] <= NextLRU; if(LRUWriteEn & (PAdr == CacheSetTag)) - CurrLRU <= NextLRU; + CurrLRU <= #1 NextLRU; else - CurrLRU <= LRUMemory[CacheSetTag]; + CurrLRU <= #1 LRUMemory[CacheSetTag]; end end diff --git a/src/cache/cachefsm.sv b/src/cache/cachefsm.sv index 4af89b08e..0059bb81d 100644 --- a/src/cache/cachefsm.sv +++ b/src/cache/cachefsm.sv @@ -50,7 +50,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P, output logic CacheAccess, // Cache access // cache internals - input logic CacheHit, // Exactly 1 way hits + input logic Hit, // Exactly 1 way hits input logic LineDirty, // The selected line and way is dirty input logic HitLineDirty, // The cache hit way is dirty input logic FlushAdrFlag, // On last set of a cache flush @@ -63,7 +63,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P, output logic ClearDirty, // Clear the dirty bit in the selected way and set output logic SelWriteback, // Overrides cached tag check to select a specific way and set for writeback output logic LRUWriteEn, // Update the LRU state - output logic SelWay, // Controls which way to select a way data and tag, 00 = hitway, 10 = victimway, 11 = flushway + output logic SelVictim, // Overides HitWay Tag matching. Selects selects the victim tag/data regardless of hit output logic FlushAdrCntEn, // Enable the counter for Flush Adr output logic FlushWayCntEn, // Enable the way counter during a flush output logic FlushCntRst, // Reset both flush counters @@ -79,12 +79,12 @@ module cachefsm import cvw::*; #(parameter cvw_t P, logic CMOZeroNoEviction; logic StallConditions; - typedef enum logic [3:0]{STATE_READY, // hit states + typedef enum logic [3:0]{STATE_ACCESS, // hit states // miss states STATE_FETCH, STATE_WRITEBACK, STATE_WRITE_LINE, - STATE_READ_HOLD, // required for back to back reads. structural hazard on writting SRAM + STATE_ADDRESS_SETUP, // required for back to back reads. structural hazard on writting SRAM // flush cache STATE_FLUSH, STATE_FLUSH_WRITEBACK @@ -92,60 +92,60 @@ module cachefsm import cvw::*; #(parameter cvw_t P, statetype CurrState, NextState; - 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 AnyMiss = (CacheRW[0] | CacheRW[1]) & ~Hit & ~InvalidateCache; // exclusion-tag: cache AnyMiss + assign AnyUpdateHit = (CacheRW[0]) & Hit; // exclusion-tag: icache storeAMO1 + assign AnyHit = AnyUpdateHit | (CacheRW[1] & Hit); // exclusion-tag: icache AnyUpdateHit assign CMOZeroNoEviction = CMOpM[3] & ~LineDirty; // (hit or miss) with no writeback store zeros now - assign CMOWriteback = ((CMOpM[1] | CMOpM[2]) & CacheHit & HitLineDirty) | CMOpM[3] & LineDirty; + assign CMOWriteback = ((CMOpM[1] | CMOpM[2]) & Hit & HitLineDirty) | CMOpM[3] & LineDirty; assign FlushFlag = FlushAdrFlag & FlushWayFlag; // outputs for the performance counters. - assign CacheAccess = (|CacheRW) & ((CurrState == STATE_READY & ~Stall & ~FlushStage) | (CurrState == STATE_READ_HOLD & ~Stall & ~FlushStage)); // exclusion-tag: icache CacheW - assign CacheMiss = CacheAccess & ~CacheHit; + assign CacheAccess = (|CacheRW) & ((CurrState == STATE_ACCESS & ~Stall & ~FlushStage) | (CurrState == STATE_ADDRESS_SETUP & ~Stall & ~FlushStage)); // exclusion-tag: icache CacheW + assign CacheMiss = CacheAccess & ~Hit; - // special case on reset. When the fsm first exists reset the + // special case on reset. When the fsm first exists reset twayhe // PCNextF will no longer be pointing to the correct address. // But PCF will be the reset vector. flop #(1) resetDelayReg(.clk, .d(reset), .q(resetDelay)); always_ff @(posedge clk) - if (reset | FlushStage) CurrState <= #1 STATE_READY; + if (reset | FlushStage) CurrState <= #1 STATE_ACCESS; else CurrState <= #1 NextState; always_comb begin - NextState = STATE_READY; + NextState = STATE_ACCESS; case (CurrState) // exclusion-tag: icache state-case - STATE_READY: if(InvalidateCache) NextState = STATE_READY; // exclusion-tag: dcache InvalidateCheck + STATE_ACCESS: if(InvalidateCache) NextState = STATE_ACCESS; // exclusion-tag: dcache InvalidateCheck else if(FlushCache & ~READ_ONLY_CACHE) NextState = STATE_FLUSH; // exclusion-tag: icache FLUSHStatement else if(AnyMiss & (READ_ONLY_CACHE | ~LineDirty)) NextState = STATE_FETCH; // exclusion-tag: icache FETCHStatement else if((AnyMiss | CMOWriteback) & ~READ_ONLY_CACHE) NextState = STATE_WRITEBACK; // exclusion-tag: icache WRITEBACKStatement - else NextState = STATE_READY; + else NextState = STATE_ACCESS; STATE_FETCH: if(CacheBusAck) NextState = STATE_WRITE_LINE; else NextState = STATE_FETCH; - STATE_WRITE_LINE: NextState = STATE_READ_HOLD; - STATE_READ_HOLD: if(Stall) NextState = STATE_READ_HOLD; - else NextState = STATE_READY; + STATE_WRITE_LINE: NextState = STATE_ADDRESS_SETUP; + STATE_ADDRESS_SETUP: if(Stall) NextState = STATE_ADDRESS_SETUP; + else NextState = STATE_ACCESS; // exclusion-tag-start: icache case STATE_WRITEBACK: if(CacheBusAck & ~(|CMOpM[3:1])) NextState = STATE_FETCH; - else if(CacheBusAck) NextState = STATE_READ_HOLD; // Read_hold lowers CacheStall + else if(CacheBusAck) NextState = STATE_ADDRESS_SETUP; // 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; - else if (FlushFlag) NextState = STATE_READ_HOLD; + else if (FlushFlag) NextState = STATE_ADDRESS_SETUP; else NextState = STATE_FLUSH; STATE_FLUSH_WRITEBACK: if(CacheBusAck & ~FlushFlag) NextState = STATE_FLUSH; - else if(CacheBusAck) NextState = STATE_READ_HOLD; + else if(CacheBusAck) NextState = STATE_ADDRESS_SETUP; else NextState = STATE_FLUSH_WRITEBACK; // exclusion-tag-end: icache case - default: NextState = STATE_READY; + default: NextState = STATE_ACCESS; endcase end // com back to CPU - assign CacheCommitted = (CurrState != STATE_READY) & ~(READ_ONLY_CACHE & (CurrState == STATE_READ_HOLD)); + assign CacheCommitted = (CurrState != STATE_ACCESS) & ~(READ_ONLY_CACHE & (CurrState == STATE_ADDRESS_SETUP)); assign StallConditions = FlushCache | AnyMiss | CMOWriteback; // exclusion-tag: icache FlushCache - assign CacheStall = (CurrState == STATE_READY & StallConditions) | // exclusion-tag: icache StallStates + assign CacheStall = (CurrState == STATE_ACCESS & StallConditions) | // exclusion-tag: icache StallStates (CurrState == STATE_FETCH) | (CurrState == STATE_WRITEBACK) | (CurrState == STATE_WRITE_LINE) | // this cycle writes the sram, must keep stalling so the next cycle can read the next hit/miss unless its a write. @@ -153,26 +153,26 @@ module cachefsm import cvw::*; #(parameter cvw_t P, (CurrState == STATE_FLUSH_WRITEBACK); // write enables internal to cache assign SetValid = CurrState == STATE_WRITE_LINE | - (CurrState == STATE_READY & CMOZeroNoEviction) | + (CurrState == STATE_ACCESS & CMOZeroNoEviction) | (CurrState == STATE_WRITEBACK & CacheBusAck & CMOpM[3]); - assign ClearValid = (CurrState == STATE_READY & CMOpM[0]) | + assign ClearValid = (CurrState == STATE_ACCESS & CMOpM[0]) | (CurrState == STATE_WRITEBACK & CMOpM[2] & CacheBusAck); - assign LRUWriteEn = (((CurrState == STATE_READY & (AnyHit | CMOZeroNoEviction)) | + assign LRUWriteEn = (((CurrState == STATE_ACCESS & (AnyHit | CMOZeroNoEviction)) | (CurrState == STATE_WRITE_LINE)) & ~FlushStage) | (CurrState == STATE_WRITEBACK & CMOpM[3] & CacheBusAck); // exclusion-tag-start: icache flushdirtycontrols - assign SetDirty = (CurrState == STATE_READY & (AnyUpdateHit | CMOZeroNoEviction)) | // exclusion-tag: icache SetDirty + assign SetDirty = (CurrState == STATE_ACCESS & (AnyUpdateHit | CMOZeroNoEviction)) | // exclusion-tag: icache SetDirty (CurrState == STATE_WRITE_LINE & (CacheRW[0])) | (CurrState == STATE_WRITEBACK & (CMOpM[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 CurrState == STATE_WRITEBACK & (CMOpM[1] | CMOpM[2]) & CacheBusAck; - assign SelWay = (CurrState == STATE_WRITEBACK & ((~CacheBusAck & ~(CMOpM[1] | CMOpM[2])) | (CacheBusAck & CMOpM[3]))) | - (CurrState == STATE_READY & ((AnyMiss & LineDirty) | (CMOZeroNoEviction & ~CacheHit))) | + assign SelVictim = (CurrState == STATE_WRITEBACK & ((~CacheBusAck & ~(CMOpM[1] | CMOpM[2])) | (CacheBusAck & CMOpM[3]))) | + (CurrState == STATE_ACCESS & ((AnyMiss & LineDirty) | (CMOZeroNoEviction & ~Hit))) | (CurrState == STATE_WRITE_LINE); assign SelWriteback = (CurrState == STATE_WRITEBACK & (CMOpM[1] | CMOpM[2] | ~CacheBusAck)) | - (CurrState == STATE_READY & AnyMiss & LineDirty); + (CurrState == STATE_ACCESS & AnyMiss & LineDirty); // coverage off -item e 1 -fecexprrow 1 // (state is always FLUSH_WRITEBACK when FlushWayFlag & CacheBusAck) assign FlushAdrCntEn = (CurrState == STATE_FLUSH_WRITEBACK & FlushWayFlag & CacheBusAck) | @@ -183,29 +183,29 @@ module cachefsm import cvw::*; #(parameter cvw_t P, (CurrState == STATE_FLUSH_WRITEBACK & FlushFlag & CacheBusAck); // exclusion-tag-end: icache flushdirtycontrols // Bus interface controls - assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss & ~LineDirty) | // exclusion-tag: icache CacheBusRCauses + assign CacheBusRW[1] = (CurrState == STATE_ACCESS & AnyMiss & ~LineDirty) | // exclusion-tag: icache CacheBusRCauses (CurrState == STATE_FETCH & ~CacheBusAck) | (CurrState == STATE_WRITEBACK & CacheBusAck & ~(|CMOpM)); logic LoadMiss; - assign LoadMiss = (CacheRW[1]) & ~CacheHit & ~InvalidateCache; // exclusion-tag: cache AnyMiss + assign LoadMiss = (CacheRW[1]) & ~Hit & ~InvalidateCache; // exclusion-tag: cache AnyMiss - assign CacheBusRW[0] = (CurrState == STATE_READY & LoadMiss & LineDirty) | // exclusion-tag: icache CacheBusW + assign CacheBusRW[0] = (CurrState == STATE_ACCESS & LoadMiss & LineDirty) | // exclusion-tag: icache CacheBusW (CurrState == STATE_WRITEBACK & ~CacheBusAck) | (CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck) | (CurrState == STATE_WRITEBACK & (CMOpM[1] | CMOpM[2]) & ~CacheBusAck); - assign SelAdrData = (CurrState == STATE_READY & (CacheRW[0] | AnyMiss | (|CMOpM))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed + assign SelAdrData = (CurrState == STATE_ACCESS & (CacheRW[0] | AnyMiss | (|CMOpM))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed (CurrState == STATE_FETCH) | (CurrState == STATE_WRITEBACK) | (CurrState == STATE_WRITE_LINE) | resetDelay; - assign SelAdrTag = (CurrState == STATE_READY & (AnyMiss | (|CMOpM))) | // exclusion-tag: icache SelAdrTag // changes if store delay hazard removed + assign SelAdrTag = (CurrState == STATE_ACCESS & (AnyMiss | (|CMOpM))) | // exclusion-tag: icache SelAdrTag // changes if store delay hazard removed (CurrState == STATE_FETCH) | (CurrState == STATE_WRITEBACK) | (CurrState == STATE_WRITE_LINE) | resetDelay; - assign SelFetchBuffer = CurrState == STATE_WRITE_LINE | CurrState == STATE_READ_HOLD; - assign CacheEn = (~Stall | StallConditions) | (CurrState != STATE_READY) | reset | InvalidateCache; // exclusion-tag: dcache CacheEn + assign SelFetchBuffer = CurrState == STATE_WRITE_LINE | CurrState == STATE_ADDRESS_SETUP; + assign CacheEn = (~Stall | StallConditions) | (CurrState != STATE_ACCESS) | reset | InvalidateCache; // exclusion-tag: dcache CacheEn endmodule // cachefsm diff --git a/src/cache/cacheway.sv b/src/cache/cacheway.sv index 020a3f63c..e14a31c97 100644 --- a/src/cache/cacheway.sv +++ b/src/cache/cacheway.sv @@ -42,7 +42,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, input logic SetValid, // Set the valid bit in the selected way and set input logic ClearValid, // Clear the valid bit in the selected way and set input logic SetDirty, // Set the dirty bit in the selected way and set - input logic SelWay, // Controls which way to select a way data and tag, 00 = hitway, 10 = victimway, 11 = flushway + input logic SelVictim, // Overides HitWay Tag matching. Selects selects the victim tag/data regardless of hit input logic ClearDirty, // Clear the dirty bit in the selected way and set input logic FlushCache, // [0] Use SelAdr, [1] SRAM reads/writes from FlushAdr input logic VictimWay, // LRU selected this way as victim to evict @@ -68,7 +68,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, logic [LINELEN-1:0] ReadDataLine; logic [TAGLEN-1:0] ReadTag; logic Dirty; - logic SelDirty; + logic SelecteDirty; logic SelectedWriteWordEn; logic [LINELEN/8-1:0] FinalByteMask; logic SetValidEN, ClearValidEN; @@ -77,33 +77,30 @@ module cacheway import cvw::*; #(parameter cvw_t P, logic SetDirtyWay; logic ClearDirtyWay; logic SelNonHit; - logic SelData; + logic SelectedWay; logic InvalidateCacheDelay; if (!READ_ONLY_CACHE) begin:flushlogic - logic FlushWayEn; - mux2 #(1) seltagmux(VictimWay, FlushWay, FlushCache, SelDirty); - + mux2 #(1) seltagmux(VictimWay, FlushWay, FlushCache, SelecteDirty); + mux3 #(1) selectedmux(HitWay, FlushWay, VictimWay, {SelVictim, FlushCache}, SelectedWay); // FlushWay is part of a one hot way selection. Must clear it if FlushWay not selected. // coverage off -item e 1 -fecexprrow 3 // nonzero ways will never see FlushCache=0 while FlushWay=1 since FlushWay only advances on a subset of FlushCache assertion cases. - assign FlushWayEn = FlushWay & FlushCache; - assign SelNonHit = FlushWayEn | SelWay; end else begin:flushlogic // no flush operation for read-only caches. - assign SelDirty = VictimWay; - assign SelNonHit = SelWay; + assign SelecteDirty = VictimWay; + mux2 #(1) selectedwaymux(HitWay, SelecteDirty, SelVictim , SelectedWay); end - mux2 #(1) selectedwaymux(HitWay, SelDirty, SelNonHit , SelData); + ///////////////////////////////////////////////////////////////////////////////////////////// // Write Enable demux ///////////////////////////////////////////////////////////////////////////////////////////// - assign SetValidWay = SetValid & SelData; - assign ClearValidWay = ClearValid & SelData; // exclusion-tag: icache ClearValidWay - assign SetDirtyWay = SetDirty & SelData; // exclusion-tag: icache SetDirtyWay - assign ClearDirtyWay = ClearDirty & SelData; + assign SetValidWay = SetValid & SelectedWay; + assign ClearValidWay = ClearValid & SelectedWay; // exclusion-tag: icache ClearValidWay + assign SetDirtyWay = SetDirty & SelectedWay; // exclusion-tag: icache SetDirtyWay + assign ClearDirtyWay = ClearDirty & SelectedWay; assign SelectedWriteWordEn = (SetValidWay | SetDirtyWay) & ~FlushStage; // exclusion-tag: icache SelectedWiteWordEn assign SetValidEN = SetValidWay & ~FlushStage; // exclusion-tag: cache SetValidEN assign ClearValidEN = ClearValidWay & ~FlushStage; // exclusion-tag: cache ClearValidEN @@ -120,9 +117,9 @@ module cacheway import cvw::*; #(parameter cvw_t P, .din(PAdr[PA_BITS-1:OFFSETLEN+INDEXLEN]), .we(SetValidEN)); // AND portion of distributed tag multiplexer - assign TagWay = SelData ? ReadTag : 0; // AND part of AOMux + assign TagWay = SelectedWay ? ReadTag : 0; // AND part of AOMux assign HitDirtyWay = Dirty & ValidWay; - assign DirtyWay = SelDirty & HitDirtyWay; // exclusion-tag: icache DirtyWay + assign DirtyWay = SelecteDirty & HitDirtyWay; // exclusion-tag: icache DirtyWay assign HitWay = ValidWay & (ReadTag == PAdr[PA_BITS-1:OFFSETLEN+INDEXLEN]) & ~InvalidateCacheDelay; // exclusion-tag: dcache HitWay flop #(1) InvalidateCacheReg(clk, InvalidateCache, InvalidateCacheDelay); @@ -152,7 +149,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, end // AND portion of distributed read multiplexers - assign ReadDataLineWay = SelData ? ReadDataLine : 0; // AND part of AO mux. + assign ReadDataLineWay = SelectedWay ? ReadDataLine : 0; // AND part of AO mux. ///////////////////////////////////////////////////////////////////////////////////////////// // Valid Bits diff --git a/src/lsu/align.sv b/src/lsu/align.sv index b934dc924..d4603941b 100644 --- a/src/lsu/align.sv +++ b/src/lsu/align.sv @@ -37,6 +37,7 @@ module align import cvw::*; #(parameter cvw_t P) ( input logic [P.XLEN-1:0] IEUAdrM, // 2 byte aligned PC in Fetch stage input logic [P.XLEN-1:0] IEUAdrE, // The next IEUAdrM input logic [2:0] Funct3M, // Size of memory operation + input logic FpLoadStoreM, // Floating point Load or Store input logic [1:0] MemRWM, 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 @@ -52,7 +53,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 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); @@ -72,6 +72,7 @@ module align import cvw::*; #(parameter cvw_t P) ( logic [P.XLEN-1:0] IEUAdrIncrementM; + localparam OFFSET_LEN = $clog2(LLENINBYTES); logic [$clog2(LLENINBYTES)-1:0] AccessByteOffsetM; logic [$clog2(LLENINBYTES)+2:0] ShiftAmount; logic PotentialSpillM; @@ -93,12 +94,15 @@ module align import cvw::*; #(parameter cvw_t P) ( // compute misalignement always_comb begin - case (Funct3M[1:0]) - 2'b00: AccessByteOffsetM = 0; // byte access - 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]; + case (Funct3M & {FpLoadStoreM, 2'b11}) + 3'b000: AccessByteOffsetM = 0; // byte access + 3'b001: AccessByteOffsetM = {{OFFSET_LEN-1{1'b0}}, IEUAdrM[0]}; // half access + 3'b010: AccessByteOffsetM = {{OFFSET_LEN-2{1'b0}}, IEUAdrM[1:0]}; // word access + 3'b011: if(P.LLEN >= 64) AccessByteOffsetM = {{OFFSET_LEN-3{1'b0}}, IEUAdrM[2:0]}; // double access + else AccessByteOffsetM = 0; // shouldn't happen + 3'b100: if(P.LLEN == 128) AccessByteOffsetM = IEUAdrM[OFFSET_LEN-1:0]; // quad access + else AccessByteOffsetM = IEUAdrM[OFFSET_LEN-1:0]; + default: AccessByteOffsetM = 0; // shouldn't happen endcase case (Funct3M[1:0]) 2'b00: PotentialSpillM = 0; // byte access @@ -118,20 +122,17 @@ module align import cvw::*; #(parameter cvw_t P) ( always_comb begin case (CurrState) - STATE_READY: if (ValidSpillM & ~MemRWM[0]) NextState = STATE_SPILL; // load spill - else if(ValidSpillM) NextState = STATE_STORE_DELAY; // store spill + STATE_READY: if (ValidSpillM) NextState = STATE_SPILL; // load spill else NextState = STATE_READY; // no spill STATE_SPILL: if(StallM) NextState = STATE_SPILL; else NextState = STATE_READY; - STATE_STORE_DELAY: NextState = STATE_SPILL; default: NextState = STATE_READY; endcase end - assign SelSpillM = (CurrState == STATE_SPILL | CurrState == STATE_STORE_DELAY); - assign SelSpillE = (CurrState == STATE_READY & ValidSpillM) | (CurrState == STATE_SPILL & CacheBusHPWTStall) | (CurrState == STATE_STORE_DELAY); + assign SelSpillM = CurrState == STATE_SPILL; + assign SelSpillE = (CurrState == STATE_READY & ValidSpillM) | (CurrState == STATE_SPILL & CacheBusHPWTStall); assign SpillSaveM = (CurrState == STATE_READY) & ValidSpillM & ~FlushM; - assign SelStoreDelay = (CurrState == STATE_STORE_DELAY); // *** Can this be merged into the PreLSURWM logic? assign SpillStallM = SelSpillE; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/lsu/lsu.sv b/src/lsu/lsu.sv index 6bc8f1735..9618e2cae 100644 --- a/src/lsu/lsu.sv +++ b/src/lsu/lsu.sv @@ -143,7 +143,6 @@ module lsu import cvw::*; #(parameter cvw_t P) ( logic [(P.LLEN-1)/8:0] ByteMaskExtendedM; // Selects which bytes within a word to write logic [1:0] MemRWSpillM; logic SpillStallM; - logic SelStoreDelay; logic DTLBMissM; // DTLB miss causes HPTW walk logic DTLBWriteM; // Writes PTE and PageType to DTLB @@ -164,12 +163,11 @@ module lsu import cvw::*; #(parameter cvw_t P) ( flopenrc #(P.XLEN) AddressMReg(clk, reset, FlushM, ~StallM, IEUAdrE, IEUAdrM); if(MISALIGN_SUPPORT) begin : ziccslm_align logic [P.XLEN-1:0] IEUAdrSpillE, IEUAdrSpillM; - align #(P) align(.clk, .reset, .StallM, .FlushM, .IEUAdrE, .IEUAdrM, .Funct3M, + align #(P) align(.clk, .reset, .StallM, .FlushM, .IEUAdrE, .IEUAdrM, .Funct3M, .FpLoadStoreM, .MemRWM, .DCacheReadDataWordM, .CacheBusHPWTStall, .SelHPTW, .ByteMaskM, .ByteMaskExtendedM, .LSUWriteDataM, .ByteMaskSpillM, .LSUWriteDataSpillM, - .IEUAdrSpillE, .IEUAdrSpillM, .SelSpillE, .DCacheReadDataWordSpillM, .SpillStallM, - .SelStoreDelay); + .IEUAdrSpillE, .IEUAdrSpillM, .SelSpillE, .DCacheReadDataWordSpillM, .SpillStallM); assign IEUAdrExtM = {2'b00, IEUAdrSpillM}; assign IEUAdrExtE = {2'b00, IEUAdrSpillE}; end else begin : no_ziccslm_align @@ -180,7 +178,7 @@ module lsu import cvw::*; #(parameter cvw_t P) ( assign ByteMaskSpillM = ByteMaskM; assign LSUWriteDataSpillM = LSUWriteDataM; assign MemRWSpillM = MemRWM; - assign {SpillStallM, SelStoreDelay} = 0; + assign {SpillStallM} = 0; end if(P.ZICBOZ_SUPPORTED) begin : cboz @@ -333,7 +331,7 @@ module lsu import cvw::*; #(parameter cvw_t P) ( cache #(.P(P), .PA_BITS(P.PA_BITS), .XLEN(P.XLEN), .LINELEN(P.DCACHE_LINELENINBITS), .NUMLINES(P.DCACHE_WAYSIZEINBYTES*8/LINELEN), .NUMWAYS(P.DCACHE_NUMWAYS), .LOGBWPL(LLENLOGBWPL), .WORDLEN(CACHEWORDLEN), .MUXINTERVAL(P.LLEN), .READ_ONLY_CACHE(0)) dcache( .clk, .reset, .Stall(GatedStallW & ~SelSpillE), .SelBusBeat, .FlushStage(FlushW | IgnoreRequestTLB), - .CacheRW(SelStoreDelay ? 2'b00 : CacheRWM), + .CacheRW(CacheRWM), .FlushCache(FlushDCache), .NextSet(IEUAdrExtE[11:0]), .PAdr(PAdrM), .ByteMask(ByteMaskSpillM), .BeatCount(BeatCount[AHBWLOGBWPL-1:AHBWLOGBWPL-LLENLOGBWPL]), .CacheWriteData(LSUWriteDataSpillM), .SelHPTW, diff --git a/src/privileged/privdec.sv b/src/privileged/privdec.sv index 360b3dab2..cf32c1f28 100644 --- a/src/privileged/privdec.sv +++ b/src/privileged/privdec.sv @@ -80,7 +80,7 @@ module privdec import cvw::*; #(parameter cvw_t P) ( if (P.U_SUPPORTED) begin:wfi logic [P.WFI_TIMEOUT_BIT:0] WFICount, WFICountPlus1; - assign WFICountPlus1 = wfiM ? 0 : WFICount + 1; // restart counting on WFI + assign WFICountPlus1 = wfiM ? WFICount + 1 : '0; // restart counting on WFI flopr #(P.WFI_TIMEOUT_BIT+1) wficountreg(clk, reset, WFICountPlus1, WFICount); // count while in WFI // coverage off -item e 1 -fecexprrow 1 // WFI Timout trap will not occur when STATUS_TW is low while in supervisor mode, so the system gets stuck waiting for an interrupt and triggers a watchdog timeout.