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
//
2023-02-04 16:19:20 +00:00
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
2021-10-10 22:07:51 +00:00
//
2023-02-04 16:19:20 +00:00
// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
// except in compliance with the License, or, at your option, the Apache License version 2.0. You
// may obtain a copy of the License at
2021-10-10 22:07:51 +00:00
//
2023-02-04 16:19:20 +00:00
// https://solderpad.org/licenses/SHL-2.1/
//
// Unless required by applicable law or agreed to in writing, any work distributed under the
// License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
2022-01-07 12:58:40 +00:00
////////////////////////////////////////////////////////////////////////////////////////////////
2021-10-10 22:07:51 +00:00
2023-05-31 21:51:00 +00:00
`include " config.vh "
2021-10-10 22:07:51 +00:00
`include " tests.vh "
2023-07-18 20:07:10 +00:00
`include " BranchPredictorType.vh "
2021-10-10 22:07:51 +00:00
2023-06-12 16:00:30 +00:00
import cvw::* ;
2023-01-06 00:00:11 +00:00
2021-10-23 13:15:26 +00:00
module testbench ;
2023-05-31 21:51:00 +00:00
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off WIDTHEXPAND */
2021-10-10 22:07:51 +00:00
parameter DEBUG = 0 ;
parameter TEST = " none " ;
2023-11-13 20:12:27 +00:00
parameter PrintHPMCounters = 0 ;
2023-11-17 17:21:25 +00:00
parameter BPRED_LOGGER = 1 ;
2023-11-13 20:12:27 +00:00
parameter I_CACHE_ADDR_LOGGER = 0 ;
parameter D_CACHE_ADDR_LOGGER = 0 ;
2021-10-10 22:07:51 +00:00
2023-06-12 16:00:30 +00:00
`include " parameter-defs.vh "
2021-10-10 22:07:51 +00:00
logic clk ;
2021-10-25 17:05:41 +00:00
logic reset_ext , reset ;
2023-06-12 19:06:17 +00:00
logic ResetMem ;
2021-10-10 22:07:51 +00:00
2023-06-14 21:35:55 +00:00
// DUT signals
2023-06-12 16:00:30 +00:00
logic [ P . AHBW - 1 : 0 ] HRDATAEXT ;
2023-06-14 21:35:55 +00:00
logic HREADYEXT , HRESPEXT ;
2023-07-21 22:43:45 +00:00
logic HSELEXTSDC ;
2023-06-12 16:00:30 +00:00
logic [ P . PA_BITS - 1 : 0 ] HADDR ;
logic [ P . AHBW - 1 : 0 ] HWDATA ;
logic [ P . XLEN / 8 - 1 : 0 ] HWSTRB ;
2023-06-14 21:35:55 +00:00
logic HWRITE ;
logic [ 2 : 0 ] HSIZE ;
logic [ 2 : 0 ] HBURST ;
logic [ 3 : 0 ] HPROT ;
logic [ 1 : 0 ] HTRANS ;
logic HMASTLOCK ;
logic HCLK , HRESETn ;
2021-10-10 22:07:51 +00:00
2023-06-14 21:35:55 +00:00
logic [ 31 : 0 ] GPIOIN , GPIOOUT , GPIOEN ;
logic UARTSin , UARTSout ;
2023-11-01 17:14:15 +00:00
logic SPIIn , SPIOut ;
logic [ 3 : 0 ] SPICS ;
2023-07-21 22:43:45 +00:00
logic SDCIntr ;
2021-10-10 22:07:51 +00:00
2023-06-14 21:35:55 +00:00
logic HREADY ;
logic HSELEXT ;
2023-05-31 21:51:00 +00:00
2023-06-14 21:35:55 +00:00
2023-04-14 02:06:09 +00:00
string ProgramAddrMapFile , ProgramLabelMapFile ;
2023-06-13 20:09:40 +00:00
integer ProgramAddrLabelArray [ string ] ;
2023-04-14 02:06:09 +00:00
2023-06-14 21:35:55 +00:00
int test , i , errors , totalerrors ;
string outputfile ;
integer outputFilePointer ;
2023-04-14 02:06:09 +00:00
2023-06-14 21:35:55 +00:00
string tests [ ] ;
2023-04-14 02:06:09 +00:00
logic DCacheFlushDone , DCacheFlushStart ;
2022-06-29 19:23:40 +00:00
logic riscofTest ;
2023-06-14 17:11:55 +00:00
logic Validate ;
logic SelectTest ;
2023-12-20 18:25:34 +00:00
logic TestComplete ;
2021-10-10 22:07:51 +00:00
// pick tests based on modes supported
initial begin
$display ( " TEST is %s " , TEST ) ;
2021-12-30 00:53:39 +00:00
//tests = '{};
2023-06-12 16:00:30 +00:00
if ( P . XLEN = = 64 ) begin // RV64
2021-10-10 22:07:51 +00:00
case ( TEST )
2023-04-14 02:18:26 +00:00
" arch64i " : tests = arch64i ;
" arch64priv " : tests = arch64priv ;
2023-06-12 16:00:30 +00:00
" arch64c " : if ( P . C_SUPPORTED )
if ( P . ZICSR_SUPPORTED ) tests = { arch64c , arch64cpriv } ;
2023-04-14 02:18:26 +00:00
else tests = { arch64c } ;
2023-06-12 16:00:30 +00:00
" arch64m " : if ( P . M_SUPPORTED ) tests = arch64m ;
2023-10-16 17:25:45 +00:00
" arch64a " : if ( P . A_SUPPORTED ) tests = arch64a ;
2023-06-12 16:00:30 +00:00
" arch64f " : if ( P . F_SUPPORTED ) tests = arch64f ;
" arch64d " : if ( P . D_SUPPORTED ) tests = arch64d ;
" arch64f_fma " : if ( P . F_SUPPORTED ) tests = arch64f_fma ;
" arch64d_fma " : if ( P . D_SUPPORTED ) tests = arch64d_fma ;
" arch64zi " : if ( P . ZIFENCEI_SUPPORTED ) tests = arch64zi ;
2023-04-14 02:18:26 +00:00
" imperas64i " : tests = imperas64i ;
2023-06-12 16:00:30 +00:00
" imperas64f " : if ( P . F_SUPPORTED ) tests = imperas64f ;
" imperas64d " : if ( P . D_SUPPORTED ) tests = imperas64d ;
" imperas64m " : if ( P . M_SUPPORTED ) tests = imperas64m ;
" wally64a " : if ( P . A_SUPPORTED ) tests = wally64a ;
" imperas64c " : if ( P . C_SUPPORTED ) tests = imperas64c ;
2023-04-14 02:18:26 +00:00
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 ;
2023-06-12 16:00:30 +00:00
" arch64zba " : if ( P . ZBA_SUPPORTED ) tests = arch64zba ;
" arch64zbb " : if ( P . ZBB_SUPPORTED ) tests = arch64zbb ;
" arch64zbc " : if ( P . ZBC_SUPPORTED ) tests = arch64zbc ;
" arch64zbs " : if ( P . ZBS_SUPPORTED ) tests = arch64zbs ;
2021-10-10 22:07:51 +00:00
endcase
end else begin // RV32
case ( TEST )
2023-04-14 02:18:26 +00:00
" arch32i " : tests = arch32i ;
" arch32priv " : tests = arch32priv ;
2023-06-12 16:00:30 +00:00
" arch32c " : if ( P . C_SUPPORTED )
if ( P . ZICSR_SUPPORTED ) tests = { arch32c , arch32cpriv } ;
2023-04-14 02:18:26 +00:00
else tests = { arch32c } ;
2023-06-12 16:00:30 +00:00
" arch32m " : if ( P . M_SUPPORTED ) tests = arch32m ;
2023-10-16 17:25:45 +00:00
" arch32a " : if ( P . A_SUPPORTED ) tests = arch32a ;
2023-06-12 16:00:30 +00:00
" arch32f " : if ( P . F_SUPPORTED ) tests = arch32f ;
" arch32d " : if ( P . D_SUPPORTED ) tests = arch32d ;
" arch32f_fma " : if ( P . F_SUPPORTED ) tests = arch32f_fma ;
" arch32d_fma " : if ( P . D_SUPPORTED ) tests = arch32d_fma ;
" arch32zi " : if ( P . ZIFENCEI_SUPPORTED ) tests = arch32zi ;
2023-04-14 02:18:26 +00:00
" imperas32i " : tests = imperas32i ;
2023-06-12 16:00:30 +00:00
" imperas32f " : if ( P . F_SUPPORTED ) tests = imperas32f ;
" imperas32m " : if ( P . M_SUPPORTED ) tests = imperas32m ;
" wally32a " : if ( P . A_SUPPORTED ) tests = wally32a ;
" imperas32c " : if ( P . C_SUPPORTED ) tests = imperas32c ;
2023-04-14 02:18:26 +00:00
else tests = imperas32iNOc ;
" wally32i " : tests = wally32i ;
" wally32e " : tests = wally32e ;
" wally32priv " : tests = wally32priv ;
" wally32periph " : tests = wally32periph ;
" embench " : tests = embench ;
" coremark " : tests = coremark ;
2023-06-12 16:00:30 +00:00
" arch32zba " : if ( P . ZBA_SUPPORTED ) tests = arch32zba ;
" arch32zbb " : if ( P . ZBB_SUPPORTED ) tests = arch32zbb ;
" arch32zbc " : if ( P . ZBC_SUPPORTED ) tests = arch32zbc ;
" arch32zbs " : if ( P . ZBS_SUPPORTED ) tests = arch32zbs ;
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
2023-06-12 19:06:17 +00:00
end // initial begin
// Model the testbench as an fsm.
// Do this in parts so it easier to verify
// part 1: build a version which echos the same behavior as the below code, but does not drive anything
// part 2: drive some of the controls
// part 3: drive all logic and remove old inital and always @ negedge clk block
2023-06-13 18:18:46 +00:00
typedef enum logic [ 3 : 0 ] { STATE_TESTBENCH_RESET ,
STATE_INIT_TEST ,
2023-06-12 19:06:17 +00:00
STATE_RESET_MEMORIES ,
2023-06-13 21:24:38 +00:00
STATE_RESET_MEMORIES2 ,
2023-06-12 19:06:17 +00:00
STATE_LOAD_MEMORIES ,
STATE_RESET_TEST ,
STATE_RUN_TEST ,
2023-12-20 18:25:34 +00:00
STATE_COPY_RAM ,
2023-06-12 20:08:23 +00:00
STATE_CHECK_TEST ,
STATE_CHECK_TEST_WAIT ,
2023-06-14 16:50:12 +00:00
STATE_VALIDATE ,
STATE_INCR_TEST } statetype ;
2023-06-12 19:06:17 +00:00
statetype CurrState , NextState ;
logic TestBenchReset ;
logic [ 2 : 0 ] ResetCount , ResetThreshold ;
logic LoadMem ;
logic ResetCntEn ;
logic ResetCntRst ;
2023-12-20 19:16:32 +00:00
logic CopyRAM ;
2021-10-10 22:07:51 +00:00
2023-06-13 18:52:02 +00:00
string signame , memfilename , pathname ;
2023-06-12 19:06:17 +00:00
integer begin_signature_addr ;
assign ResetThreshold = 3 'd5 ;
initial begin
TestBenchReset = 1 ;
# 100 ;
TestBenchReset = 0 ;
2021-10-10 22:07:51 +00:00
end
2023-06-14 17:11:55 +00:00
always_ff @ ( posedge clk )
2023-06-13 18:18:46 +00:00
if ( TestBenchReset ) CurrState < = # 1 STATE_TESTBENCH_RESET ;
2023-06-12 19:06:17 +00:00
else CurrState < = # 1 NextState ;
2021-10-10 22:07:51 +00:00
2023-06-15 19:57:05 +00:00
// fsm next state logic
2023-06-12 19:06:17 +00:00
always_comb begin
2023-06-13 18:18:46 +00:00
// 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 " ;
pathname = tvpaths [ tests [ 0 ] . atoi ( ) ] ;
case ( CurrState )
2023-06-15 19:57:05 +00:00
STATE_TESTBENCH_RESET: NextState = STATE_INIT_TEST ;
STATE_INIT_TEST: NextState = STATE_RESET_MEMORIES ;
STATE_RESET_MEMORIES: NextState = STATE_RESET_MEMORIES2 ;
STATE_RESET_MEMORIES2: NextState = STATE_LOAD_MEMORIES ; // Give the reset enough time to ensure the bus is reset before loading the memories.
STATE_LOAD_MEMORIES: NextState = STATE_RESET_TEST ;
STATE_RESET_TEST: if ( ResetCount < ResetThreshold ) NextState = STATE_RESET_TEST ;
else NextState = STATE_RUN_TEST ;
2023-12-20 18:25:34 +00:00
STATE_RUN_TEST: if ( TestComplete ) NextState = STATE_COPY_RAM ;
2023-06-15 19:57:05 +00:00
else NextState = STATE_RUN_TEST ;
2023-12-20 18:25:34 +00:00
STATE_COPY_RAM: NextState = STATE_CHECK_TEST ;
2023-06-15 19:57:05 +00:00
STATE_CHECK_TEST: if ( DCacheFlushDone ) NextState = STATE_VALIDATE ;
else NextState = STATE_CHECK_TEST_WAIT ;
STATE_CHECK_TEST_WAIT: if ( DCacheFlushDone ) NextState = STATE_VALIDATE ;
else NextState = STATE_CHECK_TEST_WAIT ;
STATE_VALIDATE: NextState = STATE_INIT_TEST ;
STATE_INCR_TEST: NextState = STATE_INIT_TEST ;
default : NextState = STATE_TESTBENCH_RESET ;
2023-06-12 19:06:17 +00:00
endcase
end // always_comb
2023-06-15 19:57:05 +00:00
// fsm output control logic
assign reset_ext = CurrState = = STATE_TESTBENCH_RESET | CurrState = = STATE_INIT_TEST |
CurrState = = STATE_RESET_MEMORIES | CurrState = = STATE_RESET_MEMORIES2 |
CurrState = = STATE_LOAD_MEMORIES | CurrState = = STATE_RESET_TEST ;
// this initialization is very expensive, only do it for coremark.
assign ResetMem = ( CurrState = = STATE_RESET_MEMORIES | CurrState = = STATE_RESET_MEMORIES2 ) & TEST = = " coremark " ;
assign LoadMem = CurrState = = STATE_LOAD_MEMORIES ;
assign ResetCntRst = CurrState = = STATE_INIT_TEST ;
assign ResetCntEn = CurrState = = STATE_RESET_TEST ;
assign Validate = CurrState = = STATE_VALIDATE ;
assign SelectTest = CurrState = = STATE_INIT_TEST ;
2023-12-20 18:25:34 +00:00
assign CopyRAM = TestComplete & CurrState = = STATE_RUN_TEST ;
assign DCacheFlushStart = CurrState = = STATE_COPY_RAM ;
2023-06-15 19:57:05 +00:00
// fsm reset counter
counter # ( 3 ) RstCounter ( clk , ResetCntRst , ResetCntEn , ResetCount ) ;
2023-06-12 19:06:17 +00:00
2023-06-15 19:57:05 +00:00
////////////////////////////////////////////////////////////////////////////////
// Find the test vector files and populate the PC to function label converter
////////////////////////////////////////////////////////////////////////////////
2023-06-16 17:27:22 +00:00
logic [ P . XLEN - 1 : 0 ] testadr ;
2023-06-15 19:57:05 +00:00
assign begin_signature_addr = ProgramAddrLabelArray [ " begin_signature " ] ;
2023-06-14 17:11:55 +00:00
always @ ( posedge clk ) begin
if ( SelectTest ) begin
if ( riscofTest ) memfilename = { pathname , tests [ test ] , " /ref/ref.elf.memfile " } ;
else memfilename = { pathname , tests [ test ] , " .elf.memfile " } ;
if ( riscofTest ) begin
ProgramAddrMapFile = { pathname , tests [ test ] , " /ref/ref.elf.objdump.addr " } ;
ProgramLabelMapFile = { pathname , tests [ test ] , " /ref/ref.elf.objdump.lab " } ;
end else begin
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)
2023-10-13 19:08:17 +00:00
updateProgramAddrLabelArray ( ProgramAddrMapFile , ProgramLabelMapFile , ProgramAddrLabelArray ) ;
2023-06-14 17:11:55 +00:00
end
2023-06-15 19:57:05 +00:00
////////////////////////////////////////////////////////////////////////////////
// Verify the test ran correctly by checking the memory against a known signature.
////////////////////////////////////////////////////////////////////////////////
2023-06-14 17:11:55 +00:00
if ( TestBenchReset ) test = 1 ;
2023-06-15 19:57:05 +00:00
if ( TEST = = " coremark " )
2023-12-20 18:25:34 +00:00
if ( dut . core . priv . priv . EcallFaultM ) begin
2023-06-15 19:57:05 +00:00
$display ( " Benchmark: coremark is done. " ) ;
$stop ;
end
2023-06-14 17:11:55 +00:00
if ( Validate ) begin
2023-06-15 19:57:05 +00:00
if ( TEST = = " embench " ) begin
2023-06-14 17:23:26 +00:00
// 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
$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 , " w " ) ;
i = 0 ;
2023-06-16 17:27:22 +00:00
testadr = ( $unsigned ( begin_signature_addr ) ) / ( P . XLEN / 8 ) ;
while ( $unsigned ( i ) < $unsigned ( 5 'd5 ) ) begin
$fdisplayh ( outputFilePointer , DCacheFlushFSM . ShadowRAM [ testadr + i ] ) ;
i = i + 1 ;
end
2023-06-14 17:23:26 +00:00
$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
end
2022-08-24 18:27:18 +00:00
2023-06-14 17:11:55 +00:00
if ( ! begin_signature_addr )
$display ( " begin_signature addr not found in %s " , ProgramLabelMapFile ) ;
2023-06-16 16:54:41 +00:00
else if ( TEST ! = " embench " ) begin // *** quick hack for embench. need a better long term solution
2023-06-14 17:11:55 +00:00
CheckSignature ( pathname , tests [ test ] , riscofTest , begin_signature_addr , errors ) ;
end
if ( errors > 0 ) totalerrors = totalerrors + 1 ;
2023-06-16 16:54:41 +00:00
test = test + 1 ; // *** this probably needs to be moved.
2023-06-14 17:11:55 +00:00
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
end
end
2023-06-12 19:06:17 +00:00
////////////////////////////////////////////////////////////////////////////////
// Some memories are not reset, but should be zeros or set to some initial value for simulation
////////////////////////////////////////////////////////////////////////////////
2023-12-20 18:25:34 +00:00
/ * - - - - - \ / - - - - - EXCLUDED - - - - - \ / - - - - -
2023-06-12 19:06:17 +00:00
integer adrindex ;
2023-06-13 18:57:58 +00:00
always @ ( posedge clk ) begin
2023-06-13 19:05:17 +00:00
if ( ResetMem ) // program memory is sometimes reset
2023-06-13 18:57:58 +00:00
if ( P . UNCORE_RAM_SUPPORTED )
2023-06-13 18:54:07 +00:00
for ( adrindex = 0 ; adrindex < ( P . UNCORE_RAM_RANGE > > 1 + ( P . XLEN / 32 ) ) ; adrindex = adrindex + 1 )
dut . uncore . uncore . ram . ram . memory . RAM [ adrindex ] = '0 ;
2023-12-13 20:53:44 +00:00
if ( reset ) begin // branch predictor must always be reset
2023-06-13 18:57:58 +00:00
if ( P . BPRED_SUPPORTED ) begin
// local history only
2023-07-18 20:07:10 +00:00
if ( P . BPRED_TYPE = = `BP_LOCAL_AHEAD | P . BPRED_TYPE = = `BP_LOCAL_REPAIR )
2023-06-13 18:57:58 +00:00
for ( adrindex = 0 ; adrindex < 2 * * P . BPRED_NUM_LHR ; adrindex + + )
2023-06-13 18:54:07 +00:00
dut . core . ifu . bpred . bpred . Predictor . DirPredictor . BHT . mem [ adrindex ] = 0 ;
2023-06-13 18:57:58 +00:00
for ( adrindex = 0 ; adrindex < 2 * * P . BTB_SIZE ; adrindex + + )
2023-06-13 18:54:07 +00:00
dut . core . ifu . bpred . bpred . TargetPredictor . memory . mem [ adrindex ] = 0 ;
2023-06-13 18:57:58 +00:00
for ( adrindex = 0 ; adrindex < 2 * * P . BPRED_SIZE ; adrindex + + )
2023-06-13 18:54:07 +00:00
dut . core . ifu . bpred . bpred . Predictor . DirPredictor . PHT . mem [ adrindex ] = 0 ;
2023-06-12 19:06:17 +00:00
end
2023-12-13 20:53:44 +00:00
end
2023-06-12 19:06:17 +00:00
end
2023-12-20 18:25:34 +00:00
- - - - - / \ - - - - - EXCLUDED - - - - - / \ - - - - - */
2023-06-12 19:06:17 +00:00
2023-12-20 18:25:34 +00:00
// still not working in this format
/ * - - - - - \ / - - - - - EXCLUDED - - - - - \ / - - - - -
integer adrindex ;
if ( P . UNCORE_RAM_SUPPORTED ) begin
always @ ( posedge clk ) begin
if ( ResetMem ) // program memory is sometimes reset
for ( adrindex = 0 ; adrindex < ( P . UNCORE_RAM_RANGE > > 1 + ( P . XLEN / 32 ) ) ; adrindex = adrindex + 1 )
dut . uncore . uncore . ram . ram . memory . RAM [ adrindex ] = '0 ;
end
end
genvar adrindex2 ;
if ( P . BPRED_SUPPORTED & ( P . BPRED_TYPE = = `BP_LOCAL_AHEAD | P . BPRED_TYPE = = `BP_LOCAL_REPAIR ) ) begin
for ( adrindex2 = 0 ; adrindex2 < 2 * * P . BPRED_NUM_LHR ; adrindex2 + + )
always @ ( posedge clk ) begin
dut . core . ifu . bpred . bpred . Predictor . DirPredictor . BHT . mem [ adrindex2 ] = 0 ;
end
end
if ( P . BPRED_SUPPORTED ) begin
always @ ( posedge clk )
dut . core . ifu . bpred . bpred . TargetPredictor . memory . mem [ 0 ] = 0 ;
for ( adrindex2 = 0 ; adrindex2 < 2 * * P . BTB_SIZE ; adrindex2 + + )
always @ ( posedge clk ) begin
dut . core . ifu . bpred . bpred . TargetPredictor . memory . mem [ adrindex2 ] = 0 ;
end
for ( adrindex2 = 0 ; adrindex2 < 2 * * P . BPRED_SIZE ; adrindex2 + + )
always @ ( posedge clk ) begin
dut . core . ifu . bpred . bpred . Predictor . DirPredictor . PHT . mem [ adrindex2 ] = 0 ;
end
end
- - - - - / \ - - - - - EXCLUDED - - - - - / \ - - - - - */
2023-06-12 19:06:17 +00:00
////////////////////////////////////////////////////////////////////////////////
// load memories with program image
////////////////////////////////////////////////////////////////////////////////
2023-12-20 18:25:34 +00:00
integer IndexTemp ;
if ( P . SDC_SUPPORTED ) begin
always @ ( posedge clk ) begin
if ( LoadMem ) begin
2023-06-13 18:52:02 +00:00
string romfilename , sdcfilename ;
romfilename = { " ../tests/custom/fpga-test-sdc/bin/fpga-test-sdc.memfile " } ;
sdcfilename = { " ../testbench/sdc/ramdisk2.hex " } ;
2023-10-13 19:08:17 +00:00
//$readmemh(romfilename, dut.uncore.uncore.bootrom.bootrom.memory.ROM);
//$readmemh(sdcfilename, sdcard.sdcard.FLASHmem);
2023-06-13 18:52:02 +00:00
// shorten sdc timers for simulation
2023-12-13 20:53:44 +00:00
//dut.uncore.uncore.sdc.SDC.LimitTimers = 1;
2023-12-20 18:25:34 +00:00
end
end
end else if ( P . IROM_SUPPORTED ) begin
always @ ( posedge clk ) begin
if ( LoadMem ) begin
$readmemh ( memfilename , dut . core . ifu . irom . irom . rom . ROM ) ;
end
end
end else if ( P . BUS_SUPPORTED ) begin
always @ ( posedge clk ) begin
if ( LoadMem ) begin
$readmemh ( memfilename , dut . uncore . uncore . ram . ram . memory . RAM ) ;
end
if ( CopyRAM ) begin
for ( IndexTemp = 0 ; IndexTemp < ( P . UNCORE_RAM_RANGE ) > > 1 + ( P . XLEN / 32 ) ; IndexTemp + + ) begin
//if(dut.uncore.uncore.ram.ram.memory.RAM[IndexTemp] === 'bx) break; // end copy early if at the end of the sig *** double check this will be valid for all tests.
testbench . DCacheFlushFSM . ShadowRAM [ ( ( P . UNCORE_RAM_BASE ) > > 1 + ( P . XLEN / 32 ) ) + IndexTemp ] = dut . uncore . uncore . ram . ram . memory . RAM [ IndexTemp ] ;
end
end
end
end
if ( P . DTIM_SUPPORTED ) begin
always @ ( posedge clk ) begin
if ( LoadMem ) begin
$readmemh ( memfilename , dut . core . lsu . dtim . dtim . ram . RAM ) ;
$display ( " Read memfile %s " , memfilename ) ;
end
if ( CopyRAM ) begin
for ( IndexTemp = 0 ; IndexTemp < ( P . DTIM_RANGE ) > > 1 + ( P . XLEN / 32 ) ; IndexTemp + + ) begin
//if(dut.core.lsu.dtim.dtim.ram.RAM[IndexTemp] === 'bx) break; // end copy early if at the end of the sig *** double check this will be valid for all tests.
testbench . DCacheFlushFSM . ShadowRAM [ ( ( P . DTIM_BASE ) > > 1 + ( P . XLEN / 32 ) ) + IndexTemp ] = dut . core . lsu . dtim . dtim . ram . RAM [ IndexTemp ] ;
end
end
2023-12-18 18:50:49 +00:00
end
2023-12-20 18:25:34 +00:00
end
2023-06-14 22:02:49 +00:00
2023-06-15 19:57:05 +00:00
////////////////////////////////////////////////////////////////////////////////
// Actual hardware
////////////////////////////////////////////////////////////////////////////////
2022-08-24 18:27:18 +00:00
2021-10-10 22:07:51 +00:00
// instantiate device to be tested
2023-03-24 23:55:43 +00:00
assign GPIOIN = 0 ;
2021-10-10 22:07:51 +00:00
assign UARTSin = 1 ;
2023-10-12 20:36:57 +00:00
assign SPIIn = 0 ;
2022-08-24 18:27:18 +00:00
2023-06-12 16:00:30 +00:00
if ( P . EXT_MEM_SUPPORTED ) begin
ram_ahb # ( . BASE ( P . EXT_MEM_BASE ) , . RANGE ( P . EXT_MEM_RANGE ) )
2022-08-24 18:27:18 +00:00
ram ( . HCLK , . HRESETn , . HADDR , . HWRITE , . HTRANS , . HWDATA , . HSELRam ( HSELEXT ) ,
2023-06-15 19:57:05 +00:00
. HREADRam ( HRDATAEXT ) , . HREADYRam ( HREADYEXT ) , . HRESPRam ( HRESPEXT ) , . HREADY , . HWSTRB ) ;
2022-08-24 18:27:18 +00:00
end else begin
assign HREADYEXT = 1 ;
2023-06-15 19:57:05 +00:00
assign { HRESPEXT , HRDATAEXT } = '0 ;
2022-08-24 18:27:18 +00:00
end
2023-10-13 19:08:17 +00:00
if ( P . SDC_SUPPORTED ) begin : sdcard
2023-07-21 22:43:45 +00:00
// *** fix later
/ * - - - - - \ / - - - - - EXCLUDED - - - - - \ / - - - - -
2022-08-24 18:27:18 +00:00
sdModel sdcard
( . sdClk ( SDCCLK ) ,
. cmd ( SDCCmd ) ,
. dat ( SDCDat ) ) ;
assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1 ' bz ;
assign SDCCmdIn = SDCCmd ;
2023-10-17 19:13:18 +00:00
assign SDCDat = sd_dat_reg_t ? sd_dat_reg_o : sd_dat_i ;
2022-08-24 18:27:18 +00:00
assign SDCDatIn = SDCDat ;
2023-07-21 22:43:45 +00:00
- - - - - / \ - - - - - EXCLUDED - - - - - / \ - - - - - */
assign SDCIntr = '0 ;
2022-08-24 18:27:18 +00:00
end else begin
2023-07-21 22:43:45 +00:00
assign SDCIntr = '0 ;
2022-08-24 18:27:18 +00:00
end
2021-10-10 22:07:51 +00:00
2023-10-13 19:08:17 +00:00
wallypipelinedsoc # ( P ) dut ( . clk , . reset_ext , . reset , . HRDATAEXT , . HREADYEXT , . HRESPEXT , . HSELEXT , . HSELEXTSDC ,
2023-06-15 19:57:05 +00:00
. HCLK , . HRESETn , . HADDR , . HWDATA , . HWSTRB , . HWRITE , . HSIZE , . HBURST , . HPROT ,
. HTRANS , . HMASTLOCK , . HREADY , . TIMECLK ( 1 'b0 ) , . GPIOIN , . GPIOOUT , . GPIOEN ,
2023-10-12 20:36:57 +00:00
. UARTSin , . UARTSout , . SDCIntr , . SPIIn , . SPIOut , . SPICS ) ;
2021-10-10 22:07:51 +00:00
// generate clock to sequence tests
2023-06-15 19:57:05 +00:00
always begin
clk = 1 ; # 5 ; clk = 0 ; # 5 ;
2023-01-06 00:00:11 +00:00
end
2023-03-03 19:10:01 +00:00
2023-06-15 19:57:05 +00:00
////////////////////////////////////////////////////////////////////////////////
// Support logic
////////////////////////////////////////////////////////////////////////////////
2023-11-03 12:24:15 +00:00
// Duplicate copy of pipeline registers that are optimized out of some configurations
logic [ 31 : 0 ] NextInstrE , InstrM ;
mux2 # ( 32 ) FlushInstrMMux ( dut . core . ifu . InstrE , dut . core . ifu . nop , dut . core . ifu . FlushM , NextInstrE ) ;
flopenr # ( 32 ) InstrMReg ( clk , reset , ~ dut . core . ifu . StallM , NextInstrE , InstrM ) ;
2023-07-02 20:29:27 +00:00
// Track names of instructions
string InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ;
logic [ 31 : 0 ] InstrW ;
2023-11-03 12:24:15 +00:00
flopenr # ( 32 ) InstrWReg ( clk , reset , ~ dut . core . ieu . dp . StallW , InstrM , InstrW ) ;
2023-07-02 20:29:27 +00:00
instrTrackerTB it ( clk , reset , dut . core . ieu . dp . FlushE ,
dut . core . ifu . InstrRawF [ 31 : 0 ] ,
dut . core . ifu . InstrD , dut . core . ifu . InstrE ,
2023-11-03 12:24:15 +00:00
InstrM , InstrW ,
2023-07-02 20:29:27 +00:00
InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ) ;
// watch for problems such as lockup, reading unitialized memory, bad configs
2023-06-15 19:57:05 +00:00
watchdog # ( P . XLEN , 1000000 ) watchdog ( . clk , . reset ) ; // check if PCW is stuck
2023-07-02 20:29:27 +00:00
ramxdetector # ( P . XLEN , P . LLEN ) ramxdetector ( clk , dut . core . lsu . MemRWM [ 1 ] , dut . core . lsu . LSULoadAccessFaultM , dut . core . lsu . ReadDataM ,
2023-11-03 12:24:15 +00:00
dut . core . ifu . PCM , InstrM , dut . core . lsu . IEUAdrM , InstrMName ) ;
2023-06-15 19:57:05 +00:00
riscvassertions # ( P ) riscvassertions ( ) ; // check assertions for a legal configuration
loggers # ( P , TEST , PrintHPMCounters , I_CACHE_ADDR_LOGGER , D_CACHE_ADDR_LOGGER , BPRED_LOGGER )
loggers ( clk , reset , DCacheFlushStart , DCacheFlushDone , memfilename ) ;
2023-01-06 00:00:11 +00:00
2021-10-10 22:07:51 +00:00
// track the current function or global label
2023-11-17 17:21:25 +00:00
if ( DEBUG = = 1 | ( ( PrintHPMCounters | BPRED_LOGGER ) & P . ZICNTR_SUPPORTED ) ) begin : FunctionName
2023-06-15 19:57:05 +00:00
FunctionName # ( P ) FunctionName ( . reset ( reset_ext | TestBenchReset ) ,
. clk ( clk ) , . ProgramAddrMapFile ( ProgramAddrMapFile ) , . ProgramLabelMapFile ( ProgramLabelMapFile ) ) ;
2021-10-10 22:07:51 +00:00
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
2023-06-12 16:00:30 +00:00
if ( P . ZICSR_SUPPORTED ) assign ecf = dut . core . priv . priv . EcallFaultM ;
2022-01-05 16:41:17 +00:00
else assign ecf = 0 ;
2023-12-20 18:25:34 +00:00
assign TestComplete = 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 ) ) |
2023-11-03 12:24:15 +00:00
( ( InstrM = = 32 'h6f | InstrM = = 32 'hfc32a423 | InstrM = = 32 'hfc32a823 ) & dut . core . ieu . c . InstrValidM ) |
2023-12-20 18:25:34 +00:00
( ( dut . core . lsu . IEUAdrM = = ProgramAddrLabelArray [ " tohost " ] ) & InstrMName = = " SW " ) ;
//assign DCacheFlushStart = TestComplete;
2023-06-15 19:57:05 +00:00
DCacheFlushFSM # ( P ) DCacheFlushFSM ( . clk ( clk ) , . reset ( reset ) , . start ( DCacheFlushStart ) , . done ( DCacheFlushDone ) ) ;
2023-05-03 17:52:32 +00:00
2023-06-14 22:02:49 +00:00
task automatic CheckSignature ;
// This task must be declared inside this module as it needs access to parameter P. There is
// no way to pass P to the task unless we convert it to a module.
2023-04-05 06:49:35 +00:00
2023-06-14 22:02:49 +00:00
input string pathname ;
input string TestName ;
input logic riscofTest ;
input integer begin_signature_addr ;
output integer errors ;
localparam SIGNATURESIZE = 5000000 ;
integer i ;
logic [ 31 : 0 ] sig32 [ 0 : SIGNATURESIZE ] ;
logic [ P . XLEN - 1 : 0 ] signature [ 0 : SIGNATURESIZE ] ;
2023-07-07 21:34:08 +00:00
string signame ;
2023-06-14 22:02:49 +00:00
logic [ P . XLEN - 1 : 0 ] testadr , testadrNoBase ;
2023-04-13 23:53:36 +00:00
2023-06-14 22:02:49 +00:00
// 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 ;
2023-04-14 02:06:09 +00:00
end
2023-06-14 22:02:49 +00:00
if ( riscofTest ) signame = { pathname , TestName , " /ref/Reference-sail_c_simulator.signature " } ;
else signame = { pathname , TestName , " .signature.output " } ;
// read signature, reformat in 64 bits if necessary
$readmemh ( signame , sig32 ) ;
i = 0 ;
while ( i < SIGNATURESIZE ) begin
if ( P . 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
if ( i > = 4 & sig32 [ i - 4 ] = = = ' bx ) 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
2023-04-14 02:06:09 +00:00
end
2023-03-27 23:36:02 +00:00
end
2023-02-20 05:48:16 +00:00
2023-06-14 22:02:49 +00:00
// Check errors
errors = ( i = = SIGNATURESIZE + 1 ) ; // error if file is empty
i = 0 ;
testadr = ( $unsigned ( begin_signature_addr ) ) / ( P . XLEN / 8 ) ;
testadrNoBase = ( begin_signature_addr - P . UNCORE_RAM_BASE ) / ( P . XLEN / 8 ) ;
/* verilator lint_off INFINITELOOP */
2023-12-20 18:25:34 +00:00
/* verilator lint_off WIDTHXZEXPAND */
2023-06-14 22:02:49 +00:00
while ( signature [ i ] ! = = ' bx ) begin
2023-12-20 18:25:34 +00:00
/* verilator lint_on WIDTHXZEXPAND */
2023-06-14 22:02:49 +00:00
logic [ P . XLEN - 1 : 0 ] sig ;
2023-12-20 18:25:34 +00:00
// **************************************
// ***** BUG BUG BUG make sure RT undoes this.
//if (P.DTIM_SUPPORTED) sig = testbench.dut.core.lsu.dtim.dtim.ram.RAM[testadrNoBase+i];
//else if (P.UNCORE_RAM_SUPPORTED) sig = testbench.dut.uncore.uncore.ram.ram.memory.RAM[testadrNoBase+i];
if ( P . UNCORE_RAM_SUPPORTED ) sig = testbench . dut . uncore . uncore . ram . ram . memory . RAM [ testadrNoBase + i ] ;
//if (P.UNCORE_RAM_SUPPORTED) sig = testbench.dut.uncore.uncore.ram.ram.memory.RAM[testadrNoBase+i];
2023-06-14 22:02:49 +00:00
//$display("signature[%h] = %h sig = %h", i, signature[i], sig);
2023-12-20 18:25:34 +00:00
//if (signature[i] !== sig & (signature[i] !== testbench.DCacheFlushFSM.ShadowRAM[testadr+i])) begin
if ( signature [ i ] ! = = testbench . DCacheFlushFSM . ShadowRAM [ testadr + i ] ) begin
2023-06-14 22:02:49 +00:00
errors = errors + 1 ;
$display ( " Error on test %s result %d: adr = %h sim (D$) %h sim (DTIM_SUPPORTED) = %h, signature = %h " ,
TestName , i , ( testadr + i ) * ( P . XLEN / 8 ) , testbench . DCacheFlushFSM . ShadowRAM [ testadr + i ] , sig , signature [ i ] ) ;
2023-12-20 18:25:34 +00:00
//$display(" Error on test %s result %d: adr = %h sim (DTIM_SUPPORTED) = %h, signature = %h",
// TestName, i, (testadr+i)*(P.XLEN/8), testbench.DCacheFlushFSM.ShadowRAM[testadr+i], signature[i]);
2023-06-14 22:02:49 +00:00
$stop ; //***debug
2023-04-14 02:06:09 +00:00
end
2023-06-14 22:02:49 +00:00
i = i + 1 ;
end
/* verilator lint_on INFINITELOOP */
if ( errors = = 0 ) begin
$display ( " %s succeeded. Brilliant!!! " , TestName ) ;
end else begin
$display ( " %s failed with %d errors. :( " , TestName , errors ) ;
//totalerrors = totalerrors+1;
2022-05-17 01:03:09 +00:00
end
2022-12-21 15:18:00 +00:00
2023-06-14 22:02:49 +00:00
endtask //
2022-12-21 15:18:00 +00:00
2023-05-31 21:51:00 +00:00
/* verilator lint_on WIDTHTRUNC */
/* verilator lint_on WIDTHEXPAND */
2021-10-10 22:07:51 +00:00
endmodule
/* verilator lint_on STMTDLY */
/* verilator lint_on WIDTH */
2022-06-17 22:07:16 +00:00
task automatic updateProgramAddrLabelArray ;
2023-05-31 21:51:00 +00:00
/* verilator lint_off WIDTHTRUNC */
/* verilator lint_off WIDTHEXPAND */
2022-06-17 22:07:16 +00:00
input string ProgramAddrMapFile , ProgramLabelMapFile ;
inout integer ProgramAddrLabelArray [ string ] ;
// Gets the memory location of begin_signature
integer ProgramLabelMapFP , ProgramAddrMapFP ;
ProgramLabelMapFP = $fopen ( ProgramLabelMapFile , " r " ) ;
ProgramAddrMapFP = $fopen ( ProgramAddrMapFile , " r " ) ;
2023-06-13 20:09:40 +00:00
2022-06-17 22:07:16 +00:00
if ( ProgramLabelMapFP & ProgramAddrMapFP ) begin // check we found both files
2023-06-13 20:09:40 +00:00
// *** RT: I'm a bit confused by the required initialization here.
ProgramAddrLabelArray [ " begin_signature " ] = 0 ;
ProgramAddrLabelArray [ " tohost " ] = 0 ;
2022-06-17 22:07:16 +00:00
while ( ! $feof ( ProgramLabelMapFP ) ) begin
string label , adrstr ;
integer returncode ;
returncode = $fscanf ( ProgramLabelMapFP , " %s \n " , label ) ;
returncode = $fscanf ( ProgramAddrMapFP , " %s \n " , adrstr ) ;
2023-04-14 02:06:09 +00:00
if ( ProgramAddrLabelArray . exists ( label ) ) ProgramAddrLabelArray [ label ] = adrstr . atohex ( ) ;
2022-06-17 22:07:16 +00:00
end
end
$fclose ( ProgramLabelMapFP ) ;
$fclose ( ProgramAddrMapFP ) ;
2023-05-31 21:51:00 +00:00
/* verilator lint_on WIDTHTRUNC */
/* verilator lint_on WIDTHEXPAND */
2022-07-17 21:20:04 +00:00
endtask
2023-01-12 16:09:34 +00:00