mirror of
https://github.com/openhwgroup/cvw.git
synced 2025-04-24 13:57:07 -04:00
merged coverage exclusions
This commit is contained in:
commit
b00b8ba366
38 changed files with 632 additions and 501 deletions
18
sim/GetLineNum.do
Normal file
18
sim/GetLineNum.do
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Alec Vercruysse
|
||||
# 2023-04-12
|
||||
# Note that the target string is regex, and needs to be double-escaped.
|
||||
# e.g. to match a (, you need \\(.
|
||||
proc GetLineNum {fname target} {
|
||||
set f [open $fname]
|
||||
set linectr 1
|
||||
while {[gets $f line] != -1} {
|
||||
if {[regexp $target $line]} {
|
||||
close $f
|
||||
return $linectr
|
||||
}
|
||||
incr linectr
|
||||
}
|
||||
close $f
|
||||
return -code error \
|
||||
"target string not found"
|
||||
}
|
|
@ -27,6 +27,8 @@
|
|||
# This file should be a last resort. It's preferable to put
|
||||
# // coverage off
|
||||
# statements inline with the code whenever possible.
|
||||
# a hack to describe coverage exclusions without hardcoding linenumbers:
|
||||
do GetLineNum.do
|
||||
|
||||
# LZA (i<64) statement confuses coverage tool
|
||||
# This is ugly to exlcude the whole file - is there a better option? // coverage off isn't working
|
||||
|
@ -35,6 +37,46 @@ coverage exclude -srcfile lzc.sv
|
|||
# FDIVSQRT has
|
||||
coverage exclude -scope /core/fpu/fpu/fdivsqrt/fdivsqrtfsm -ftrans state DONE->BUSY
|
||||
|
||||
### Exclude D$ states and logic for the I$ instance
|
||||
# This is cleaner than trying to set an I$-specific pragma in cachefsm.sv (which would exclude it for the D$ instance too)
|
||||
# Also exclude the write line to ready transition for the I$ since we can't get a flush during this operation.
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -fstate CurrState STATE_FLUSH STATE_FLUSH_WRITEBACK STATE_FLUSH_WRITEBACK STATE_WRITEBACK
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -ftrans CurrState STATE_WRITE_LINE->STATE_READY
|
||||
# exclude unused transitions from case statement. Unfortunately the whole branch needs to be excluded I think. Expression coverage should still work.
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache state-case"] -item b 1
|
||||
# exclude branch/condition coverage: LineDirty if statement
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache FETCHStatement"] -item bc 1
|
||||
# exclude the unreachable logic
|
||||
set start [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-start: icache case"]
|
||||
set end [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-end: icache case"]
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange $start-$end
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache WRITEBACKStatement"]
|
||||
# exclude Atomic Operation logic
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache storeAMO"] -item e 1 -fecexprrow 6
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache storeAMO1"] -item e 1 -fecexprrow 2-4
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache AnyUpdateHit"] -item e 1 -fecexprrow 2
|
||||
# cache write logic
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheW"] -item e 1 -fecexprrow 4
|
||||
# output signal logic
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache StallStates"] -item e 1 -fecexprrow 8 12 14
|
||||
set start [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-start: icache flushdirtycontrols"]
|
||||
set end [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag-end: icache flushdirtycontrols"]
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange $start-$end
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheBusW"]
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache SelAdrCauses"] -item e 1 -fecexprrow 4 10
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheBusRCauses"] -item e 1 -fecexprrow 1-2 12
|
||||
# cache.sv AdrSelMux and CacheBusAdrMux, excluding unhit Flush branch
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/AdrSelMux -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheBusAdrMux -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1 3
|
||||
# CacheWay Dirty logic. -scope does not accept wildcards.
|
||||
set numcacheways 4
|
||||
for {set i 0} {$i < $numcacheways} {incr i} {
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheWays[$i] -linerange [GetLineNum ../src/cache/cacheway.sv "exclusion-tag: icache SetDirtyWay"] -item e 1
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheWays[$i] -linerange [GetLineNum ../src/cache/cacheway.sv "exclusion-tag: icache SelectedWiteWordEn"] -item e 1 -fecexprrow 4 6
|
||||
# below: flushD can't go high during an icache write b/c of pipeline stall
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheWays[$i] -linerange [GetLineNum ../src/cache/cacheway.sv "exclusion-tag: icache SetValidEN"] -item e 1 -fecexprrow 4
|
||||
}
|
||||
|
||||
|
||||
# Excluding peripherals as sources of instructions for the ifu
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/clintdec
|
||||
|
|
20
src/cache/cache.sv
vendored
20
src/cache/cache.sv
vendored
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////
|
||||
// cache
|
||||
// cache.sv
|
||||
//
|
||||
// Written: Ross Thompson ross1728@gmail.com
|
||||
// Created: 7 July 2021
|
||||
|
@ -122,7 +122,7 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE
|
|||
// Select victim way for associative caches
|
||||
if(NUMWAYS > 1) begin:vict
|
||||
cacheLRU #(NUMWAYS, SETLEN, OFFSETLEN, NUMLINES) cacheLRU(
|
||||
.clk, .reset, .CacheEn, .FlushStage, .HitWay, .ValidWay, .VictimWay, .CacheSet, .LRUWriteEn,
|
||||
.clk, .reset, .CacheEn, .HitWay, .ValidWay, .VictimWay, .CacheSet, .LRUWriteEn,
|
||||
.SetValid, .PAdr(PAdr[SETTOP-1:OFFSETLEN]), .InvalidateCache, .FlushCache);
|
||||
end else
|
||||
assign VictimWay = 1'b1; // one hot.
|
||||
|
@ -167,22 +167,22 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE
|
|||
// Adjust byte mask from word to cache line
|
||||
onehotdecoder #(LOGCWPL) adrdec(.bin(PAdr[LOGCWPL+LOGLLENBYTES-1:LOGLLENBYTES]), .decoded(MemPAdrDecoded));
|
||||
for(index = 0; index < 2**LOGCWPL; index++) begin
|
||||
assign DemuxedByteMask[(index+1)*(WORDLEN/8)-1:index*(WORDLEN/8)] = MemPAdrDecoded[index] ? ByteMask : '0;
|
||||
assign DemuxedByteMask[(index+1)*(WORDLEN/8)-1:index*(WORDLEN/8)] = MemPAdrDecoded[index] ? ByteMask : '0;
|
||||
end
|
||||
assign FetchBufferByteSel = SetValid & ~SetDirty ? '1 : ~DemuxedByteMask; // 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]), .y(LineWriteData[8*index+7:8*index]));
|
||||
mux2 #(8) WriteDataMux(.d0(CacheWriteData[(8*index)%WORDLEN+7:(8*index)%WORDLEN]),
|
||||
.d1(FetchBuffer[8*index+7:8*index]), .s(FetchBufferByteSel[index]), .y(LineWriteData[8*index+7:8*index]));
|
||||
end
|
||||
assign LineByteMask = SetValid ? '1 : SetDirty ? DemuxedByteMask : '0;
|
||||
end
|
||||
else
|
||||
begin:WriteSelLogic
|
||||
// No need for this mux if the cache does not handle writes.
|
||||
assign LineWriteData = FetchBuffer;
|
||||
assign LineByteMask = '1;
|
||||
// No need for this mux if the cache does not handle writes.
|
||||
assign LineWriteData = FetchBuffer;
|
||||
assign LineByteMask = '1;
|
||||
end
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Flush logic
|
||||
|
@ -203,8 +203,8 @@ module cache #(parameter LINELEN, NUMLINES, NUMWAYS, LOGBWPL, WORDLEN, MUXINTE
|
|||
assign FlushWayFlag = FlushWay[NUMWAYS-1];
|
||||
end // block: flushlogic
|
||||
else begin:flushlogic
|
||||
assign FlushWayFlag = 0;
|
||||
assign FlushAdrFlag = 0;
|
||||
assign FlushWayFlag = 0;
|
||||
assign FlushAdrFlag = 0;
|
||||
end
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
53
src/cache/cacheLRU.sv
vendored
53
src/cache/cacheLRU.sv
vendored
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////
|
||||
// dcache (data cache)
|
||||
// cacheLRU.sv
|
||||
//
|
||||
// Written: Ross Thompson ross1728@gmail.com
|
||||
// Created: 20 July 2021
|
||||
|
@ -32,12 +32,11 @@
|
|||
module cacheLRU
|
||||
#(parameter NUMWAYS = 4, SETLEN = 9, OFFSETLEN = 5, NUMLINES = 128) (
|
||||
input logic clk,
|
||||
input logic reset,
|
||||
input logic FlushStage, // Pipeline flush of second stage (prevent writes and bus operations)
|
||||
input logic reset,
|
||||
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] CacheSet, // Cache address, the output of the address select mux, NextAdr, PAdr, or FlushAdr
|
||||
input logic [SETLEN-1:0] CacheSet, // 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
|
||||
|
@ -90,16 +89,26 @@ module cacheLRU
|
|||
assign WayExpanded[StartIndex : EndIndex] = {{DuplicationFactor}{WayEncoded[row]}};
|
||||
end
|
||||
|
||||
genvar r, a, s;
|
||||
genvar node;
|
||||
assign LRUUpdate[NUMWAYS-2] = '1;
|
||||
for(s = NUMWAYS-2; s >= NUMWAYS/2; s--) begin : enables
|
||||
localparam p = NUMWAYS - s - 1;
|
||||
localparam g = log2(p);
|
||||
localparam t0 = s - p;
|
||||
localparam t1 = t0 - 1;
|
||||
localparam r = LOGNUMWAYS - g;
|
||||
assign LRUUpdate[t0] = LRUUpdate[s] & ~WayEncoded[r];
|
||||
assign LRUUpdate[t1] = LRUUpdate[s] & WayEncoded[r];
|
||||
for(node = NUMWAYS-2; node >= NUMWAYS/2; node--) begin : enables
|
||||
localparam ctr = NUMWAYS - node - 1;
|
||||
localparam ctr_depth = log2(ctr);
|
||||
localparam lchild = node - ctr;
|
||||
localparam rchild = lchild - 1;
|
||||
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 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];
|
||||
end
|
||||
else begin
|
||||
assign LRUUpdate[lchild] = LRUUpdate[node] & ~WayEncoded[r];
|
||||
assign LRUUpdate[rchild] = LRUUpdate[node] & WayEncoded[r];
|
||||
end
|
||||
end
|
||||
|
||||
// The root node of the LRU tree will always be selected in LRUUpdate. No mux needed.
|
||||
|
@ -107,15 +116,15 @@ module cacheLRU
|
|||
mux2 #(1) LRUMuxes[NUMWAYS-3:0](CurrLRU[NUMWAYS-3:0], ~WayExpanded[NUMWAYS-3:0], LRUUpdate[NUMWAYS-3:0], NextLRU[NUMWAYS-3:0]);
|
||||
|
||||
// Compute next victim way.
|
||||
for(s = NUMWAYS-2; s >= NUMWAYS/2; s--) begin
|
||||
localparam t0 = 2*s - NUMWAYS;
|
||||
for(node = NUMWAYS-2; node >= NUMWAYS/2; node--) begin
|
||||
localparam t0 = 2*node - NUMWAYS;
|
||||
localparam t1 = t0 + 1;
|
||||
assign Intermediate[s] = CurrLRU[s] ? Intermediate[t0] : Intermediate[t1];
|
||||
assign Intermediate[node] = CurrLRU[node] ? Intermediate[t0] : Intermediate[t1];
|
||||
end
|
||||
for(s = NUMWAYS/2-1; s >= 0; s--) begin
|
||||
localparam int0 = (NUMWAYS/2-1-s)*2;
|
||||
for(node = NUMWAYS/2-1; node >= 0; node--) begin
|
||||
localparam int0 = (NUMWAYS/2-1-node)*2;
|
||||
localparam int1 = int0 + 1;
|
||||
assign Intermediate[s] = CurrLRU[s] ? int1[LOGNUMWAYS-1:0] : int0[LOGNUMWAYS-1:0];
|
||||
assign Intermediate[node] = CurrLRU[node] ? int1[LOGNUMWAYS-1:0] : int0[LOGNUMWAYS-1:0];
|
||||
end
|
||||
|
||||
logic [NUMWAYS-1:0] FirstZero;
|
||||
|
@ -134,11 +143,9 @@ module cacheLRU
|
|||
always_ff @(posedge clk) begin
|
||||
if (reset) for (int set = 0; set < NUMLINES; set++) LRUMemory[set] <= '0;
|
||||
if(CacheEn) begin
|
||||
// if((InvalidateCache | FlushCache) & ~FlushStage) for (int set = 0; set < NUMLINES; set++) LRUMemory[set] <= '0;
|
||||
if (LRUWriteEn & ~FlushStage) begin
|
||||
if(LRUWriteEn)
|
||||
LRUMemory[PAdr] <= NextLRU;
|
||||
end
|
||||
if(LRUWriteEn & ~FlushStage & (PAdr == CacheSet))
|
||||
if(LRUWriteEn & (PAdr == CacheSet))
|
||||
CurrLRU <= #1 NextLRU;
|
||||
else
|
||||
CurrLRU <= #1 LRUMemory[CacheSet];
|
||||
|
|
42
src/cache/cachefsm.sv
vendored
42
src/cache/cachefsm.sv
vendored
|
@ -1,11 +1,11 @@
|
|||
///////////////////////////////////////////
|
||||
// dcache (data cache) fsm
|
||||
// cachefsm.sv
|
||||
//
|
||||
// Written: Ross Thompson ross1728@gmail.com
|
||||
// Created: 25 August 2021
|
||||
// Modified: 20 January 2023
|
||||
//
|
||||
// Purpose: Controller for the dcache fsm
|
||||
// Purpose: Controller for the cache fsm
|
||||
//
|
||||
// Documentation: RISC-V System on Chip Design Chapter 7 (Figure 7.14 and Table 7.1)
|
||||
//
|
||||
|
@ -89,13 +89,13 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
|
|||
assign AMO = CacheAtomic[1] & (&CacheRW);
|
||||
assign StoreAMO = AMO | CacheRW[0];
|
||||
|
||||
assign AnyMiss = (StoreAMO | CacheRW[1]) & ~CacheHit & ~InvalidateCache;
|
||||
assign AnyUpdateHit = (StoreAMO) & CacheHit;
|
||||
assign AnyHit = AnyUpdateHit | (CacheRW[1] & CacheHit);
|
||||
assign AnyMiss = (StoreAMO | CacheRW[1]) & ~CacheHit & ~InvalidateCache; // exclusion-tag: icache storeAMO
|
||||
assign AnyUpdateHit = (StoreAMO) & CacheHit; // exclusion-tag: icache storeAMO1
|
||||
assign AnyHit = AnyUpdateHit | (CacheRW[1] & CacheHit); // exclusion-tag: icache AnyUpdateHit
|
||||
assign FlushFlag = FlushAdrFlag & FlushWayFlag;
|
||||
|
||||
// outputs for the performance counters.
|
||||
assign CacheAccess = (AMO | CacheRW[1] | CacheRW[0]) & CurrState == STATE_READY;
|
||||
assign CacheAccess = (AMO | CacheRW[1] | CacheRW[0]) & CurrState == STATE_READY; // exclusion-tag: icache CacheW
|
||||
assign CacheMiss = CacheAccess & ~CacheHit;
|
||||
|
||||
// special case on reset. When the fsm first exists reset the
|
||||
|
@ -109,17 +109,18 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
|
|||
|
||||
always_comb begin
|
||||
NextState = STATE_READY;
|
||||
case (CurrState)
|
||||
case (CurrState) // exclusion-tag: icache state-case
|
||||
STATE_READY: if(InvalidateCache) NextState = STATE_READY;
|
||||
else if(FlushCache & ~READ_ONLY_CACHE) NextState = STATE_FLUSH;
|
||||
else if(AnyMiss & (READ_ONLY_CACHE | ~LineDirty)) NextState = STATE_FETCH;
|
||||
else if(AnyMiss & LineDirty) NextState = STATE_WRITEBACK;
|
||||
else if(AnyMiss & (READ_ONLY_CACHE | ~LineDirty)) NextState = STATE_FETCH; // exclusion-tag: icache FETCHStatement
|
||||
else if(AnyMiss & LineDirty) NextState = STATE_WRITEBACK; // exclusion-tag: icache WRITEBACKStatement
|
||||
else NextState = STATE_READY;
|
||||
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;
|
||||
// exclusion-tag-start: icache case
|
||||
STATE_WRITEBACK: if(CacheBusAck) NextState = STATE_FETCH;
|
||||
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.
|
||||
|
@ -129,13 +130,14 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
|
|||
STATE_FLUSH_WRITEBACK: if(CacheBusAck & ~FlushFlag) NextState = STATE_FLUSH;
|
||||
else if(CacheBusAck) NextState = STATE_READ_HOLD;
|
||||
else NextState = STATE_FLUSH_WRITEBACK;
|
||||
// exclusion-tag-end: icache case
|
||||
default: NextState = STATE_READY;
|
||||
endcase
|
||||
end
|
||||
|
||||
// com back to CPU
|
||||
assign CacheCommitted = (CurrState != STATE_READY) & ~(READ_ONLY_CACHE & CurrState == STATE_READ_HOLD);
|
||||
assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss)) |
|
||||
assign CacheStall = (CurrState == STATE_READY & (FlushCache | AnyMiss)) | // 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.
|
||||
|
@ -143,12 +145,14 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
|
|||
(CurrState == STATE_FLUSH_WRITEBACK);
|
||||
// write enables internal to cache
|
||||
assign SetValid = CurrState == STATE_WRITE_LINE;
|
||||
assign SetDirty = (CurrState == STATE_READY & AnyUpdateHit) |
|
||||
(CurrState == STATE_WRITE_LINE & (StoreAMO));
|
||||
assign ClearDirty = (CurrState == STATE_WRITE_LINE & ~(StoreAMO)) |
|
||||
(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.
|
||||
// coverage off -item e 1 -fecexprrow 8
|
||||
assign LRUWriteEn = (CurrState == STATE_READY & AnyHit) |
|
||||
(CurrState == STATE_WRITE_LINE);
|
||||
(CurrState == STATE_WRITE_LINE) & ~FlushStage;
|
||||
// exclusion-tag-start: icache flushdirtycontrols
|
||||
assign SetDirty = (CurrState == STATE_READY & AnyUpdateHit) | // exclusion-tag: icache SetDirty
|
||||
(CurrState == STATE_WRITE_LINE & (StoreAMO));
|
||||
assign ClearDirty = (CurrState == STATE_WRITE_LINE & ~(StoreAMO)) | // 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
|
||||
assign SelWriteback = (CurrState == STATE_WRITEBACK & ~CacheBusAck) |
|
||||
(CurrState == STATE_READY & AnyMiss & LineDirty);
|
||||
|
@ -162,20 +166,20 @@ module cachefsm #(parameter READ_ONLY_CACHE = 0) (
|
|||
(CurrState == STATE_FLUSH_WRITEBACK & CacheBusAck);
|
||||
assign FlushCntRst = (CurrState == STATE_FLUSH & FlushFlag & ~LineDirty) |
|
||||
(CurrState == STATE_FLUSH_WRITEBACK & FlushFlag & CacheBusAck);
|
||||
// exclusion-tag-end: icache flushdirtycontrols
|
||||
// Bus interface controls
|
||||
assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss & ~LineDirty) |
|
||||
assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss & ~LineDirty) | // exclusion-tag: icache CacheBusRCauses
|
||||
(CurrState == STATE_FETCH & ~CacheBusAck) |
|
||||
(CurrState == STATE_WRITEBACK & CacheBusAck);
|
||||
assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) |
|
||||
assign CacheBusRW[0] = (CurrState == STATE_READY & AnyMiss & LineDirty) | // exclusion-tag: icache CacheBusW
|
||||
(CurrState == STATE_WRITEBACK & ~CacheBusAck) |
|
||||
(CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck);
|
||||
|
||||
assign SelAdr = (CurrState == STATE_READY & (StoreAMO | AnyMiss)) | // changes if store delay hazard removed
|
||||
assign SelAdr = (CurrState == STATE_READY & (StoreAMO | AnyMiss)) | // exclusion-tag: icache SelAdrCauses // 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 | FlushCache | AnyMiss) | (CurrState != STATE_READY) | reset | InvalidateCache;
|
||||
|
||||
|
|
11
src/cache/cacheway.sv
vendored
11
src/cache/cacheway.sv
vendored
|
@ -97,18 +97,13 @@ module cacheway #(parameter NUMLINES=512, LINELEN = 256, TAGLEN = 26,
|
|||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
assign SetValidWay = SetValid & SelData;
|
||||
assign SetDirtyWay = SetDirty & SelData; // exclusion-tag: icache SetDirtyWay
|
||||
assign ClearDirtyWay = ClearDirty & SelData;
|
||||
if (!READ_ONLY_CACHE) begin
|
||||
assign SetDirtyWay = SetDirty & SelData;
|
||||
assign SelectedWriteWordEn = (SetValidWay | SetDirtyWay) & ~FlushStage;
|
||||
end
|
||||
else begin
|
||||
assign SelectedWriteWordEn = SetValidWay & ~FlushStage;
|
||||
end
|
||||
assign SelectedWriteWordEn = (SetValidWay | SetDirtyWay) & ~FlushStage; // exclusion-tag: icache SelectedWiteWordEn
|
||||
assign SetValidEN = SetValidWay & ~FlushStage; // exclusion-tag: icache SetValidEN
|
||||
|
||||
// If writing the whole line set all write enables to 1, else only set the correct word.
|
||||
assign FinalByteMask = SetValidWay ? '1 : LineByteMask; // OR
|
||||
assign SetValidEN = SetValidWay & ~FlushStage;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tag Array
|
||||
|
|
5
src/cache/subcachelineread.sv
vendored
5
src/cache/subcachelineread.sv
vendored
|
@ -1,11 +1,11 @@
|
|||
///////////////////////////////////////////
|
||||
// subcachelineread
|
||||
// subcachelineread.sv
|
||||
//
|
||||
// Written: Ross Thompson ross1728@gmail.com
|
||||
// Created: 4 February 2022
|
||||
// Modified: 20 January 2023
|
||||
//
|
||||
// Purpose: Muxes the cache line downto the word size. Also include possilbe save/restore registers/muxes.
|
||||
// Purpose: Muxes the cache line down to the word size. Also include possible save/restore registers/muxes.
|
||||
//
|
||||
// Documentation: RISC-V System on Chip Design Chapter 7
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
|||
|
||||
module subcachelineread #(parameter LINELEN, WORDLEN,
|
||||
parameter MUXINTERVAL )( // The number of bits between mux. Set to 16 for I$ to support compressed. Set to `LLEN for D$
|
||||
|
||||
input logic [$clog2(LINELEN/8) - $clog2(MUXINTERVAL/8) - 1 : 0] PAdr, // Physical address
|
||||
input logic [LINELEN-1:0] ReadDataLine,// Read data of the whole cacheline
|
||||
output logic [WORDLEN-1:0] ReadDataWord // read data of selected word.
|
||||
|
|
|
@ -38,27 +38,27 @@ module ahbcacheinterface #(
|
|||
)(
|
||||
input logic HCLK, HRESETn,
|
||||
// bus interface controls
|
||||
input logic HREADY, // AHB peripheral ready
|
||||
input logic HREADY, // AHB peripheral ready
|
||||
output logic [1:0] HTRANS, // AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
output logic HWRITE, // AHB 0: Read operation 1: Write operation
|
||||
output logic [2:0] HSIZE, // AHB transaction width
|
||||
output logic [2:0] HBURST, // AHB burst length
|
||||
// bus interface buses
|
||||
input logic [`AHBW-1:0] HRDATA, // AHB read data
|
||||
input logic [`AHBW-1:0] HRDATA, // AHB read data
|
||||
output logic [`PA_BITS-1:0] HADDR, // AHB address
|
||||
output logic [`AHBW-1:0] HWDATA, // AHB write data
|
||||
output logic [`AHBW/8-1:0] HWSTRB, // AHB byte mask
|
||||
|
||||
// cache interface
|
||||
input logic [`PA_BITS-1:0] CacheBusAdr, // Address of cache line
|
||||
input logic [`LLEN-1:0] CacheReadDataWordM, // one word of cache line during a writeback
|
||||
input logic CacheableOrFlushCacheM, // Memory operation is cacheable or flushing D$
|
||||
input logic Cacheable, // Memory operation is cachable
|
||||
input logic [1:0] CacheBusRW, // Cache bus operation, 01: writeback, 10: fetch
|
||||
output logic CacheBusAck, // Handshack to $ indicating bus transaction completed
|
||||
output logic [LINELEN-1:0] FetchBuffer, // Register to hold beats of cache line as the arrive from bus
|
||||
output logic [AHBWLOGBWPL-1:0] BeatCount, // Beat position within the cache line in the Address Phase
|
||||
output logic SelBusBeat, // Tells the cache to select the word from ReadData or WriteData from BeatCount rather than PAdr
|
||||
input logic [`PA_BITS-1:0] CacheBusAdr, // Address of cache line
|
||||
input logic [`LLEN-1:0] CacheReadDataWordM, // One word of cache line during a writeback
|
||||
input logic CacheableOrFlushCacheM, // Memory operation is cacheable or flushing D$
|
||||
input logic Cacheable, // Memory operation is cachable
|
||||
input logic [1:0] CacheBusRW, // Cache bus operation, 01: writeback, 10: fetch
|
||||
output logic CacheBusAck, // Handshake to $ indicating bus transaction completed
|
||||
output logic [LINELEN-1:0] FetchBuffer, // Register to hold beats of cache line as the arrive from bus
|
||||
output logic [AHBWLOGBWPL-1:0] BeatCount, // Beat position within the cache line in the Address Phase
|
||||
output logic SelBusBeat, // Tells the cache to select the word from ReadData or WriteData from BeatCount rather than PAdr
|
||||
|
||||
// uncached interface
|
||||
input logic [`PA_BITS-1:0] PAdr, // Physical address of uncached memory operation
|
||||
|
@ -77,7 +77,7 @@ module ahbcacheinterface #(
|
|||
logic [`PA_BITS-1:0] LocalHADDR; // Address after selecting between cached and uncached operation
|
||||
logic [AHBWLOGBWPL-1:0] BeatCountDelayed; // Beat within the cache line in the second (Data) cache stage
|
||||
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/8-1:0] BusByteMaskM; // Byte enables within a word. For cache request all 1s
|
||||
logic [`AHBW-1:0] PreHWDATA; // AHB Address phase write data
|
||||
|
||||
genvar index;
|
||||
|
@ -107,7 +107,7 @@ module ahbcacheinterface #(
|
|||
end else assign CacheReadDataWordAHB = CacheReadDataWordM[`AHBW-1:0];
|
||||
|
||||
mux2 #(`AHBW) HWDATAMux(.d0(CacheReadDataWordAHB), .d1(WriteDataM[`AHBW-1:0]),
|
||||
.s(~(CacheableOrFlushCacheM)), .y(PreHWDATA));
|
||||
.s(~(CacheableOrFlushCacheM)), .y(PreHWDATA));
|
||||
flopen #(`AHBW) wdreg(HCLK, HREADY, PreHWDATA, HWDATA); // delay HWDATA by 1 cycle per spec
|
||||
|
||||
// *** bummer need a second byte mask for bus as it is AHBW rather than LLEN.
|
||||
|
@ -119,5 +119,5 @@ module ahbcacheinterface #(
|
|||
buscachefsm #(BeatCountThreshold, AHBWLOGBWPL, READ_ONLY_CACHE) AHBBuscachefsm(
|
||||
.HCLK, .HRESETn, .Flush, .BusRW, .Stall, .BusCommitted, .BusStall, .CaptureEn, .SelBusBeat,
|
||||
.CacheBusRW, .CacheBusAck, .BeatCount, .BeatCountDelayed,
|
||||
.HREADY, .HTRANS, .HWRITE, .HBURST);
|
||||
.HREADY, .HTRANS, .HWRITE, .HBURST);
|
||||
endmodule
|
||||
|
|
|
@ -32,21 +32,21 @@
|
|||
module ahbinterface #(
|
||||
parameter LSU = 0 // 1: LSU bus width is `XLEN, 0: IFU bus width is 32 bits
|
||||
)(
|
||||
input logic HCLK, HRESETn,
|
||||
input logic HCLK, HRESETn,
|
||||
// bus interface
|
||||
input logic HREADY, // AHB peripheral ready
|
||||
input logic HREADY, // AHB peripheral ready
|
||||
output logic [1:0] HTRANS, // AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
output logic HWRITE, // AHB 0: Read operation 1: Write operation
|
||||
input logic [`XLEN-1:0] HRDATA, // AHB read data
|
||||
input logic [`XLEN-1:0] HRDATA, // AHB read data
|
||||
output logic [`XLEN-1:0] HWDATA, // AHB write data
|
||||
output logic [`XLEN/8-1:0] HWSTRB, // AHB byte mask
|
||||
|
||||
// lsu/ifu interface
|
||||
input logic Stall, // Core pipeline is stalled
|
||||
input logic Flush, // Pipeline stage flush. Prevents bus transaction from starting
|
||||
input logic [1:0] BusRW, // Memory operation read/write control: 10: read, 01: write
|
||||
input logic [`XLEN/8-1:0] ByteMask, // Bytes enables within a word
|
||||
input logic [`XLEN-1:0] WriteData, // IEU write data for a store
|
||||
input logic Stall, // Core pipeline is stalled
|
||||
input logic Flush, // Pipeline stage flush. Prevents bus transaction from starting
|
||||
input logic [1:0] BusRW, // Memory operation read/write control: 10: read, 01: write
|
||||
input logic [`XLEN/8-1:0] ByteMask, // Bytes enables within a word
|
||||
input logic [`XLEN-1:0] WriteData, // IEU write data for a store
|
||||
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
|
||||
output logic [(LSU ? `XLEN : 32)-1:0] FetchBuffer // Register to hold HRDATA after arriving from the bus
|
||||
|
|
|
@ -40,29 +40,29 @@ module buscachefsm #(
|
|||
input logic HRESETn,
|
||||
|
||||
// IEU interface
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
// ahb cache interface locals.
|
||||
output logic CaptureEn, // Enable updating the Fetch buffer with valid data from HRDATA
|
||||
output logic CaptureEn, // Enable updating the Fetch buffer with valid data from HRDATA
|
||||
|
||||
// cache interface
|
||||
input logic [1:0] CacheBusRW, // Cache bus operation, 01: writeback, 10: fetch
|
||||
output logic CacheBusAck, // Handshack to $ indicating bus transaction completed
|
||||
input logic [1:0] CacheBusRW, // Cache bus operation, 01: writeback, 10: fetch
|
||||
output logic CacheBusAck, // Handshack to $ indicating bus transaction completed
|
||||
|
||||
// lsu interface
|
||||
output logic [AHBWLOGBWPL-1:0] BeatCount, // Beat position within the cache line in the Address Phase
|
||||
output logic [AHBWLOGBWPL-1:0] BeatCountDelayed, // Beat within the cache line in the second (Data) cache stage
|
||||
output logic SelBusBeat, // Tells the cache to select the word from ReadData or WriteData from BeatCount rather than PAdr
|
||||
output logic SelBusBeat, // Tells the cache to select the word from ReadData or WriteData from BeatCount rather than PAdr
|
||||
|
||||
// BUS interface
|
||||
input logic HREADY, // AHB peripheral ready
|
||||
output logic [1:0] HTRANS, // AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
output logic HWRITE, // AHB 0: Read operation 1: Write operation
|
||||
output logic [2:0] HBURST // AHB burst length
|
||||
input logic HREADY, // AHB peripheral ready
|
||||
output logic [1:0] HTRANS, // AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
output logic HWRITE, // AHB 0: Read operation 1: Write operation
|
||||
output logic [2:0] HBURST // AHB burst length
|
||||
);
|
||||
|
||||
typedef enum logic [2:0] {ADR_PHASE, DATA_PHASE, MEM3, CACHE_FETCH, CACHE_WRITEBACK} busstatetype;
|
||||
|
@ -78,8 +78,8 @@ module buscachefsm #(
|
|||
logic CacheAccess;
|
||||
|
||||
always_ff @(posedge HCLK)
|
||||
if (~HRESETn | Flush) CurrState <= #1 ADR_PHASE;
|
||||
else CurrState <= #1 NextState;
|
||||
if (~HRESETn | Flush) CurrState <= #1 ADR_PHASE;
|
||||
else CurrState <= #1 NextState;
|
||||
|
||||
always_comb begin
|
||||
case(CurrState)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////
|
||||
// controller input stage
|
||||
// controllerinput.sv
|
||||
//
|
||||
// Written: Ross Thompson ross1728@gmail.com
|
||||
// Created: August 31, 2022
|
||||
|
@ -36,26 +36,26 @@
|
|||
module controllerinput #(
|
||||
parameter SAVE_ENABLED = 1 // 1: Save manager inputs if Save = 1, 0: Don't save inputs
|
||||
)(
|
||||
input logic HCLK,
|
||||
input logic HRESETn,
|
||||
input logic Save, // Two or more managers requesting (HTRANS != 00) at the same time. Save the non-granted manager inputs
|
||||
input logic Restore, // Restore a saved manager inputs when it is finally granted
|
||||
input logic Disable, // Supress HREADY to the non-granted manager
|
||||
input logic HCLK,
|
||||
input logic HRESETn,
|
||||
input logic Save, // Two or more managers requesting (HTRANS != 00) at the same time. Save the non-granted manager inputs
|
||||
input logic Restore, // Restore a saved manager inputs when it is finally granted
|
||||
input logic Disable, // Suppress HREADY to the non-granted manager
|
||||
output logic Request, // This manager is making a request
|
||||
// controller input
|
||||
input logic [1:0] HTRANSIn, // Manager input. AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
input logic HWRITEIn, // Manager input. AHB 0: Read operation 1: Write operation
|
||||
input logic [2:0] HSIZEIn, // Manager input. AHB transaction width
|
||||
input logic [2:0] HBURSTIn, // Manager input. AHB burst length
|
||||
input logic [`PA_BITS-1:0] HADDRIn, // Manager input. AHB address
|
||||
output logic HREADYOut, // Indicate to manager the peripherial is not busy and another manager does not have priority
|
||||
input logic [1:0] HTRANSIn, // Manager input. AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
input logic HWRITEIn, // Manager input. AHB 0: Read operation 1: Write operation
|
||||
input logic [2:0] HSIZEIn, // Manager input. AHB transaction width
|
||||
input logic [2:0] HBURSTIn, // Manager input. AHB burst length
|
||||
input logic [`PA_BITS-1:0] HADDRIn, // Manager input. AHB address
|
||||
output logic HREADYOut, // Indicate to manager the peripheral is not busy and another manager does not have priority
|
||||
// controller output
|
||||
output logic [1:0] HTRANSOut, // Aribrated manager transaction. AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
output logic HWRITEOut, // Aribrated manager transaction. AHB 0: Read operation 1: Write operation
|
||||
output logic [2:0] HSIZEOut, // Aribrated manager transaction. AHB transaction width
|
||||
output logic [2:0] HBURSTOut, // Aribrated manager transaction. AHB burst length
|
||||
output logic [`PA_BITS-1:0] HADDROut, // Aribrated manager transaction. AHB address
|
||||
input logic HREADYIn // Peripherial ready
|
||||
output logic [1:0] HTRANSOut, // Arbitrated manager transaction. AHB transaction type, 00: IDLE, 10 NON_SEQ, 11 SEQ
|
||||
output logic HWRITEOut, // Arbitrated manager transaction. AHB 0: Read operation 1: Write operation
|
||||
output logic [2:0] HSIZEOut, // Arbitrated manager transaction. AHB transaction width
|
||||
output logic [2:0] HBURSTOut, // Arbitrated manager transaction. AHB burst length
|
||||
output logic [`PA_BITS-1:0] HADDROut, // Arbitrated manager transaction. AHB address
|
||||
input logic HREADYIn // Peripheral ready
|
||||
);
|
||||
|
||||
logic HWRITESave;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////
|
||||
// ebufsmarb
|
||||
// ebufsmarb.sv
|
||||
//
|
||||
// Written: Ross Thompson ross1728@gmail.com
|
||||
// Created: 23 January 2023
|
||||
|
@ -55,7 +55,7 @@ module ebufsmarb (
|
|||
logic IFUReqD; // 1 cycle delayed IFU request. Part of arbitration
|
||||
logic FinalBeat, FinalBeatD; // Indicates the last beat of a burst
|
||||
logic BeatCntEn;
|
||||
logic [3:0] BeatCount; // Position within a burst transfer
|
||||
logic [3:0] BeatCount; // Position within a burst transfer
|
||||
logic BeatCntReset;
|
||||
logic [3:0] Threshold; // Number of beats derived from HBURST
|
||||
|
||||
|
@ -86,7 +86,7 @@ module ebufsmarb (
|
|||
// Controller 1 (LSU)
|
||||
// When both the IFU and LSU request at the same time, the FSM will go into the arbitrate state.
|
||||
// Once the LSU request is done the fsm returns to IDLE. To prevent the LSU from regaining
|
||||
// priority and re issuing the same memroy operation, the delayed IFUReqD squashes the LSU request.
|
||||
// priority and re-issuing the same memory operation, the delayed IFUReqD squashes the LSU request.
|
||||
// This is necessary because the pipeline is stalled for the entire duration of both transactions,
|
||||
// and the LSU memory request will stil be active.
|
||||
flopr #(1) ifureqreg(HCLK, ~HRESETn, IFUReq, IFUReqD);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////
|
||||
// fdivsqrtpreproc.sv
|
||||
// fdivsqrtexpcalc.sv
|
||||
//
|
||||
// Written: David_Harris@hmc.edu, me@KatherineParry.com, cturek@hmc.edu
|
||||
// Modified:13 January 2022
|
||||
|
@ -30,11 +30,11 @@
|
|||
|
||||
module fdivsqrtexpcalc(
|
||||
input logic [`FMTBITS-1:0] Fmt,
|
||||
input logic [`NE-1:0] Xe, Ye,
|
||||
input logic Sqrt,
|
||||
input logic XZero,
|
||||
input logic [`DIVBLEN:0] ell, m,
|
||||
output logic [`NE+1:0] Qe
|
||||
input logic [`NE-1:0] Xe, Ye,
|
||||
input logic Sqrt,
|
||||
input logic XZero,
|
||||
input logic [`DIVBLEN:0] ell, m,
|
||||
output logic [`NE+1:0] Qe
|
||||
);
|
||||
logic [`NE-2:0] Bias;
|
||||
logic [`NE+1:0] SXExp;
|
||||
|
@ -42,28 +42,28 @@ module fdivsqrtexpcalc(
|
|||
logic [`NE+1:0] DExp;
|
||||
|
||||
if (`FPSIZES == 1) begin
|
||||
assign Bias = (`NE-1)'(`BIAS);
|
||||
assign Bias = (`NE-1)'(`BIAS);
|
||||
|
||||
end else if (`FPSIZES == 2) begin
|
||||
assign Bias = Fmt ? (`NE-1)'(`BIAS) : (`NE-1)'(`BIAS1);
|
||||
assign Bias = Fmt ? (`NE-1)'(`BIAS) : (`NE-1)'(`BIAS1);
|
||||
|
||||
end else if (`FPSIZES == 3) begin
|
||||
always_comb
|
||||
case (Fmt)
|
||||
`FMT: Bias = (`NE-1)'(`BIAS);
|
||||
`FMT1: Bias = (`NE-1)'(`BIAS1);
|
||||
`FMT2: Bias = (`NE-1)'(`BIAS2);
|
||||
default: Bias = 'x;
|
||||
endcase
|
||||
always_comb
|
||||
case (Fmt)
|
||||
`FMT: Bias = (`NE-1)'(`BIAS);
|
||||
`FMT1: Bias = (`NE-1)'(`BIAS1);
|
||||
`FMT2: Bias = (`NE-1)'(`BIAS2);
|
||||
default: Bias = 'x;
|
||||
endcase
|
||||
|
||||
end else if (`FPSIZES == 4) begin
|
||||
always_comb
|
||||
case (Fmt)
|
||||
2'h3: Bias = (`NE-1)'(`Q_BIAS);
|
||||
2'h1: Bias = (`NE-1)'(`D_BIAS);
|
||||
2'h0: Bias = (`NE-1)'(`S_BIAS);
|
||||
2'h2: Bias = (`NE-1)'(`H_BIAS);
|
||||
endcase
|
||||
always_comb
|
||||
case (Fmt)
|
||||
2'h3: Bias = (`NE-1)'(`Q_BIAS);
|
||||
2'h1: Bias = (`NE-1)'(`D_BIAS);
|
||||
2'h0: Bias = (`NE-1)'(`S_BIAS);
|
||||
2'h2: Bias = (`NE-1)'(`H_BIAS);
|
||||
endcase
|
||||
end
|
||||
assign SXExp = {2'b0, Xe} - {{(`NE+1-`DIVBLEN){1'b0}}, ell} - (`NE+2)'(`BIAS);
|
||||
assign SExp = {SXExp[`NE+1], SXExp[`NE+1:1]} + {2'b0, Bias};
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
`include "wally-config.vh"
|
||||
|
||||
module fdivsqrtfgen2 (
|
||||
input logic up, uz,
|
||||
input logic up, uz,
|
||||
input logic [`DIVb+3:0] C, U, UM,
|
||||
output logic [`DIVb+3:0] F
|
||||
);
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
`include "wally-config.vh"
|
||||
|
||||
module fdivsqrtfgen4 (
|
||||
input logic [3:0] udigit,
|
||||
input logic [3:0] udigit,
|
||||
input logic [`DIVb+3:0] C, U, UM,
|
||||
output logic [`DIVb+3:0] F
|
||||
);
|
||||
|
|
|
@ -29,24 +29,24 @@
|
|||
`include "wally-config.vh"
|
||||
|
||||
module fdivsqrtfsm(
|
||||
input logic clk,
|
||||
input logic reset,
|
||||
input logic clk,
|
||||
input logic reset,
|
||||
input logic [`FMTBITS-1:0] FmtE,
|
||||
input logic XInfE, YInfE,
|
||||
input logic XZeroE, YZeroE,
|
||||
input logic XNaNE, YNaNE,
|
||||
input logic FDivStartE, IDivStartE,
|
||||
input logic XsE,
|
||||
input logic SqrtE,
|
||||
input logic StallM,
|
||||
input logic FlushE,
|
||||
input logic WZeroE,
|
||||
input logic IntDivE,
|
||||
input logic [`DIVBLEN:0] nE,
|
||||
input logic ISpecialCaseE,
|
||||
output logic IFDivStartE,
|
||||
output logic FDivBusyE, FDivDoneE,
|
||||
output logic SpecialCaseM
|
||||
input logic XInfE, YInfE,
|
||||
input logic XZeroE, YZeroE,
|
||||
input logic XNaNE, YNaNE,
|
||||
input logic FDivStartE, IDivStartE,
|
||||
input logic XsE,
|
||||
input logic SqrtE,
|
||||
input logic StallM,
|
||||
input logic FlushE,
|
||||
input logic WZeroE,
|
||||
input logic IntDivE,
|
||||
input logic [`DIVBLEN:0] nE,
|
||||
input logic ISpecialCaseE,
|
||||
output logic IFDivStartE,
|
||||
output logic FDivBusyE, FDivDoneE,
|
||||
output logic SpecialCaseM
|
||||
);
|
||||
|
||||
typedef enum logic [1:0] {IDLE, BUSY, DONE} statetype;
|
||||
|
|
|
@ -29,10 +29,10 @@
|
|||
`include "wally-config.vh"
|
||||
|
||||
module fdivsqrtiter(
|
||||
input logic clk,
|
||||
input logic IFDivStartE,
|
||||
input logic FDivBusyE,
|
||||
input logic SqrtE,
|
||||
input logic clk,
|
||||
input logic IFDivStartE,
|
||||
input logic FDivBusyE,
|
||||
input logic SqrtE,
|
||||
input logic [`DIVb+3:0] X,
|
||||
input logic [`DIVb-1:0] DPreproc,
|
||||
output logic [`DIVb-1:0] D,
|
||||
|
|
|
@ -112,7 +112,7 @@ module fdivsqrtpostproc(
|
|||
|
||||
// Select quotient or remainder and do normalization shift
|
||||
mux2 #(`DIVBLEN+1) normshiftmux(((`DIVBLEN+1)'(`DIVb) - (nM * (`DIVBLEN+1)'(`LOGR))), (mM + (`DIVBLEN+1)'(`DIVa)), RemOpM, NormShiftM);
|
||||
mux2 #(`DIVb+4) presresultmux(NormQuotM, NormRemM, RemOpM, PreResultM);
|
||||
mux2 #(`DIVb+4) presresultmux(NormQuotM, NormRemM, RemOpM, PreResultM);
|
||||
assign PreIntResultM = $signed(PreResultM >>> NormShiftM);
|
||||
|
||||
// special case logic
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
module fdivsqrtqsel2 (
|
||||
input logic [3:0] ps, pc,
|
||||
output logic up, uz, un
|
||||
output logic up, uz, un
|
||||
);
|
||||
|
||||
logic [3:0] p, g;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
module fdivsqrtstage4 (
|
||||
input logic [`DIVb-1:0] D,
|
||||
input logic [`DIVb+3:0] DBar, D2, DBar2,
|
||||
input logic [`DIVb:0] U,UM,
|
||||
input logic [`DIVb:0] U,UM,
|
||||
input logic [`DIVb+3:0] WS, WC,
|
||||
input logic [`DIVb+1:0] C,
|
||||
input logic SqrtE, j1,
|
||||
|
@ -58,8 +58,8 @@ module fdivsqrtstage4 (
|
|||
// 0000 = 0
|
||||
// 0010 = -1
|
||||
// 0001 = -2
|
||||
assign Smsbs = U[`DIVb:`DIVb-4];
|
||||
assign Dmsbs = D[`DIVb-1:`DIVb-3];
|
||||
assign Smsbs = U[`DIVb:`DIVb-4];
|
||||
assign Dmsbs = D[`DIVb-1:`DIVb-3];
|
||||
assign WCmsbs = WC[`DIVb+3:`DIVb-4];
|
||||
assign WSmsbs = WS[`DIVb+3:`DIVb-4];
|
||||
|
||||
|
|
|
@ -32,10 +32,10 @@
|
|||
// Unified OTFC, Radix 2 //
|
||||
///////////////////////////////
|
||||
module fdivsqrtuotfc2(
|
||||
input logic up, un,
|
||||
input logic up, un,
|
||||
input logic [`DIVb+1:0] C,
|
||||
input logic [`DIVb:0] U, UM,
|
||||
output logic [`DIVb:0] UNext, UMNext
|
||||
input logic [`DIVb:0] U, UM,
|
||||
output logic [`DIVb:0] UNext, UMNext
|
||||
);
|
||||
// The on-the-fly converter transfers the divsqrt
|
||||
// bits to the quotient as they come.
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
`include "wally-config.vh"
|
||||
|
||||
module fdivsqrtuotfc4(
|
||||
input logic [3:0] udigit,
|
||||
input logic [3:0] udigit,
|
||||
input logic [`DIVb:0] U, UM,
|
||||
input logic [`DIVb:0] C,
|
||||
output logic [`DIVb:0] UNext, UMNext
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module lzc #(parameter WIDTH = 1) (
|
||||
input logic [WIDTH-1:0] num, // number to count the leading zeroes of
|
||||
input logic [WIDTH-1:0] num, // number to count the leading zeroes of
|
||||
output logic [$clog2(WIDTH+1)-1:0] ZeroCnt // the number of leading zeroes
|
||||
);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ module mux3 #(parameter WIDTH = 8) (
|
|||
input logic [1:0] s,
|
||||
output logic [WIDTH-1:0] y);
|
||||
|
||||
assign y = s[1] ? d2 : (s[0] ? d1 : d0);
|
||||
assign y = s[1] ? d2 : (s[0] ? d1 : d0); // exclusion-tag: mux3
|
||||
endmodule
|
||||
|
||||
module mux4 #(parameter WIDTH = 8) (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////
|
||||
// oneHotDecoder.sv
|
||||
// onehotdecoder.sv
|
||||
//
|
||||
// Written: ross1728@gmail.com July 09, 2021
|
||||
// Modified:
|
||||
|
|
|
@ -30,13 +30,13 @@
|
|||
|
||||
module hazard (
|
||||
// Detect hazards
|
||||
input logic BPWrongE, CSRWriteFenceM, RetM, TrapM,
|
||||
input logic LoadStallD, StoreStallD, MDUStallD, CSRRdStallD,
|
||||
input logic LSUStallM, IFUStallF,
|
||||
input logic FCvtIntStallD, FPUStallD,
|
||||
input logic DivBusyE, FDivBusyE,
|
||||
input logic EcallFaultM, BreakpointFaultM,
|
||||
input logic wfiM, IntPendingM,
|
||||
input logic BPWrongE, CSRWriteFenceM, RetM, TrapM,
|
||||
input logic LoadStallD, StoreStallD, MDUStallD, CSRRdStallD,
|
||||
input logic LSUStallM, IFUStallF,
|
||||
input logic FCvtIntStallD, FPUStallD,
|
||||
input logic DivBusyE, FDivBusyE,
|
||||
input logic EcallFaultM, BreakpointFaultM,
|
||||
input logic wfiM, IntPendingM,
|
||||
// Stall & flush outputs
|
||||
output logic StallF, StallD, StallE, StallM, StallW,
|
||||
output logic FlushD, FlushE, FlushM, FlushW
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
module byteUnit #(parameter WIDTH=32) (
|
||||
input logic [WIDTH-1:0] A, // Operands
|
||||
input logic ByteSelect, // LSB of Immediate
|
||||
input logic ByteSelect, // LSB of Immediate
|
||||
output logic [WIDTH-1:0] ByteResult); // rev8, orcb result
|
||||
|
||||
logic [WIDTH-1:0] OrcBResult, Rev8Result;
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
|
||||
module cnt #(parameter WIDTH = 32) (
|
||||
input logic [WIDTH-1:0] A, RevA, // Operands
|
||||
input logic [1:0] B, // Last 2 bits of immediate
|
||||
input logic W64, // Indicates word operation
|
||||
input logic [1:0] B, // Last 2 bits of immediate
|
||||
input logic W64, // Indicates word operation
|
||||
output logic [WIDTH-1:0] CntResult // count result
|
||||
);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
module ext #(parameter WIDTH = 32) (
|
||||
input logic [WIDTH-1:0] A, // Operands
|
||||
input logic [1:0] ExtSelect, // B[2], B[0] of immediate
|
||||
input logic [1:0] ExtSelect, // B[2], B[0] of immediate
|
||||
output logic [WIDTH-1:0] ExtResult); // Extend Result
|
||||
|
||||
logic [WIDTH-1:0] sexthResult, zexthResult, sextbResult;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module popcnt #(parameter WIDTH = 32) (
|
||||
input logic [WIDTH-1:0] num, // number to count total ones
|
||||
input logic [WIDTH-1:0] num, // number to count total ones
|
||||
output logic [$clog2(WIDTH):0] PopCnt // the total number of ones
|
||||
);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
`include "wally-config.vh"
|
||||
|
||||
module ieu (
|
||||
input logic clk, reset,
|
||||
input logic clk, reset,
|
||||
// Decode stage signals
|
||||
input logic [31:0] InstrD, // Instruction
|
||||
input logic IllegalIEUFPUInstrD, // Illegal instruction
|
||||
|
|
|
@ -35,9 +35,9 @@ module shifter (
|
|||
input logic Right, Rotate, W64, SubArith, // Shift right, rotate, W64-type operation, arithmetic shift
|
||||
output logic [`XLEN-1:0] Y); // Shifted result
|
||||
|
||||
logic [2*`XLEN-2:0] Z, ZShift; // Input to funnel shifter, shifted amount before truncated to 32 or 64 bits
|
||||
logic [`LOG_XLEN-1:0] TruncAmt, Offset; // Shift amount adjusted for RV64, right-shift amount
|
||||
logic Sign; // Sign bit for sign extension
|
||||
logic [2*`XLEN-2:0] Z, ZShift; // Input to funnel shifter, shifted amount before truncated to 32 or 64 bits
|
||||
logic [`LOG_XLEN-1:0] TruncAmt, Offset; // Shift amount adjusted for RV64, right-shift amount
|
||||
logic Sign; // Sign bit for sign extension
|
||||
|
||||
assign Sign = A[`XLEN-1] & SubArith; // sign bit for sign extension
|
||||
if (`XLEN==32) begin // rv32
|
||||
|
|
|
@ -48,25 +48,25 @@ module bpred (
|
|||
input logic [`XLEN-1:0] PCE, // Execution stage instruction address
|
||||
input logic [`XLEN-1:0] PCM, // Memory stage instruction address
|
||||
|
||||
input logic [31:0] PostSpillInstrRawF, // Instruction
|
||||
input logic [31:0] PostSpillInstrRawF, // Instruction
|
||||
|
||||
// Branch and jump outcome
|
||||
input logic InstrValidD, InstrValidE,
|
||||
input logic InstrValidD, InstrValidE,
|
||||
input logic BranchD, BranchE,
|
||||
input logic JumpD, JumpE,
|
||||
input logic PCSrcE, // Executation stage branch is taken
|
||||
input logic [`XLEN-1:0] IEUAdrE, // The branch/jump target address
|
||||
input logic [`XLEN-1:0] IEUAdrM, // The branch/jump target address
|
||||
input logic [`XLEN-1:0] PCLinkE, // The address following the branch instruction. (AKA Fall through address)
|
||||
input logic PCSrcE, // Executation stage branch is taken
|
||||
input logic [`XLEN-1:0] IEUAdrE, // The branch/jump target address
|
||||
input logic [`XLEN-1:0] IEUAdrM, // The branch/jump target address
|
||||
input logic [`XLEN-1:0] PCLinkE, // The address following the branch instruction. (AKA Fall through address)
|
||||
output logic [3:0] InstrClassM, // The valid instruction class. 1-hot encoded as call, return, jr (not return), j, br
|
||||
|
||||
// Report branch prediction status
|
||||
output logic BPWrongE, // Prediction is wrong
|
||||
output logic BPWrongM, // Prediction is wrong
|
||||
output logic BPWrongE, // Prediction is wrong
|
||||
output logic BPWrongM, // Prediction is wrong
|
||||
output logic BPDirPredWrongM, // Prediction direction is wrong
|
||||
output logic BTAWrongM, // Prediction target wrong
|
||||
output logic BTAWrongM, // Prediction target wrong
|
||||
output logic RASPredPCWrongM, // RAS prediction is wrong
|
||||
output logic IClassWrongM // Class prediction is wrong
|
||||
output logic IClassWrongM // Class prediction is wrong
|
||||
);
|
||||
|
||||
logic [1:0] BPDirPredF;
|
||||
|
@ -187,7 +187,7 @@ module bpred (
|
|||
// Correct branch/jump target.
|
||||
mux2 #(`XLEN) pccorrectemux(PCLinkE, IEUAdrE, PCSrcE, PCCorrectE);
|
||||
|
||||
// If the fence/csrw was predicted as a taken branch then we select PCF, rather PCE.
|
||||
// If the fence/csrw was predicted as a taken branch then we select PCF, rather than PCE.
|
||||
// Effectively this is PCM+4 or the non-existant PCLinkM
|
||||
if(`INSTR_CLASS_PRED) mux2 #(`XLEN) pcmuxBPWrongInvalidateFlush(PCE, PCF, BPWrongM, NextValidPCE);
|
||||
else assign NextValidPCE = PCE;
|
||||
|
@ -201,11 +201,11 @@ module bpred (
|
|||
// 3. target ras (ras target wrong / class[2])
|
||||
// 4. direction (br dir wrong / class[0])
|
||||
|
||||
// Unforuantely we can't use PCD to infer the correctness of the BTB or RAS because the class prediction
|
||||
// Unfortunately we can't use PCD to infer the correctness of the BTB or RAS because the class prediction
|
||||
// could be wrong or the fall through address selected for branch predict not taken.
|
||||
// By pipeline the BTB's PC and RAS address through the pipeline we can measure the accuracy of
|
||||
// both without the above inaccuracies.
|
||||
// **** use BPBTAWrongM from BTB.
|
||||
// **** use BPBTAWrongM from BTB.
|
||||
assign BTAWrongE = (BPBTAE != IEUAdrE) & (BranchE | JumpE & ~ReturnE) & PCSrcE;
|
||||
assign RASPredPCWrongE = (RASPCE != IEUAdrE) & ReturnE & PCSrcE;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
///////////////////////////////////////////
|
||||
// btb.sv
|
||||
//
|
||||
// Written: Ross Thomposn ross1728@gmail.com
|
||||
// Written: Ross Thompson ross1728@gmail.com
|
||||
// Created: February 15, 2021
|
||||
// Modified: 24 January 2023
|
||||
//
|
||||
|
@ -34,19 +34,19 @@ module btb #(parameter Depth = 10 ) (
|
|||
input logic clk,
|
||||
input logic reset,
|
||||
input logic StallF, StallD, StallE, StallM, StallW, FlushD, FlushE, FlushM, FlushW,
|
||||
input logic [`XLEN-1:0] PCNextF, PCF, PCD, PCE, PCM,// PC at various stages
|
||||
output logic [`XLEN-1:0] BPBTAF, // BTB's guess at PC
|
||||
input logic [`XLEN-1:0] PCNextF, PCF, PCD, PCE, PCM, // PC at various stages
|
||||
output logic [`XLEN-1:0] BPBTAF, // BTB's guess at PC
|
||||
output logic [`XLEN-1:0] BPBTAD,
|
||||
output logic [`XLEN-1:0] BPBTAE,
|
||||
output logic [3:0] BTBIClassF, // BTB's guess at instruction class
|
||||
output logic [3:0] BTBIClassF, // BTB's guess at instruction class
|
||||
// update
|
||||
input logic IClassWrongM, // BTB's instruction class guess was wrong
|
||||
input logic IClassWrongM, // BTB's instruction class guess was wrong
|
||||
input logic IClassWrongE,
|
||||
input logic [`XLEN-1:0] IEUAdrE, // Branch/jump target address to insert into btb
|
||||
input logic [`XLEN-1:0] IEUAdrM, // Branch/jump target address to insert into btb
|
||||
input logic [3:0] InstrClassD, // Instruction class to insert into btb
|
||||
input logic [3:0] InstrClassE, // Instruction class to insert into btb
|
||||
input logic [3:0] InstrClassM, // Instruction class to insert into btb
|
||||
input logic [`XLEN-1:0] IEUAdrE, // Branch/jump target address to insert into btb
|
||||
input logic [`XLEN-1:0] IEUAdrM, // Branch/jump target address to insert into btb
|
||||
input logic [3:0] InstrClassD, // Instruction class to insert into btb
|
||||
input logic [3:0] InstrClassE, // Instruction class to insert into btb
|
||||
input logic [3:0] InstrClassM, // Instruction class to insert into btb
|
||||
input logic [3:0] InstrClassW
|
||||
);
|
||||
|
||||
|
@ -73,7 +73,7 @@ module btb #(parameter Depth = 10 ) (
|
|||
|
||||
// must output a valid PC and valid bit during reset. Because only PCF, not PCNextF is reset, PCNextF is invalid
|
||||
// during reset. The BTB must produce a non X PC1NextF to allow the simulation to run.
|
||||
// While thie mux could be included in IFU it is not necessary for the IROM/I$/bus.
|
||||
// While the mux could be included in IFU it is not necessary for the IROM/I$/bus.
|
||||
// For now it is optimal to leave it here.
|
||||
assign ResetPC = `RESET_VECTOR;
|
||||
assign PCNextFIndex = reset ? ResetPC[Depth+1:2] : {PCNextF[Depth+1] ^ PCNextF[1], PCNextF[Depth:2]};
|
||||
|
|
|
@ -198,9 +198,12 @@ module csrsr (
|
|||
STATUS_UBE <= #1 CSRWriteValM[6] & `U_SUPPORTED & `BIGENDIAN_SUPPORTED;
|
||||
STATUS_MBE <= #1 nextMBE;
|
||||
STATUS_SBE <= #1 nextSBE;
|
||||
// coverage off
|
||||
// MSTATUSH only exists in 32-bit configurations, will not be hit on rv64gc
|
||||
end else if (WriteMSTATUSHM) begin
|
||||
STATUS_MBE <= #1 CSRWriteValM[5] & `BIGENDIAN_SUPPORTED;
|
||||
STATUS_SBE <= #1 CSRWriteValM[4] & `S_SUPPORTED & `BIGENDIAN_SUPPORTED;
|
||||
// coverage on
|
||||
end else if (WriteSSTATUSM) begin // write a subset of the STATUS bits
|
||||
STATUS_MXR_INT <= #1 CSRWriteValM[19];
|
||||
STATUS_SUM_INT <= #1 CSRWriteValM[18];
|
||||
|
|
|
@ -81,11 +81,14 @@ module trap (
|
|||
///////////////////////////////////////////
|
||||
|
||||
assign BothInstrAccessFaultM = InstrAccessFaultM | HPTWInstrAccessFaultM;
|
||||
// coverage off -item e 1 -fecexprrow 2
|
||||
// excludes InstrMisalignedFaultM from coverage of this line, since misaligned instructions cannot occur in rv64gc.
|
||||
assign ExceptionM = InstrMisalignedFaultM | BothInstrAccessFaultM | IllegalInstrFaultM |
|
||||
LoadMisalignedFaultM | StoreAmoMisalignedFaultM |
|
||||
InstrPageFaultM | LoadPageFaultM | StoreAmoPageFaultM |
|
||||
BreakpointFaultM | EcallFaultM |
|
||||
LoadAccessFaultM | StoreAmoAccessFaultM;
|
||||
// coverage on
|
||||
assign TrapM = ExceptionM | InterruptM;
|
||||
assign RetM = mretM | sretM;
|
||||
|
||||
|
|
|
@ -52,29 +52,29 @@ module testbench;
|
|||
string tests[];
|
||||
logic [3:0] dummy;
|
||||
|
||||
logic [`AHBW-1:0] HRDATAEXT;
|
||||
logic HREADYEXT, HRESPEXT;
|
||||
logic [`AHBW-1:0] HRDATAEXT;
|
||||
logic HREADYEXT, HRESPEXT;
|
||||
logic [`PA_BITS-1:0] HADDR;
|
||||
logic [`AHBW-1:0] HWDATA;
|
||||
logic [`XLEN/8-1:0] HWSTRB;
|
||||
logic HWRITE;
|
||||
logic [2:0] HSIZE;
|
||||
logic [2:0] HBURST;
|
||||
logic [3:0] HPROT;
|
||||
logic [1:0] HTRANS;
|
||||
logic HMASTLOCK;
|
||||
logic HCLK, HRESETn;
|
||||
logic [`XLEN-1:0] PCW;
|
||||
logic [`AHBW-1:0] HWDATA;
|
||||
logic [`XLEN/8-1:0] HWSTRB;
|
||||
logic HWRITE;
|
||||
logic [2:0] HSIZE;
|
||||
logic [2:0] HBURST;
|
||||
logic [3:0] HPROT;
|
||||
logic [1:0] HTRANS;
|
||||
logic HMASTLOCK;
|
||||
logic HCLK, HRESETn;
|
||||
logic [`XLEN-1:0] PCW;
|
||||
|
||||
string ProgramAddrMapFile, ProgramLabelMapFile;
|
||||
integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 };
|
||||
string ProgramAddrMapFile, ProgramLabelMapFile;
|
||||
integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 };
|
||||
|
||||
logic DCacheFlushDone, DCacheFlushStart;
|
||||
logic DCacheFlushDone, DCacheFlushStart;
|
||||
logic riscofTest;
|
||||
logic StartSample, EndSample;
|
||||
|
||||
flopenr #(`XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW);
|
||||
flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW);
|
||||
flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW);
|
||||
|
||||
// check assertions for a legal configuration
|
||||
riscvassertions riscvassertions();
|
||||
|
@ -85,62 +85,62 @@ module testbench;
|
|||
//tests = '{};
|
||||
if (`XLEN == 64) begin // RV64
|
||||
case (TEST)
|
||||
"arch64i": tests = arch64i;
|
||||
"arch64priv": tests = arch64priv;
|
||||
"arch64i": tests = arch64i;
|
||||
"arch64priv": tests = arch64priv;
|
||||
"arch64c": if (`C_SUPPORTED)
|
||||
if (`ZICSR_SUPPORTED) tests = {arch64c, arch64cpriv};
|
||||
else tests = {arch64c};
|
||||
"arch64m": if (`M_SUPPORTED) tests = arch64m;
|
||||
"arch64f": if (`F_SUPPORTED) tests = arch64f;
|
||||
"arch64d": if (`D_SUPPORTED) tests = arch64d;
|
||||
if (`ZICSR_SUPPORTED) tests = {arch64c, arch64cpriv};
|
||||
else tests = {arch64c};
|
||||
"arch64m": if (`M_SUPPORTED) tests = arch64m;
|
||||
"arch64f": if (`F_SUPPORTED) tests = arch64f;
|
||||
"arch64d": if (`D_SUPPORTED) tests = arch64d;
|
||||
"arch64zi": if (`ZIFENCEI_SUPPORTED) tests = arch64zi;
|
||||
"imperas64i": tests = imperas64i;
|
||||
"imperas64f": if (`F_SUPPORTED) tests = imperas64f;
|
||||
"imperas64d": if (`D_SUPPORTED) tests = imperas64d;
|
||||
"imperas64m": if (`M_SUPPORTED) tests = imperas64m;
|
||||
"wally64a": if (`A_SUPPORTED) tests = wally64a;
|
||||
"imperas64c": if (`C_SUPPORTED) tests = imperas64c;
|
||||
else tests = imperas64iNOc;
|
||||
"custom": tests = custom;
|
||||
"wally64i": tests = wally64i;
|
||||
"wally64priv": tests = wally64priv;
|
||||
"wally64periph": tests = wally64periph;
|
||||
"coremark": tests = coremark;
|
||||
"fpga": tests = fpga;
|
||||
"ahb" : tests = ahb;
|
||||
"coverage64gc" : tests = coverage64gc;
|
||||
"arch64zba": if (`ZBA_SUPPORTED) tests = arch64zba;
|
||||
"arch64zbb": if (`ZBB_SUPPORTED) tests = arch64zbb;
|
||||
"arch64zbc": if (`ZBC_SUPPORTED) tests = arch64zbc;
|
||||
"arch64zbs": if (`ZBS_SUPPORTED) tests = arch64zbs;
|
||||
"imperas64i": tests = imperas64i;
|
||||
"imperas64f": if (`F_SUPPORTED) tests = imperas64f;
|
||||
"imperas64d": if (`D_SUPPORTED) tests = imperas64d;
|
||||
"imperas64m": if (`M_SUPPORTED) tests = imperas64m;
|
||||
"wally64a": if (`A_SUPPORTED) tests = wally64a;
|
||||
"imperas64c": if (`C_SUPPORTED) tests = imperas64c;
|
||||
else tests = imperas64iNOc;
|
||||
"custom": tests = custom;
|
||||
"wally64i": tests = wally64i;
|
||||
"wally64priv": tests = wally64priv;
|
||||
"wally64periph": tests = wally64periph;
|
||||
"coremark": tests = coremark;
|
||||
"fpga": tests = fpga;
|
||||
"ahb" : tests = ahb;
|
||||
"coverage64gc" : tests = coverage64gc;
|
||||
"arch64zba": if (`ZBA_SUPPORTED) tests = arch64zba;
|
||||
"arch64zbb": if (`ZBB_SUPPORTED) tests = arch64zbb;
|
||||
"arch64zbc": if (`ZBC_SUPPORTED) tests = arch64zbc;
|
||||
"arch64zbs": if (`ZBS_SUPPORTED) tests = arch64zbs;
|
||||
endcase
|
||||
end else begin // RV32
|
||||
case (TEST)
|
||||
"arch32i": tests = arch32i;
|
||||
"arch32priv": tests = arch32priv;
|
||||
"arch32i": tests = arch32i;
|
||||
"arch32priv": tests = arch32priv;
|
||||
"arch32c": if (`C_SUPPORTED)
|
||||
if (`ZICSR_SUPPORTED) tests = {arch32c, arch32cpriv};
|
||||
else tests = {arch32c};
|
||||
"arch32m": if (`M_SUPPORTED) tests = arch32m;
|
||||
"arch32f": if (`F_SUPPORTED) tests = arch32f;
|
||||
"arch32d": if (`D_SUPPORTED) tests = arch32d;
|
||||
if (`ZICSR_SUPPORTED) tests = {arch32c, arch32cpriv};
|
||||
else tests = {arch32c};
|
||||
"arch32m": if (`M_SUPPORTED) tests = arch32m;
|
||||
"arch32f": if (`F_SUPPORTED) tests = arch32f;
|
||||
"arch32d": if (`D_SUPPORTED) tests = arch32d;
|
||||
"arch32zi": if (`ZIFENCEI_SUPPORTED) tests = arch32zi;
|
||||
"imperas32i": tests = imperas32i;
|
||||
"imperas32f": if (`F_SUPPORTED) tests = imperas32f;
|
||||
"imperas32m": if (`M_SUPPORTED) tests = imperas32m;
|
||||
"wally32a": if (`A_SUPPORTED) tests = wally32a;
|
||||
"imperas32c": if (`C_SUPPORTED) tests = imperas32c;
|
||||
else tests = imperas32iNOc;
|
||||
"wally32i": tests = wally32i;
|
||||
"wally32e": tests = wally32e;
|
||||
"wally32priv": tests = wally32priv;
|
||||
"wally32periph": tests = wally32periph;
|
||||
"embench": tests = embench;
|
||||
"coremark": tests = coremark;
|
||||
"arch32zba": if (`ZBA_SUPPORTED) tests = arch32zba;
|
||||
"arch32zbb": if (`ZBB_SUPPORTED) tests = arch32zbb;
|
||||
"arch32zbc": if (`ZBC_SUPPORTED) tests = arch32zbc;
|
||||
"arch32zbs": if (`ZBS_SUPPORTED) tests = arch32zbs;
|
||||
"imperas32i": tests = imperas32i;
|
||||
"imperas32f": if (`F_SUPPORTED) tests = imperas32f;
|
||||
"imperas32m": if (`M_SUPPORTED) tests = imperas32m;
|
||||
"wally32a": if (`A_SUPPORTED) tests = wally32a;
|
||||
"imperas32c": if (`C_SUPPORTED) tests = imperas32c;
|
||||
else tests = imperas32iNOc;
|
||||
"wally32i": tests = wally32i;
|
||||
"wally32e": tests = wally32e;
|
||||
"wally32priv": tests = wally32priv;
|
||||
"wally32periph": tests = wally32periph;
|
||||
"embench": tests = embench;
|
||||
"coremark": tests = coremark;
|
||||
"arch32zba": if (`ZBA_SUPPORTED) tests = arch32zba;
|
||||
"arch32zbb": if (`ZBB_SUPPORTED) tests = arch32zbb;
|
||||
"arch32zbc": if (`ZBC_SUPPORTED) tests = arch32zbc;
|
||||
"arch32zbs": if (`ZBS_SUPPORTED) tests = arch32zbs;
|
||||
endcase
|
||||
end
|
||||
if (tests.size() == 0) begin
|
||||
|
@ -149,7 +149,7 @@ module testbench;
|
|||
end
|
||||
end
|
||||
|
||||
string signame, memfilename, pathname, objdumpfilename, adrstr, outputfile;
|
||||
string signame, memfilename, pathname, objdumpfilename, adrstr, outputfile;
|
||||
integer outputFilePointer;
|
||||
|
||||
logic [31:0] GPIOIN, GPIOOUT, GPIOEN;
|
||||
|
@ -160,16 +160,16 @@ module testbench;
|
|||
logic SDCCmdOut;
|
||||
logic SDCCmdOE;
|
||||
logic [3:0] SDCDatIn;
|
||||
tri1 [3:0] SDCDat;
|
||||
tri1 [3:0] SDCDat;
|
||||
tri1 SDCCmd;
|
||||
|
||||
logic HREADY;
|
||||
logic HSELEXT;
|
||||
|
||||
logic InitializingMemories;
|
||||
integer ResetCount, ResetThreshold;
|
||||
logic InReset;
|
||||
logic Begin;
|
||||
logic InitializingMemories;
|
||||
integer ResetCount, ResetThreshold;
|
||||
logic InReset;
|
||||
logic BeginSample;
|
||||
|
||||
// instantiate device to be tested
|
||||
assign GPIOIN = 0;
|
||||
|
@ -225,13 +225,14 @@ module testbench;
|
|||
totalerrors = 0;
|
||||
testadr = 0;
|
||||
testadrNoBase = 0;
|
||||
// riscof tests have a different signature, tests[0] == "1" refers to RiscvArchTests and tests[0] == "2" refers to WallyRiscvArchTests
|
||||
// riscof tests have a different signature, tests[0] == "1" refers to RiscvArchTests
|
||||
// and tests[0] == "2" refers to WallyRiscvArchTests
|
||||
riscofTest = tests[0] == "1" | tests[0] == "2";
|
||||
// fill memory with defined values to reduce Xs in simulation
|
||||
// Quick note the memory will need to be initialized. The C library does not
|
||||
// guarantee the initialized reads. For example a strcmp can read 6 byte
|
||||
// strings, but uses a load double to read them in. If the last 2 bytes are
|
||||
// not initialized the compare results in an 'x' which propagates through
|
||||
// guarantee the initialized reads. For example a strcmp can read 6 byte
|
||||
// strings, but uses a load double to read them in. If the last 2 bytes are
|
||||
// not initialized the compare results in an 'x' which propagates through
|
||||
// the design.
|
||||
if (TEST == "coremark")
|
||||
for (i=MemStartAddr; i<MemEndAddr; i = i+1)
|
||||
|
@ -243,7 +244,7 @@ module testbench;
|
|||
pathname = tvpaths[0];
|
||||
else pathname = tvpaths[1]; */
|
||||
if (riscofTest) memfilename = {pathname, tests[test], "/ref/ref.elf.memfile"};
|
||||
else memfilename = {pathname, tests[test], ".elf.memfile"};
|
||||
else memfilename = {pathname, tests[test], ".elf.memfile"};
|
||||
if (`FPGA) begin
|
||||
string romfilename, sdcfilename;
|
||||
romfilename = {"../tests/custom/fpga-test-sdc/bin/fpga-test-sdc.memfile"};
|
||||
|
@ -253,9 +254,9 @@ module testbench;
|
|||
// force sdc timers
|
||||
force dut.uncore.uncore.sdc.SDC.LimitTimers = 1;
|
||||
end else begin
|
||||
if (`IROM_SUPPORTED) $readmemh(memfilename, dut.core.ifu.irom.irom.rom.ROM);
|
||||
if (`IROM_SUPPORTED) $readmemh(memfilename, dut.core.ifu.irom.irom.rom.ROM);
|
||||
else if (`BUS_SUPPORTED) $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
|
||||
if (`DTIM_SUPPORTED) $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM);
|
||||
if (`DTIM_SUPPORTED) $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM);
|
||||
end
|
||||
|
||||
if (riscofTest) begin
|
||||
|
@ -265,8 +266,9 @@ module testbench;
|
|||
ProgramAddrMapFile = {pathname, tests[test], ".elf.objdump.addr"};
|
||||
ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"};
|
||||
end
|
||||
// declare memory labels that interest us, the updateProgramAddrLabelArray task will find the addr of each label and fill the array
|
||||
// to expand, add more elements to this array and initialize them to zero (also initilaize them to zero at the start of the next test)
|
||||
// declare memory labels that interest us, the updateProgramAddrLabelArray task will find
|
||||
// the addr of each label and fill the array. To expand, add more elements to this array
|
||||
// and initialize them to zero (also initilaize them to zero at the start of the next test)
|
||||
if(!`FPGA) begin
|
||||
updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray);
|
||||
$display("Read memfile %s", memfilename);
|
||||
|
@ -294,99 +296,99 @@ module testbench;
|
|||
ResetCount = 0;
|
||||
end
|
||||
end else begin
|
||||
if (TEST == "coremark")
|
||||
if (TEST == "coremark")
|
||||
if (dut.core.priv.priv.EcallFaultM) begin
|
||||
$display("Benchmark: coremark is done.");
|
||||
$stop;
|
||||
$display("Benchmark: coremark is done.");
|
||||
$stop;
|
||||
end
|
||||
// Termination condition (i.e. we finished running current test)
|
||||
if (DCacheFlushDone) begin
|
||||
// Termination condition (i.e. we finished running current test)
|
||||
if (DCacheFlushDone) begin
|
||||
integer begin_signature_addr;
|
||||
InReset = 1;
|
||||
begin_signature_addr = ProgramAddrLabelArray["begin_signature"];
|
||||
if (!begin_signature_addr)
|
||||
$display("begin_signature addr not found in %s", ProgramLabelMapFile);
|
||||
$display("begin_signature addr not found in %s", ProgramLabelMapFile);
|
||||
testadr = ($unsigned(begin_signature_addr))/(`XLEN/8);
|
||||
testadrNoBase = (begin_signature_addr - `UNCORE_RAM_BASE)/(`XLEN/8);
|
||||
#600; // give time for instructions in pipeline to finish
|
||||
if (TEST == "embench") begin
|
||||
// Writes contents of begin_signature to .sim.output file
|
||||
// this contains instret and cycles for start and end of test run, used by embench python speed script to calculate embench speed score
|
||||
// also begin_signature contains the results of the self checking mechanism, which will be read by the python script for error checking
|
||||
// this contains instret and cycles for start and end of test run, used by embench
|
||||
// python speed script to calculate embench speed score.
|
||||
// also, begin_signature contains the results of the self checking mechanism,
|
||||
// which will be read by the python script for error checking
|
||||
$display("Embench Benchmark: %s is done.", tests[test]);
|
||||
if (riscofTest) outputfile = {pathname, tests[test], "/ref/ref.sim.output"};
|
||||
else outputfile = {pathname, tests[test], ".sim.output"};
|
||||
outputFilePointer = $fopen(outputfile);
|
||||
i = 0;
|
||||
while ($unsigned(i) < $unsigned(5'd5)) begin
|
||||
$fdisplayh(outputFilePointer, DCacheFlushFSM.ShadowRAM[testadr+i]);
|
||||
i = i + 1;
|
||||
$fdisplayh(outputFilePointer, DCacheFlushFSM.ShadowRAM[testadr+i]);
|
||||
i = i + 1;
|
||||
end
|
||||
$fclose(outputFilePointer);
|
||||
$display("Embench Benchmark: created output file: %s", outputfile);
|
||||
end else if (TEST == "coverage64gc") begin
|
||||
$display("Coverage tests don't get checked");
|
||||
end else begin
|
||||
// for tests with no self checking mechanism, read .signature.output file and compare to check for errors
|
||||
// clear signature to prevent contamination from previous tests
|
||||
for(i=0; i<SIGNATURESIZE; i=i+1) begin
|
||||
// for tests with no self checking mechanism, read .signature.output file and compare to check for errors
|
||||
// clear signature to prevent contamination from previous tests
|
||||
for(i=0; i<SIGNATURESIZE; i=i+1) begin
|
||||
sig32[i] = 'bx;
|
||||
end
|
||||
if (riscofTest) signame = {pathname, tests[test], "/ref/Reference-sail_c_simulator.signature"};
|
||||
else signame = {pathname, tests[test], ".signature.output"};
|
||||
// read signature, reformat in 64 bits if necessary
|
||||
$readmemh(signame, sig32);
|
||||
i = 0;
|
||||
while (i < SIGNATURESIZE) begin
|
||||
end
|
||||
if (riscofTest) signame = {pathname, tests[test], "/ref/Reference-sail_c_simulator.signature"};
|
||||
else signame = {pathname, tests[test], ".signature.output"};
|
||||
// read signature, reformat in 64 bits if necessary
|
||||
$readmemh(signame, sig32);
|
||||
i = 0;
|
||||
while (i < SIGNATURESIZE) begin
|
||||
if (`XLEN == 32) begin
|
||||
signature[i] = sig32[i];
|
||||
i = i+1;
|
||||
signature[i] = sig32[i];
|
||||
i = i+1;
|
||||
end else begin
|
||||
signature[i/2] = {sig32[i+1], sig32[i]};
|
||||
i = i + 2;
|
||||
signature[i/2] = {sig32[i+1], sig32[i]};
|
||||
i = i + 2;
|
||||
end
|
||||
if (i >= 4 & sig32[i-4] === 'bx) begin
|
||||
if (i == 4) begin
|
||||
if (i == 4) begin
|
||||
i = SIGNATURESIZE+1; // flag empty file
|
||||
$display(" Error: empty test file");
|
||||
end else i = SIGNATURESIZE; // skip over the rest of the x's for efficiency
|
||||
end else i = SIGNATURESIZE; // skip over the rest of the x's for efficiency
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Check errors
|
||||
errors = (i == SIGNATURESIZE+1); // error if file is empty
|
||||
i = 0;
|
||||
/* verilator lint_off INFINITELOOP */
|
||||
while (signature[i] !== 'bx) begin
|
||||
// Check errors
|
||||
errors = (i == SIGNATURESIZE+1); // error if file is empty
|
||||
i = 0;
|
||||
/* verilator lint_off INFINITELOOP */
|
||||
while (signature[i] !== 'bx) begin
|
||||
logic [`XLEN-1:0] sig;
|
||||
if (`DTIM_SUPPORTED) sig = dut.core.lsu.dtim.dtim.ram.RAM[testadrNoBase+i];
|
||||
else if (`UNCORE_RAM_SUPPORTED) sig = dut.uncore.uncore.ram.ram.memory.RAM[testadrNoBase+i];
|
||||
//$display("signature[%h] = %h sig = %h", i, signature[i], sig);
|
||||
if (signature[i] !== sig & (signature[i] !== DCacheFlushFSM.ShadowRAM[testadr+i])) begin
|
||||
errors = errors+1;
|
||||
$display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h",
|
||||
tests[test], i, (testadr+i)*(`XLEN/8), DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]);
|
||||
$stop;//***debug
|
||||
errors = errors+1;
|
||||
$display(" Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h",
|
||||
tests[test], i, (testadr+i)*(`XLEN/8), DCacheFlushFSM.ShadowRAM[testadr+i], sig, signature[i]);
|
||||
$stop; //***debug
|
||||
end
|
||||
i = i + 1;
|
||||
end
|
||||
/* verilator lint_on INFINITELOOP */
|
||||
if (errors == 0) begin
|
||||
end
|
||||
/* verilator lint_on INFINITELOOP */
|
||||
if (errors == 0) begin
|
||||
$display("%s succeeded. Brilliant!!!", tests[test]);
|
||||
end
|
||||
else begin
|
||||
end else begin
|
||||
$display("%s failed with %d errors. :(", tests[test], errors);
|
||||
totalerrors = totalerrors+1;
|
||||
end
|
||||
end
|
||||
end
|
||||
// move onto the next test, check to see if we're done
|
||||
test = test + 1;
|
||||
if (test == tests.size()) begin
|
||||
if (totalerrors == 0) $display("SUCCESS! All tests ran without failures.");
|
||||
else $display("FAIL: %d test programs had errors", totalerrors);
|
||||
$stop;
|
||||
end
|
||||
else begin
|
||||
if (totalerrors == 0) $display("SUCCESS! All tests ran without failures.");
|
||||
else $display("FAIL: %d test programs had errors", totalerrors);
|
||||
$stop;
|
||||
end else begin
|
||||
InitializingMemories = 1;
|
||||
// If there are still additional tests to run, read in information for the next test
|
||||
//pathname = tvpaths[tests[0]];
|
||||
|
@ -394,7 +396,7 @@ module testbench;
|
|||
else memfilename = {pathname, tests[test], ".elf.memfile"};
|
||||
//$readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
|
||||
if (`IROM_SUPPORTED) $readmemh(memfilename, dut.core.ifu.irom.irom.rom.ROM);
|
||||
else if (`UNCORE_RAM_SUPPORTED) $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
|
||||
else if (`UNCORE_RAM_SUPPORTED) $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
|
||||
if (`DTIM_SUPPORTED) $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM);
|
||||
|
||||
if (riscofTest) begin
|
||||
|
@ -405,22 +407,22 @@ module testbench;
|
|||
ProgramLabelMapFile = {pathname, tests[test], ".elf.objdump.lab"};
|
||||
end
|
||||
ProgramAddrLabelArray = '{ "begin_signature" : 0, "tohost" : 0 };
|
||||
if(!`FPGA) begin
|
||||
if(!`FPGA) begin
|
||||
updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray);
|
||||
$display("Read memfile %s", memfilename);
|
||||
end
|
||||
end
|
||||
end
|
||||
end // if (DCacheFlushDone)
|
||||
end // if (DCacheFlushDone)
|
||||
end
|
||||
end // always @ (negedge clk)
|
||||
|
||||
|
||||
if(`PrintHPMCounters & `ZICOUNTERS_SUPPORTED) begin : HPMCSample
|
||||
integer HPMCindex;
|
||||
logic StartSampleFirst;
|
||||
logic StartSampleDelayed, BeginDelayed;
|
||||
logic EndSampleFirst, EndSampleDelayed;
|
||||
logic [`XLEN-1:0] InitialHPMCOUNTERH[`COUNTERS-1:0];
|
||||
integer HPMCindex;
|
||||
logic StartSampleFirst;
|
||||
logic StartSampleDelayed, BeginDelayed;
|
||||
logic EndSampleFirst, EndSampleDelayed;
|
||||
logic [`XLEN-1:0] InitialHPMCOUNTERH[`COUNTERS-1:0];
|
||||
|
||||
string HPMCnames[] = '{"Mcycle",
|
||||
"------",
|
||||
|
@ -433,8 +435,8 @@ module testbench;
|
|||
"BP Target Wrong",
|
||||
"RAS Wrong",
|
||||
"Instr Class Wrong",
|
||||
"Load Stall",
|
||||
"Store Stall",
|
||||
"Load Stall",
|
||||
"Store Stall",
|
||||
"D Cache Access",
|
||||
"D Cache Miss",
|
||||
"D Cache Cycles",
|
||||
|
@ -447,56 +449,55 @@ module testbench;
|
|||
"Interrupt",
|
||||
"Exception",
|
||||
"Divide Cycles"
|
||||
};
|
||||
};
|
||||
|
||||
if(TEST == "embench") begin
|
||||
// embench runs warmup then runs start_trigger
|
||||
// embench end with stop_trigger.
|
||||
assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_trigger";
|
||||
flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
if(TEST == "embench") begin
|
||||
// embench runs warmup then runs start_trigger
|
||||
// embench end with stop_trigger.
|
||||
assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_trigger";
|
||||
flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
|
||||
assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_trigger";
|
||||
flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
|
||||
assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
|
||||
assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_trigger";
|
||||
flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
|
||||
assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
|
||||
|
||||
end else if(TEST == "coremark") begin
|
||||
// embench runs warmup then runs start_trigger
|
||||
// embench end with stop_trigger.
|
||||
assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_time";
|
||||
flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
end else if(TEST == "coremark") begin
|
||||
// embench runs warmup then runs start_trigger
|
||||
// embench end with stop_trigger.
|
||||
assign StartSampleFirst = FunctionName.FunctionName.FunctionName == "start_time";
|
||||
flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
|
||||
assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_time";
|
||||
flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
|
||||
assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
|
||||
assign EndSampleFirst = FunctionName.FunctionName.FunctionName == "stop_time";
|
||||
flopr #(1) EndSampleReg(clk, reset, EndSampleFirst, EndSampleDelayed);
|
||||
assign EndSample = EndSampleFirst & ~ EndSampleDelayed;
|
||||
|
||||
end else begin
|
||||
// default start condiction is reset
|
||||
// default end condiction is end of test (DCacheFlushDone)
|
||||
assign StartSampleFirst = InReset;
|
||||
flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
assign EndSample = DCacheFlushStart & ~DCacheFlushDone;
|
||||
end else begin
|
||||
// default start condiction is reset
|
||||
// default end condiction is end of test (DCacheFlushDone)
|
||||
assign StartSampleFirst = InReset;
|
||||
flopr #(1) StartSampleReg(clk, reset, StartSampleFirst, StartSampleDelayed);
|
||||
assign StartSample = StartSampleFirst & ~ StartSampleDelayed;
|
||||
assign EndSample = DCacheFlushStart & ~DCacheFlushDone;
|
||||
|
||||
flop #(1) BeginReg(clk, StartSampleFirst, BeginDelayed);
|
||||
assign Begin = StartSampleFirst & ~BeginDelayed;
|
||||
flop #(1) BeginReg(clk, StartSampleFirst, BeginDelayed);
|
||||
assign BeginSample = StartSampleFirst & ~BeginDelayed;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
always @(negedge clk) begin
|
||||
if(StartSample) begin
|
||||
for(HPMCindex = 0; HPMCindex < 32; HPMCindex += 1) begin
|
||||
InitialHPMCOUNTERH[HPMCindex] <= dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[HPMCindex];
|
||||
end
|
||||
end
|
||||
if(StartSample) begin
|
||||
for(HPMCindex = 0; HPMCindex < 32; HPMCindex += 1) begin
|
||||
InitialHPMCOUNTERH[HPMCindex] <= dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[HPMCindex];
|
||||
end
|
||||
end
|
||||
if(EndSample) begin
|
||||
for(HPMCindex = 0; HPMCindex < HPMCnames.size(); HPMCindex += 1) begin
|
||||
// unlikely to have more than 10M in any counter.
|
||||
$display("Cnt[%2d] = %7d %s", HPMCindex, dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[HPMCindex] - InitialHPMCOUNTERH[HPMCindex], HPMCnames[HPMCindex]);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -535,58 +536,59 @@ module testbench;
|
|||
if (`BPRED_SUPPORTED) begin
|
||||
integer adrindex;
|
||||
|
||||
always @(*) begin
|
||||
if(reset) begin
|
||||
for(adrindex = 0; adrindex < 2**`BTB_SIZE; adrindex++) begin
|
||||
force dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex] = 0;
|
||||
end
|
||||
for(adrindex = 0; adrindex < 2**`BPRED_SIZE; adrindex++) begin
|
||||
force dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex] = 0;
|
||||
end
|
||||
#1;
|
||||
for(adrindex = 0; adrindex < 2**`BTB_SIZE; adrindex++) begin
|
||||
release dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex];
|
||||
end
|
||||
for(adrindex = 0; adrindex < 2**`BPRED_SIZE; adrindex++) begin
|
||||
release dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
always @(*) begin
|
||||
if(reset) begin
|
||||
for(adrindex = 0; adrindex < 2**`BTB_SIZE; adrindex++) begin
|
||||
force dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex] = 0;
|
||||
end
|
||||
for(adrindex = 0; adrindex < 2**`BPRED_SIZE; adrindex++) begin
|
||||
force dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex] = 0;
|
||||
end
|
||||
#1;
|
||||
for(adrindex = 0; adrindex < 2**`BTB_SIZE; adrindex++) begin
|
||||
release dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex];
|
||||
end
|
||||
for(adrindex = 0; adrindex < 2**`BPRED_SIZE; adrindex++) begin
|
||||
release dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if (`ICACHE_SUPPORTED && `I_CACHE_ADDR_LOGGER) begin : ICacheLogger
|
||||
int file;
|
||||
string LogFile;
|
||||
logic resetD, resetEdge;
|
||||
logic Enable, InvalDelayed;
|
||||
logic Enable;
|
||||
logic InvalDelayed, InvalEdge;
|
||||
|
||||
assign Enable = dut.core.ifu.bus.icache.icache.cachefsm.LRUWriteEn &
|
||||
dut.core.ifu.immu.immu.pmachecker.Cacheable &
|
||||
~dut.core.ifu.bus.icache.icache.cachefsm.FlushStage &
|
||||
~reset;
|
||||
flop #(1) ResetDReg(clk, reset, resetD);
|
||||
assign resetEdge = ~reset & resetD;
|
||||
flop #(1) ResetDReg(clk, reset, resetD);
|
||||
assign resetEdge = ~reset & resetD;
|
||||
|
||||
flop #(1) InvalReg(clk, dut.core.ifu.InvalidateICacheM, InvalDelayed);
|
||||
assign InvalEdge = dut.core.ifu.InvalidateICacheM & ~InvalDelayed;
|
||||
assign InvalEdge = dut.core.ifu.InvalidateICacheM & ~InvalDelayed;
|
||||
|
||||
initial begin
|
||||
LogFile = $psprintf("ICache.log");
|
||||
LogFile = $psprintf("ICache.log");
|
||||
file = $fopen(LogFile, "w");
|
||||
$fwrite(file, "BEGIN %s\n", memfilename);
|
||||
end
|
||||
$fwrite(file, "BEGIN %s\n", memfilename);
|
||||
end
|
||||
string AccessTypeString, HitMissString;
|
||||
assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" :
|
||||
dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M";
|
||||
always @(posedge clk) begin
|
||||
if(resetEdge) $fwrite(file, "TRAIN\n");
|
||||
if(Begin) $fwrite(file, "BEGIN %s\n", memfilename);
|
||||
if(Enable) begin // only log i cache reads
|
||||
$fwrite(file, "%h R %s\n", dut.core.ifu.PCPF, HitMissString);
|
||||
end
|
||||
if(resetEdge) $fwrite(file, "TRAIN\n");
|
||||
if(BeginSample) $fwrite(file, "BEGIN %s\n", memfilename);
|
||||
if(Enable) begin // only log i cache reads
|
||||
$fwrite(file, "%h R %s\n", dut.core.ifu.PCPF, HitMissString);
|
||||
end
|
||||
if(InvalEdge) $fwrite(file, "0 I X\n");
|
||||
if(EndSample) $fwrite(file, "END %s\n", memfilename);
|
||||
if(EndSample) $fwrite(file, "END %s\n", memfilename);
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -615,18 +617,18 @@ end
|
|||
(AccessTypeString != "NULL");
|
||||
|
||||
initial begin
|
||||
LogFile = $psprintf("DCache.log");
|
||||
LogFile = $psprintf("DCache.log");
|
||||
file = $fopen(LogFile, "w");
|
||||
$fwrite(file, "BEGIN %s\n", memfilename);
|
||||
end
|
||||
$fwrite(file, "BEGIN %s\n", memfilename);
|
||||
end
|
||||
always @(posedge clk) begin
|
||||
if(resetEdge) $fwrite(file, "TRAIN\n");
|
||||
if(Begin) $fwrite(file, "BEGIN %s\n", memfilename);
|
||||
if(Enabled) begin
|
||||
$fwrite(file, "%h %s %s\n", dut.core.lsu.PAdrM, AccessTypeString, HitMissString);
|
||||
end
|
||||
if(dut.core.lsu.bus.dcache.dcache.cachefsm.FlushFlag) $fwrite(file, "0 F X\n");
|
||||
if(EndSample) $fwrite(file, "END %s\n", memfilename);
|
||||
if(resetEdge) $fwrite(file, "TRAIN\n");
|
||||
if(BeginSample) $fwrite(file, "BEGIN %s\n", memfilename);
|
||||
if(Enabled) begin
|
||||
$fwrite(file, "%h %s %s\n", dut.core.lsu.PAdrM, AccessTypeString, HitMissString);
|
||||
end
|
||||
if(dut.core.lsu.bus.dcache.dcache.cachefsm.FlushFlag) $fwrite(file, "0 F X\n");
|
||||
if(EndSample) $fwrite(file, "END %s\n", memfilename);
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -634,45 +636,45 @@ end
|
|||
if (`BPRED_LOGGER) begin
|
||||
string direction;
|
||||
int file;
|
||||
logic PCSrcM;
|
||||
string LogFile;
|
||||
logic resetD, resetEdge;
|
||||
flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PCSrcE, PCSrcM);
|
||||
flop #(1) ResetDReg(clk, reset, resetD);
|
||||
assign resetEdge = ~reset & resetD;
|
||||
logic PCSrcM;
|
||||
string LogFile;
|
||||
logic resetD, resetEdge;
|
||||
flopenrc #(1) PCSrcMReg(clk, reset, dut.core.FlushM, ~dut.core.StallM, dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PCSrcE, PCSrcM);
|
||||
flop #(1) ResetDReg(clk, reset, resetD);
|
||||
assign resetEdge = ~reset & resetD;
|
||||
initial begin
|
||||
LogFile = $psprintf("branch_%s%0d.log", `BPRED_TYPE, `BPRED_SIZE);
|
||||
LogFile = $psprintf("branch_%s%0d.log", `BPRED_TYPE, `BPRED_SIZE);
|
||||
file = $fopen(LogFile, "w");
|
||||
end
|
||||
end
|
||||
always @(posedge clk) begin
|
||||
if(resetEdge) $fwrite(file, "TRAIN\n");
|
||||
if(StartSample) $fwrite(file, "BEGIN %s\n", memfilename);
|
||||
if(dut.core.ifu.InstrClassM[0] & ~dut.core.StallW & ~dut.core.FlushW & dut.core.InstrValidM) begin
|
||||
direction = PCSrcM ? "t" : "n";
|
||||
$fwrite(file, "%h %s\n", dut.core.PCM, direction);
|
||||
end
|
||||
if(EndSample) $fwrite(file, "END %s\n", memfilename);
|
||||
end
|
||||
if(resetEdge) $fwrite(file, "TRAIN\n");
|
||||
if(StartSample) $fwrite(file, "BEGIN %s\n", memfilename);
|
||||
if(dut.core.ifu.InstrClassM[0] & ~dut.core.StallW & ~dut.core.FlushW & dut.core.InstrValidM) begin
|
||||
direction = PCSrcM ? "t" : "n";
|
||||
$fwrite(file, "%h %s\n", dut.core.PCM, direction);
|
||||
end
|
||||
if(EndSample) $fwrite(file, "END %s\n", memfilename);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// check for hange up.
|
||||
// check for hang up.
|
||||
logic [`XLEN-1:0] OldPCW;
|
||||
integer WatchDogTimerCount;
|
||||
localparam WatchDogTimerThreshold = 1000000;
|
||||
logic WatchDogTimeOut;
|
||||
integer WatchDogTimerCount;
|
||||
localparam WatchDogTimerThreshold = 1000000;
|
||||
logic WatchDogTimeOut;
|
||||
always_ff @(posedge clk) begin
|
||||
OldPCW <= PCW;
|
||||
if(OldPCW == PCW) WatchDogTimerCount = WatchDogTimerCount + 1'b1;
|
||||
else WatchDogTimerCount = '0;
|
||||
OldPCW <= PCW;
|
||||
if(OldPCW == PCW) WatchDogTimerCount = WatchDogTimerCount + 1'b1;
|
||||
else WatchDogTimerCount = '0;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
WatchDogTimeOut = WatchDogTimerCount >= WatchDogTimerThreshold;
|
||||
if(WatchDogTimeOut) begin
|
||||
$display("FAILURE: Watch Dog Time Out triggered. PCW stuck at %x for more than %d cycles", PCW, WatchDogTimerCount);
|
||||
$stop;
|
||||
end
|
||||
WatchDogTimeOut = WatchDogTimerCount >= WatchDogTimerThreshold;
|
||||
if(WatchDogTimeOut) begin
|
||||
$display("FAILURE: Watch Dog Time Out triggered. PCW stuck at %x for more than %d cycles", PCW, WatchDogTimerCount);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -690,34 +692,34 @@ module DCacheFlushFSM
|
|||
|
||||
logic [`XLEN-1:0] ShadowRAM[`UNCORE_RAM_BASE>>(1+`XLEN/32):(`UNCORE_RAM_RANGE+`UNCORE_RAM_BASE)>>1+(`XLEN/32)];
|
||||
|
||||
if(`DCACHE_SUPPORTED) begin
|
||||
localparam numlines = testbench.dut.core.lsu.bus.dcache.dcache.NUMLINES;
|
||||
localparam numways = testbench.dut.core.lsu.bus.dcache.dcache.NUMWAYS;
|
||||
localparam linebytelen = testbench.dut.core.lsu.bus.dcache.dcache.LINEBYTELEN;
|
||||
localparam linelen = testbench.dut.core.lsu.bus.dcache.dcache.LINELEN;
|
||||
localparam sramlen = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].SRAMLEN;
|
||||
localparam cachesramwords = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].NUMSRAM;
|
||||
localparam numwords = sramlen/`XLEN;
|
||||
localparam lognumlines = $clog2(numlines);
|
||||
localparam loglinebytelen = $clog2(linebytelen);
|
||||
localparam lognumways = $clog2(numways);
|
||||
localparam tagstart = lognumlines + loglinebytelen;
|
||||
if(`DCACHE_SUPPORTED) begin
|
||||
localparam numlines = testbench.dut.core.lsu.bus.dcache.dcache.NUMLINES;
|
||||
localparam numways = testbench.dut.core.lsu.bus.dcache.dcache.NUMWAYS;
|
||||
localparam linebytelen = testbench.dut.core.lsu.bus.dcache.dcache.LINEBYTELEN;
|
||||
localparam linelen = testbench.dut.core.lsu.bus.dcache.dcache.LINELEN;
|
||||
localparam sramlen = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].SRAMLEN;
|
||||
localparam cachesramwords = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].NUMSRAM;
|
||||
localparam numwords = sramlen/`XLEN;
|
||||
localparam lognumlines = $clog2(numlines);
|
||||
localparam loglinebytelen = $clog2(linebytelen);
|
||||
localparam lognumways = $clog2(numways);
|
||||
localparam tagstart = lognumlines + loglinebytelen;
|
||||
|
||||
|
||||
|
||||
genvar index, way, cacheWord;
|
||||
logic [sramlen-1:0] CacheData [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic [sramlen-1:0] cacheline;
|
||||
logic [`XLEN-1:0] CacheTag [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic CacheValid [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic CacheDirty [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic [`PA_BITS-1:0] CacheAdr [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
genvar index, way, cacheWord;
|
||||
logic [sramlen-1:0] CacheData [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic [sramlen-1:0] cacheline;
|
||||
logic [`XLEN-1:0] CacheTag [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic CacheValid [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic CacheDirty [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
logic [`PA_BITS-1:0] CacheAdr [numways-1:0] [numlines-1:0] [cachesramwords-1:0];
|
||||
for(index = 0; index < numlines; index++) begin
|
||||
for(way = 0; way < numways; way++) begin
|
||||
for(cacheWord = 0; cacheWord < cachesramwords; cacheWord++) begin
|
||||
copyShadow #(.tagstart(tagstart),
|
||||
.loglinebytelen(loglinebytelen), .sramlen(sramlen))
|
||||
copyShadow(.clk,
|
||||
for(way = 0; way < numways; way++) begin
|
||||
for(cacheWord = 0; cacheWord < cachesramwords; cacheWord++) begin
|
||||
copyShadow #(.tagstart(tagstart),
|
||||
.loglinebytelen(loglinebytelen), .sramlen(sramlen))
|
||||
copyShadow(.clk,
|
||||
.start,
|
||||
.tag(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].CacheTagMem.RAM[index][`PA_BITS-1-tagstart:0]),
|
||||
.valid(testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[way].ValidBits[index]),
|
||||
|
@ -766,18 +768,18 @@ endmodule
|
|||
|
||||
module copyShadow
|
||||
#(parameter tagstart, loglinebytelen, sramlen)
|
||||
(input logic clk,
|
||||
input logic start,
|
||||
input logic [`PA_BITS-1:tagstart] tag,
|
||||
input logic valid, dirty,
|
||||
input logic [sramlen-1:0] data,
|
||||
input logic [32-1:0] index,
|
||||
input logic [32-1:0] cacheWord,
|
||||
output logic [sramlen-1:0] CacheData,
|
||||
output logic [`PA_BITS-1:0] CacheAdr,
|
||||
output logic [`XLEN-1:0] CacheTag,
|
||||
output logic CacheValid,
|
||||
output logic CacheDirty);
|
||||
(input logic clk,
|
||||
input logic start,
|
||||
input logic [`PA_BITS-1:tagstart] tag,
|
||||
input logic valid, dirty,
|
||||
input logic [sramlen-1:0] data,
|
||||
input logic [32-1:0] index,
|
||||
input logic [32-1:0] cacheWord,
|
||||
output logic [sramlen-1:0] CacheData,
|
||||
output logic [`PA_BITS-1:0] CacheAdr,
|
||||
output logic [`XLEN-1:0] CacheTag,
|
||||
output logic CacheValid,
|
||||
output logic CacheDirty);
|
||||
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
|
@ -806,8 +808,7 @@ task automatic updateProgramAddrLabelArray;
|
|||
integer returncode;
|
||||
returncode = $fscanf(ProgramLabelMapFP, "%s\n", label);
|
||||
returncode = $fscanf(ProgramAddrMapFP, "%s\n", adrstr);
|
||||
if (ProgramAddrLabelArray.exists(label))
|
||||
ProgramAddrLabelArray[label] = adrstr.atohex();
|
||||
if (ProgramAddrLabelArray.exists(label)) ProgramAddrLabelArray[label] = adrstr.atohex();
|
||||
end
|
||||
end
|
||||
$fclose(ProgramLabelMapFP);
|
||||
|
|
|
@ -142,6 +142,65 @@ main:
|
|||
# Test writes to floating point CSRs
|
||||
csrw frm, t0
|
||||
csrw fflags, t0
|
||||
|
||||
# CSRC MCOUNTEREN Register
|
||||
# Go to machine mode
|
||||
li a0, 3
|
||||
ecall
|
||||
# Activate HPM3
|
||||
li t0, -1
|
||||
csrw mcounteren, t0
|
||||
csrw scounteren, t0
|
||||
|
||||
# Go to supervisor
|
||||
li a0, 1
|
||||
ecall
|
||||
#try to write to HPMs
|
||||
csrw 333, t0
|
||||
#go to user mode
|
||||
li a0, 0
|
||||
ecall
|
||||
csrr t0, hpmcounter22
|
||||
|
||||
# setting registers bits to 0
|
||||
li a0, 3 # back to machine mode
|
||||
ecall
|
||||
li t0, 0
|
||||
csrw mcounteren, t0
|
||||
csrw scounteren, t0
|
||||
|
||||
# Write to satp when status.TVM is 1 from machine mode
|
||||
bseti t0, zero, 20
|
||||
csrs mstatus, t0
|
||||
|
||||
csrw satp, t0
|
||||
|
||||
|
||||
|
||||
# Test checking privilege for reading counters (using counter 22 as an example)
|
||||
|
||||
# Go to machine mode
|
||||
li a0, 3
|
||||
ecall
|
||||
|
||||
# Set SCOUNTEREN to all 0s, MCOUNTEREN to all 1s
|
||||
li t0, 0
|
||||
csrw scounteren, t0
|
||||
li t1, -1
|
||||
csrw mcounteren, t1
|
||||
|
||||
# Go to supervisor mode
|
||||
li a0, 1
|
||||
ecall
|
||||
|
||||
# try to read from HPM22
|
||||
csrr t0, hpmcounter22
|
||||
|
||||
# go to user mode
|
||||
li a0, 0
|
||||
ecall
|
||||
|
||||
csrr t0, hpmcounter22
|
||||
|
||||
j done
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue