2021-10-10 22:07:51 +00:00
///////////////////////////////////////////
// testbench.sv
//
// Written: David_Harris@hmc.edu 9 January 2021
// Modified:
//
// Purpose: Wally Testbench and helper modules
// Applies test programs from the riscv-arch-test and Imperas suites
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
2022-01-07 12:58:40 +00:00
// MIT LICENSE
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
2021-10-10 22:07:51 +00:00
//
2022-01-07 12:58:40 +00:00
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
2021-10-10 22:07:51 +00:00
//
2022-01-07 12:58:40 +00:00
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////
2021-10-10 22:07:51 +00:00
`include " wally-config.vh "
`include " tests.vh "
2021-10-23 13:15:26 +00:00
module testbench ;
2021-10-10 22:07:51 +00:00
parameter DEBUG = 0 ;
parameter TEST = " none " ;
logic clk ;
2021-10-25 17:05:41 +00:00
logic reset_ext , reset ;
2021-10-10 22:07:51 +00:00
parameter SIGNATURESIZE = 5000000 ;
int test , i , errors , totalerrors ;
logic [ 31 : 0 ] sig32 [ 0 : SIGNATURESIZE ] ;
logic [ `XLEN - 1 : 0 ] signature [ 0 : SIGNATURESIZE ] ;
logic [ `XLEN - 1 : 0 ] testadr ;
string InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ;
logic [ 31 : 0 ] InstrW ;
string tests [ ] ;
logic [ 3 : 0 ] dummy ;
string ProgramAddrMapFile , ProgramLabelMapFile ;
logic [ `AHBW - 1 : 0 ] HRDATAEXT ;
logic HREADYEXT , HRESPEXT ;
logic [ 31 : 0 ] HADDR ;
logic [ `AHBW - 1 : 0 ] HWDATA ;
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 DCacheFlushDone , DCacheFlushStart ;
2022-01-20 16:02:08 +00:00
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 ) ;
2021-10-10 22:07:51 +00:00
// check assertions for a legal configuration
riscvassertions riscvassertions ( ) ;
// pick tests based on modes supported
initial begin
$display ( " TEST is %s " , TEST ) ;
2021-12-30 00:53:39 +00:00
//tests = '{};
2021-10-10 22:07:51 +00:00
if ( `XLEN = = 64 ) begin // RV64
case ( TEST )
" arch64i " : tests = arch64i ;
" arch64priv " : tests = arch64priv ;
2021-12-30 02:25:46 +00:00
" arch64c " : if ( `C_SUPPORTED )
if ( `ZICSR_SUPPORTED ) tests = { arch64c , arch64cpriv } ;
else tests = { arch64c } ;
2021-10-10 22:07:51 +00:00
" arch64m " : if ( `M_SUPPORTED ) tests = arch64m ;
2021-10-30 05:31:48 +00:00
" arch64d " : if ( `D_SUPPORTED ) tests = arch64d ;
2021-10-10 22:07:51 +00:00
" imperas64i " : tests = imperas64i ;
2022-02-03 01:08:34 +00:00
// "imperas64mmu": if (`VIRTMEM_SUPPORTED) tests = imperas64mmu;
2021-10-10 22:07:51 +00:00
" imperas64f " : if ( `F_SUPPORTED ) tests = imperas64f ;
" imperas64d " : if ( `D_SUPPORTED ) tests = imperas64d ;
" imperas64m " : if ( `M_SUPPORTED ) tests = imperas64m ;
2022-03-02 07:09:37 +00:00
" wally64a " : if ( `A_SUPPORTED ) tests = wally64a ;
2021-10-10 22:07:51 +00:00
" imperas64c " : if ( `C_SUPPORTED ) tests = imperas64c ;
else tests = imperas64iNOc ;
" testsBP64 " : tests = testsBP64 ;
2021-12-29 00:28:51 +00:00
" wally64i " : tests = wally64i ; // *** redo
" wally64priv " : tests = wally64priv ; // *** redo
2022-02-22 03:46:08 +00:00
" wally64periph " : tests = wally64periph ;
2022-02-01 23:00:11 +00:00
" coremark " : tests = coremark ;
2021-10-10 22:07:51 +00:00
endcase
end else begin // RV32
case ( TEST )
" arch32i " : tests = arch32i ;
" arch32priv " : tests = arch32priv ;
2021-12-30 02:25:46 +00:00
" arch32c " : if ( `C_SUPPORTED )
if ( `ZICSR_SUPPORTED ) tests = { arch32c , arch32cpriv } ;
else tests = { arch32c } ;
2021-10-10 22:07:51 +00:00
" arch32m " : if ( `M_SUPPORTED ) tests = arch32m ;
2021-10-27 17:37:35 +00:00
" arch32f " : if ( `F_SUPPORTED ) tests = arch32f ;
2021-10-10 22:07:51 +00:00
" imperas32i " : tests = imperas32i ;
" imperas32p " : tests = imperas32p ;
2022-02-03 01:08:34 +00:00
// "imperas32mmu": if (`VIRTMEM_SUPPORTED) tests = imperas32mmu;
2021-10-10 22:07:51 +00:00
" imperas32f " : if ( `F_SUPPORTED ) tests = imperas32f ;
" imperas32m " : if ( `M_SUPPORTED ) tests = imperas32m ;
" imperas32a " : if ( `A_SUPPORTED ) tests = imperas32a ;
" imperas32c " : if ( `C_SUPPORTED ) tests = imperas32c ;
else tests = imperas32iNOc ;
2021-12-29 00:28:51 +00:00
" wally32i " : tests = wally32i ; // *** redo
2022-02-05 04:16:18 +00:00
" wally32e " : tests = wally32e ;
2021-12-29 00:28:51 +00:00
" wally32priv " : tests = wally32priv ; // *** redo
2021-10-10 22:07:51 +00:00
endcase
end
2021-12-29 00:28:51 +00:00
if ( tests . size ( ) = = 0 ) begin
2021-10-10 22:07:51 +00:00
$display ( " TEST %s not supported in this configuration " , TEST ) ;
$stop ;
end
end
string signame , memfilename , pathname ;
logic [ 31 : 0 ] GPIOPinsIn , GPIOPinsOut , GPIOPinsEn ;
logic UARTSin , UARTSout ;
2021-12-02 23:47:46 +00:00
logic SDCCLK ;
logic SDCCmdIn ;
logic SDCCmdOut ;
logic SDCCmdOE ;
logic [ 3 : 0 ] SDCDatIn ;
logic HREADY ;
logic HSELEXT ;
2021-10-10 22:07:51 +00:00
// instantiate device to be tested
assign GPIOPinsIn = 0 ;
assign UARTSin = 1 ;
assign HREADYEXT = 1 ;
assign HRESPEXT = 0 ;
assign HRDATAEXT = 0 ;
2021-12-14 21:43:06 +00:00
wallypipelinedsoc dut ( . clk , . reset_ext , . reset , . HRDATAEXT , . HREADYEXT , . HRESPEXT , . HSELEXT ,
2021-12-13 01:53:26 +00:00
. HCLK , . HRESETn , . HADDR , . HWDATA , . HWRITE , . HSIZE , . HBURST , . HPROT ,
2022-01-02 21:18:16 +00:00
. HTRANS , . HMASTLOCK , . HREADY , . TIMECLK ( 1 'b0 ) , . GPIOPinsIn , . GPIOPinsOut , . GPIOPinsEn ,
2021-12-13 01:53:26 +00:00
. UARTSin , . UARTSout , . SDCCmdIn , . SDCCmdOut , . SDCCmdOE , . SDCDatIn , . SDCCLK ) ;
2021-10-10 22:07:51 +00:00
// Track names of instructions
2022-01-20 16:02:08 +00:00
instrTrackerTB it ( clk , reset , dut . core . ieu . dp . FlushE ,
2022-02-01 23:00:11 +00:00
dut . core . ifu . FinalInstrRawF [ 31 : 0 ] ,
2022-01-20 16:02:08 +00:00
dut . core . ifu . InstrD , dut . core . ifu . InstrE ,
dut . core . ifu . InstrM , InstrW ,
2021-10-10 22:07:51 +00:00
InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ) ;
// initialize tests
2021-12-14 21:43:06 +00:00
localparam integer MemStartAddr = `RAM_BASE > > ( 1 + `XLEN / 32 ) ;
localparam integer MemEndAddr = ( `RAM_RANGE + `RAM_BASE ) > > 1 + ( `XLEN / 32 ) ;
2021-10-10 22:07:51 +00:00
initial
begin
test = 1 ;
totalerrors = 0 ;
testadr = 0 ;
// 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
// the design.
2022-02-08 12:18:13 +00:00
if ( TEST = = " coremark " )
for ( i = MemStartAddr ; i < MemEndAddr ; i = i + 1 )
dut . uncore . ram . ram . RAM [ i ] = 64 'h0 ;
2021-10-10 22:07:51 +00:00
// read test vectors into memory
2021-11-01 15:48:46 +00:00
pathname = tvpaths [ tests [ 0 ] . atoi ( ) ] ;
/ * if ( tests [ 0 ] = = `IMPERASTEST )
2021-10-10 22:07:51 +00:00
pathname = tvpaths [ 0 ] ;
2021-11-01 15:48:46 +00:00
else pathname = tvpaths [ 1 ] ; */
2021-10-10 22:07:51 +00:00
memfilename = { pathname , tests [ test ] , " .elf.memfile " } ;
2022-02-08 12:18:13 +00:00
if ( `IMEM = = `MEM_TIM ) $readmemh ( memfilename , dut . core . ifu . irom . irom . ram . RAM ) ;
else $readmemh ( memfilename , dut . uncore . ram . ram . RAM ) ;
2022-02-08 15:24:37 +00:00
if ( `DMEM = = `MEM_TIM ) $readmemh ( memfilename , dut . core . lsu . dtim . dtim . ram . RAM ) ;
2022-02-08 12:18:13 +00:00
2021-10-10 22:07:51 +00:00
ProgramAddrMapFile = { pathname , tests [ test ] , " .elf.objdump.addr " } ;
ProgramLabelMapFile = { pathname , tests [ test ] , " .elf.objdump.lab " } ;
$display ( " Read memfile %s " , memfilename ) ;
2021-10-25 17:05:41 +00:00
reset_ext = 1 ; # 42 ; reset_ext = 0 ;
2021-10-10 22:07:51 +00:00
end
// generate clock to sequence tests
always
begin
clk = 1 ; # 5 ; clk = 0 ; # 5 ;
2022-01-07 17:02:16 +00:00
// if ($time % 100000 == 0) $display("Time is %0t", $time);
2021-10-10 22:07:51 +00:00
end
// check results
always @ ( negedge clk )
begin
2022-02-04 14:30:36 +00:00
if ( TEST = = " coremark " )
if ( dut . core . priv . priv . ecallM ) begin
$display ( " Benchmark: coremark is done. " ) ;
$stop ;
end
2021-10-10 22:07:51 +00:00
if ( DCacheFlushDone ) begin
# 600 ; // give time for instructions in pipeline to finish
// clear signature to prevent contamination from previous tests
for ( i = 0 ; i < SIGNATURESIZE ; i = i + 1 ) begin
sig32 [ i ] = ' bx ;
end
// read signature, reformat in 64 bits if necessary
signame = { pathname , tests [ test ] , " .signature.output " } ;
$readmemh ( signame , sig32 ) ;
i = 0 ;
while ( i < SIGNATURESIZE ) begin
if ( `XLEN = = 32 ) begin
signature [ i ] = sig32 [ i ] ;
i = i + 1 ;
end else begin
signature [ i / 2 ] = { sig32 [ i + 1 ] , sig32 [ i ] } ;
i = i + 2 ;
end
2022-02-08 12:18:13 +00:00
if ( i > = 4 & sig32 [ i - 4 ] = = = ' bx ) begin
if ( i = = 4 ) begin
2021-10-10 22:07:51 +00:00
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
end
// Check errors
errors = ( i = = SIGNATURESIZE + 1 ) ; // error if file is empty
i = 0 ;
2021-12-14 21:43:06 +00:00
testadr = ( `RAM_BASE + tests [ test + 1 ] . atohex ( ) ) / ( `XLEN / 8 ) ;
2021-10-10 22:07:51 +00:00
/* verilator lint_off INFINITELOOP */
while ( signature [ i ] ! = = ' bx ) begin
2022-02-08 12:18:13 +00:00
logic [ `XLEN - 1 : 0 ] sig ;
if ( `DMEM = = `MEM_TIM ) sig = dut . core . lsu . dtim . dtim . ram . RAM [ testadr + i ] ;
else sig = dut . uncore . ram . ram . RAM [ testadr + i ] ;
// $display("signature[%h] = %h sig = %h", i, signature[i], sig);
if ( signature [ i ] ! = = sig &
2022-01-20 16:02:08 +00:00
//if (signature[i] !== dut.core.lsu.dtim.ram.RAM[testadr+i] &
2022-02-08 12:18:13 +00:00
( signature [ i ] ! = = DCacheFlushFSM . ShadowRAM [ testadr + i ] ) ) begin // ***i+1?
2022-02-08 12:40:02 +00:00
if ( ( signature [ i ] ! = = '0 | signature [ i + 4 ] ! = = 'x ) ) begin
2022-02-08 12:18:13 +00:00
// if (signature[i+4] !== 'bx | (signature[i] !== 32'hFFFFFFFF & signature[i] !== 32'h00000000)) begin
2021-10-10 22:07:51 +00:00
// report errors unless they are garbage at the end of the sim
// kind of hacky test for garbage right now
2022-02-08 12:18:13 +00:00
$display ( " sig4 = %h ne %b " , signature [ i + 4 ] , signature [ i + 4 ] ! = = ' bx ) ;
2021-10-10 22:07:51 +00:00
errors = errors + 1 ;
2022-02-08 12:18:13 +00:00
$display ( " Error on test %s result %d: adr = %h sim (D$) %h sim (DMEM) = %h, signature = %h " ,
tests [ test ] , i , ( testadr + i ) * ( `XLEN / 8 ) , DCacheFlushFSM . ShadowRAM [ testadr + i ] , sig , signature [ i ] ) ;
2022-01-20 16:02:08 +00:00
// tests[test], i, (testadr+i)*(`XLEN/8), DCacheFlushFSM.ShadowRAM[testadr+i], dut.core.lsu.dtim.ram.RAM[testadr+i], signature[i]);
2021-10-10 22:07:51 +00:00
$stop ; //***debug
end
end
i = i + 1 ;
end
/* verilator lint_on INFINITELOOP */
if ( errors = = 0 ) begin
$display ( " %s succeeded. Brilliant!!! " , tests [ test ] ) ;
end
else begin
$display ( " %s failed with %d errors. :( " , tests [ test ] , errors ) ;
totalerrors = totalerrors + 1 ;
end
test = test + 2 ;
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
//pathname = tvpaths[tests[0]];
memfilename = { pathname , tests [ test ] , " .elf.memfile " } ;
2022-02-08 12:18:13 +00:00
//$readmemh(memfilename, dut.uncore.ram.ram.RAM);
if ( `IMEM = = `MEM_TIM ) $readmemh ( memfilename , dut . core . ifu . irom . irom . ram . RAM ) ;
else $readmemh ( memfilename , dut . uncore . ram . ram . RAM ) ;
2022-02-08 15:24:37 +00:00
if ( `DMEM = = `MEM_TIM ) $readmemh ( memfilename , dut . core . lsu . dtim . dtim . ram . RAM ) ;
2022-02-08 12:18:13 +00:00
2021-10-10 22:07:51 +00:00
ProgramAddrMapFile = { pathname , tests [ test ] , " .elf.objdump.addr " } ;
ProgramLabelMapFile = { pathname , tests [ test ] , " .elf.objdump.lab " } ;
$display ( " Read memfile %s " , memfilename ) ;
2021-10-25 17:05:41 +00:00
reset_ext = 1 ; # 47 ; reset_ext = 0 ;
2021-10-10 22:07:51 +00:00
end
end
end // always @ (negedge clk)
// track the current function or global label
if ( DEBUG = = 1 ) begin : FunctionName
FunctionName FunctionName ( . reset ( reset ) ,
. clk ( clk ) ,
. ProgramAddrMapFile ( ProgramAddrMapFile ) ,
. ProgramLabelMapFile ( ProgramLabelMapFile ) ) ;
end
// Termination condition
2022-01-07 17:02:16 +00:00
// terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed
2021-12-25 22:39:51 +00:00
// or sw gp,-56(t0) for new Imperas tests
2022-01-07 17:02:16 +00:00
// or sd gp, -56(t0)
2021-12-25 22:39:51 +00:00
// or on a jump to self infinite loop (6f) for RISC-V Arch tests
2021-12-30 00:53:39 +00:00
logic ecf ; // remove this once we don't rely on old Imperas tests with Ecalls
2022-01-20 16:02:08 +00:00
if ( `ZICSR_SUPPORTED ) assign ecf = dut . core . priv . priv . EcallFaultM ;
2022-01-05 16:41:17 +00:00
else assign ecf = 0 ;
2022-01-02 21:47:21 +00:00
assign DCacheFlushStart = ecf &
2022-01-20 16:02:08 +00:00
( dut . core . ieu . dp . regf . rf [ 3 ] = = 1 |
( dut . core . ieu . dp . regf . we3 &
dut . core . ieu . dp . regf . a3 = = 3 &
dut . core . ieu . dp . regf . wd3 = = 1 ) ) |
( dut . core . ifu . InstrM = = 32 'h6f | dut . core . ifu . InstrM = = 32 'hfc32a423 | dut . core . ifu . InstrM = = 32 'hfc32a823 ) & dut . core . ieu . c . InstrValidM ;
2021-12-30 04:24:37 +00:00
2021-10-10 22:07:51 +00:00
DCacheFlushFSM DCacheFlushFSM ( . clk ( clk ) ,
2021-12-30 04:24:37 +00:00
. reset ( reset ) ,
. start ( DCacheFlushStart ) ,
. done ( DCacheFlushDone ) ) ;
2021-10-10 22:07:51 +00:00
2022-01-05 16:41:17 +00:00
// initialize the branch predictor
if ( `BPRED_ENABLED = = 1 )
initial begin
2022-01-20 16:02:08 +00:00
$readmemb ( `TWO_BIT_PRELOAD , dut . core . ifu . bpred . bpred . Predictor . DirPredictor . PHT . mem ) ;
$readmemb ( `BTB_PRELOAD , dut . core . ifu . bpred . bpred . TargetPredictor . memory . mem ) ;
2022-01-05 16:41:17 +00:00
end
2021-10-10 22:07:51 +00:00
endmodule
2021-10-23 13:15:26 +00:00
module riscvassertions ;
2021-10-10 22:07:51 +00:00
initial begin
2022-01-02 21:47:21 +00:00
assert ( `PMP_ENTRIES = = 0 | `PMP_ENTRIES = = 16 | `PMP_ENTRIES = = 64 ) else $error ( " Illegal number of PMP entries: PMP_ENTRIES must be 0, 16, or 64 " ) ;
2022-02-03 01:08:34 +00:00
assert ( `S_SUPPORTED | `VIRTMEM_SUPPORTED = = 0 ) else $error ( " Virtual memory requires S mode support " ) ;
2022-01-02 21:47:21 +00:00
assert ( `DIV_BITSPERCYCLE = = 1 | `DIV_BITSPERCYCLE = = 2 | `DIV_BITSPERCYCLE = = 4 ) else $error ( " Illegal number of divider bits/cycle: DIV_BITSPERCYCLE must be 1, 2, or 4 " ) ;
assert ( `F_SUPPORTED | ~ `D_SUPPORTED ) else $error ( " Can't support double (D) without supporting float (F) " ) ;
2022-01-17 14:01:01 +00:00
assert ( `I_SUPPORTED ^ `E_SUPPORTED ) else $error ( " Exactly one of I and E must be supported " ) ;
2022-01-02 21:47:21 +00:00
assert ( `XLEN = = 64 | ~ `D_SUPPORTED ) else $error ( " Wally does not yet support D extensions on RV32 " ) ;
2022-02-03 01:08:34 +00:00
assert ( `DCACHE_WAYSIZEINBYTES < = 4096 | ( `DMEM ! = `MEM_CACHE ) | `VIRTMEM_SUPPORTED = = 0 ) else $error ( " DCACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing) " ) ;
2022-02-03 00:41:09 +00:00
assert ( `DCACHE_LINELENINBITS > = 128 | ( `DMEM ! = `MEM_CACHE ) ) else $error ( " DCACHE_LINELENINBITS must be at least 128 when caches are enabled " ) ;
2022-01-05 04:08:18 +00:00
assert ( `DCACHE_LINELENINBITS < `DCACHE_WAYSIZEINBYTES * 8 ) else $error ( " DCACHE_LINELENINBITS must be smaller than way size " ) ;
2022-02-03 01:08:34 +00:00
assert ( `ICACHE_WAYSIZEINBYTES < = 4096 | ( `IMEM ! = `MEM_CACHE ) | `VIRTMEM_SUPPORTED = = 0 ) else $error ( " ICACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing) " ) ;
2022-02-03 00:41:09 +00:00
assert ( `ICACHE_LINELENINBITS > = 32 | ( `IMEM ! = `MEM_CACHE ) ) else $error ( " ICACHE_LINELENINBITS must be at least 32 when caches are enabled " ) ;
2022-01-05 04:08:18 +00:00
assert ( `ICACHE_LINELENINBITS < `ICACHE_WAYSIZEINBYTES * 8 ) else $error ( " ICACHE_LINELENINBITS must be smaller than way size " ) ;
2022-02-03 00:41:09 +00:00
assert ( 2 * * $clog2 ( `DCACHE_LINELENINBITS ) = = `DCACHE_LINELENINBITS | ( `DMEM ! = `MEM_CACHE ) ) else $error ( " DCACHE_LINELENINBITS must be a power of 2 " ) ;
assert ( 2 * * $clog2 ( `DCACHE_WAYSIZEINBYTES ) = = `DCACHE_WAYSIZEINBYTES | ( `DMEM ! = `MEM_CACHE ) ) else $error ( " DCACHE_WAYSIZEINBYTES must be a power of 2 " ) ;
assert ( 2 * * $clog2 ( `ICACHE_LINELENINBITS ) = = `ICACHE_LINELENINBITS | ( `IMEM ! = `MEM_CACHE ) ) else $error ( " ICACHE_LINELENINBITS must be a power of 2 " ) ;
assert ( 2 * * $clog2 ( `ICACHE_WAYSIZEINBYTES ) = = `ICACHE_WAYSIZEINBYTES | ( `IMEM ! = `MEM_CACHE ) ) else $error ( " ICACHE_WAYSIZEINBYTES must be a power of 2 " ) ;
2022-02-03 01:08:34 +00:00
assert ( 2 * * $clog2 ( `ITLB_ENTRIES ) = = `ITLB_ENTRIES | `VIRTMEM_SUPPORTED = = 0 ) else $error ( " ITLB_ENTRIES must be a power of 2 " ) ;
assert ( 2 * * $clog2 ( `DTLB_ENTRIES ) = = `DTLB_ENTRIES | `VIRTMEM_SUPPORTED = = 0 ) else $error ( " DTLB_ENTRIES must be a power of 2 " ) ;
2021-12-14 21:43:06 +00:00
assert ( `RAM_RANGE > = 56 'h07FFFFFF ) else $warning ( " Some regression tests will fail if RAM_RANGE is less than 56'h07FFFFFF " ) ;
2022-02-03 01:08:34 +00:00
assert ( `ZICSR_SUPPORTED = = 1 | ( `PMP_ENTRIES = = 0 & `VIRTMEM_SUPPORTED = = 0 ) ) else $error ( " PMP_ENTRIES and VIRTMEM_SUPPORTED must be zero if ZICSR not supported. " ) ;
2022-01-02 21:47:21 +00:00
assert ( `ZICSR_SUPPORTED = = 1 | ( `S_SUPPORTED = = 0 & `U_SUPPORTED = = 0 ) ) else $error ( " S and U modes not supported if ZISR not supported " ) ;
assert ( `U_SUPPORTED | ( `S_SUPPORTED = = 0 ) ) else $error ( " S mode only supported if U also is supported " ) ;
2022-02-03 00:41:09 +00:00
// assert (`MEM_DCACHE == 0 | `MEM_DTIM == 0) else $error("Can't simultaneously have a data cache and TIM");
2022-02-03 01:08:34 +00:00
assert ( `DMEM = = `MEM_CACHE | `VIRTMEM_SUPPORTED = = 0 ) else $error ( " Virtual memory needs dcache " ) ;
assert ( `IMEM = = `MEM_CACHE | `VIRTMEM_SUPPORTED = = 0 ) else $error ( " Virtual memory needs icache " ) ;
2021-10-10 22:07:51 +00:00
end
endmodule
/* verilator lint_on STMTDLY */
/* verilator lint_on WIDTH */
module DCacheFlushFSM
( input logic clk ,
input logic reset ,
input logic start ,
output logic done ) ;
genvar adr ;
2021-12-14 21:43:06 +00:00
logic [ `XLEN - 1 : 0 ] ShadowRAM [ `RAM_BASE > > ( 1 + `XLEN / 32 ) : ( `RAM_RANGE + `RAM_BASE ) > > 1 + ( `XLEN / 32 ) ] ;
2021-10-10 22:07:51 +00:00
2022-02-03 00:41:09 +00:00
if ( `DMEM = = `MEM_CACHE ) begin
2022-01-20 16:02:08 +00:00
localparam integer numlines = testbench . dut . core . lsu . bus . dcache . dcache . NUMLINES ;
localparam integer numways = testbench . dut . core . lsu . bus . dcache . dcache . NUMWAYS ;
localparam integer linebytelen = testbench . dut . core . lsu . bus . dcache . dcache . LINEBYTELEN ;
localparam integer numwords = testbench . dut . core . lsu . bus . dcache . dcache . LINELEN / `XLEN ;
2021-12-30 21:26:32 +00:00
localparam integer lognumlines = $clog2 ( numlines ) ;
2022-01-05 04:08:18 +00:00
localparam integer loglinebytelen = $clog2 ( linebytelen ) ;
2021-12-30 21:26:32 +00:00
localparam integer lognumways = $clog2 ( numways ) ;
2022-01-05 04:08:18 +00:00
localparam integer tagstart = lognumlines + loglinebytelen ;
2021-12-30 21:26:32 +00:00
genvar index , way , cacheWord ;
logic [ `XLEN - 1 : 0 ] CacheData [ numways - 1 : 0 ] [ numlines - 1 : 0 ] [ numwords - 1 : 0 ] ;
logic [ `XLEN - 1 : 0 ] CacheTag [ numways - 1 : 0 ] [ numlines - 1 : 0 ] [ numwords - 1 : 0 ] ;
logic CacheValid [ numways - 1 : 0 ] [ numlines - 1 : 0 ] [ numwords - 1 : 0 ] ;
logic CacheDirty [ numways - 1 : 0 ] [ numlines - 1 : 0 ] [ numwords - 1 : 0 ] ;
logic [ `PA_BITS - 1 : 0 ] CacheAdr [ numways - 1 : 0 ] [ numlines - 1 : 0 ] [ numwords - 1 : 0 ] ;
for ( index = 0 ; index < numlines ; index + + ) begin
for ( way = 0 ; way < numways ; way + + ) begin
for ( cacheWord = 0 ; cacheWord < numwords ; cacheWord + + ) begin
copyShadow # ( . tagstart ( tagstart ) ,
2022-01-05 04:08:18 +00:00
. loglinebytelen ( loglinebytelen ) )
2021-12-30 21:26:32 +00:00
copyShadow ( . clk ,
. start ,
2022-02-03 15:36:11 +00:00
. tag ( testbench . dut . core . lsu . bus . dcache . dcache . CacheWays [ way ] . CacheTagMem . StoredData [ index ] ) ,
. valid ( testbench . dut . core . lsu . bus . dcache . dcache . CacheWays [ way ] . ValidBits [ index ] ) ,
. dirty ( testbench . dut . core . lsu . bus . dcache . dcache . CacheWays [ way ] . DirtyBits [ index ] ) ,
. data ( testbench . dut . core . lsu . bus . dcache . dcache . CacheWays [ way ] . word [ cacheWord ] . CacheDataMem . StoredData [ index ] ) ,
2021-12-30 21:26:32 +00:00
. index ( index ) ,
. cacheWord ( cacheWord ) ,
. CacheData ( CacheData [ way ] [ index ] [ cacheWord ] ) ,
. CacheAdr ( CacheAdr [ way ] [ index ] [ cacheWord ] ) ,
. CacheTag ( CacheTag [ way ] [ index ] [ cacheWord ] ) ,
. CacheValid ( CacheValid [ way ] [ index ] [ cacheWord ] ) ,
. CacheDirty ( CacheDirty [ way ] [ index ] [ cacheWord ] ) ) ;
end
end
2021-10-10 22:07:51 +00:00
end
2021-12-30 21:26:32 +00:00
integer i , j , k ;
always @ ( posedge clk ) begin
if ( start ) begin # 1
# 1
for ( i = 0 ; i < numlines ; i + + ) begin
for ( j = 0 ; j < numways ; j + + ) begin
for ( k = 0 ; k < numwords ; k + + ) begin
2022-01-02 21:47:21 +00:00
if ( CacheValid [ j ] [ i ] [ k ] & CacheDirty [ j ] [ i ] [ k ] ) begin
2021-12-30 21:26:32 +00:00
ShadowRAM [ CacheAdr [ j ] [ i ] [ k ] > > $clog2 ( `XLEN / 8 ) ] = CacheData [ j ] [ i ] [ k ] ;
end
end
end
end
end
end
2021-10-10 22:07:51 +00:00
end
2022-01-05 16:41:17 +00:00
flop # ( 1 ) doneReg ( . clk , . d ( start ) , . q ( done ) ) ;
2021-10-10 22:07:51 +00:00
endmodule
module copyShadow
2022-01-05 04:08:18 +00:00
# ( parameter tagstart , loglinebytelen )
2021-10-10 22:07:51 +00:00
( input logic clk ,
input logic start ,
input logic [ `PA_BITS - 1 : tagstart ] tag ,
input logic valid , dirty ,
input logic [ `XLEN - 1 : 0 ] data ,
input logic [ 32 - 1 : 0 ] index ,
input logic [ 32 - 1 : 0 ] cacheWord ,
output logic [ `XLEN - 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
if ( start ) begin
CacheTag = tag ;
CacheValid = valid ;
CacheDirty = dirty ;
CacheData = data ;
2022-01-05 04:08:18 +00:00
CacheAdr = ( tag < < tagstart ) + ( index < < loglinebytelen ) + ( cacheWord < < $clog2 ( `XLEN / 8 ) ) ;
2021-10-10 22:07:51 +00:00
end
end
endmodule