2021-06-07 16:37:46 +00:00
///////////////////////////////////////////
// testbench-linux.sv
//
// Written: nboorstin@g.hmc.edu 2021
// Modified:
//
// Purpose: Testbench for buildroot or busybear linux
//
// A component of the Wally configurable RISC-V project.
//
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
//
// 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:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// 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.
///////////////////////////////////////////
`include " wally-config.vh "
2021-07-30 01:26:50 +00:00
`define DEBUG_TRACE 0
2021-06-07 16:37:46 +00:00
module testbench ( ) ;
2021-06-24 05:42:35 +00:00
2021-07-23 18:00:44 +00:00
parameter waveOnICount = `BUSYBEAR * 140000 + `BUILDROOT * 3080000 ; // # of instructions at which to turn on waves in graphical sim
2021-07-02 22:22:09 +00:00
parameter stopICount = `BUSYBEAR * 143898 + `BUILDROOT * 0000000 ; // # instructions at which to halt sim completely (set to 0 to let it run as far as it can)
2021-06-07 16:37:46 +00:00
2021-06-24 05:42:35 +00:00
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////// DUT /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
logic clk , reset ;
2021-07-17 18:48:12 +00:00
logic [ `AHBW - 1 : 0 ] r eadDataExpected ;
2021-06-07 16:37:46 +00:00
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 [ `AHBW - 1 : 0 ] HRDATAEXT ;
logic HREADYEXT , HRESPEXT ;
2021-06-24 05:42:35 +00:00
logic [ 31 : 0 ] GPIOPinsIn ;
logic [ 31 : 0 ] GPIOPinsOut , GPIOPinsEn ;
logic UARTSin , UARTSout ;
2021-06-07 16:37:46 +00:00
assign GPIOPinsIn = 0 ;
assign UARTSin = 1 ;
wallypipelinedsoc dut ( . * ) ;
2021-06-24 05:42:35 +00:00
///////////////////////////////////////////////////////////////////////////////
2021-06-25 12:15:19 +00:00
//////////////////////// Signals & Shared Macros ///////////////////////////
2021-06-24 05:42:35 +00:00
//////////////////////// AKA stuff that comes first ///////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Sorry if these have gotten decontextualized.
// Verilog expects them to be defined before they are used.
// -------------------
// Signal Declarations
// -------------------
// Testbench Core
integer instrs ;
integer warningCount = 0 ;
// PC, Instr Checking
logic [ `XLEN - 1 : 0 ] PCW ;
2021-07-30 01:26:50 +00:00
integer data_file_all ;
2021-08-06 21:06:50 +00:00
// Write Back stage signals needed for trace compare, but don't actually
// exist in CPU.
logic [ `XLEN - 1 : 0 ] MemAdrW , WriteDataW ;
// Write Back trace signals
2021-07-30 01:26:50 +00:00
logic checkInstrW ;
2021-08-13 19:39:05 +00:00
//integer RegAdr;
2021-08-06 21:06:50 +00:00
2021-07-30 01:26:50 +00:00
integer fault ;
2021-08-05 21:49:03 +00:00
logic TrapW ;
2021-08-06 21:06:50 +00:00
// Signals used to parse the trace file.
logic checkInstrM ;
integer matchCount ;
string line ;
logic [ `XLEN - 1 : 0 ] ExpectedPCM ;
logic [ 31 : 0 ] ExpectedInstrM ;
string textM ;
string token ;
string ExpectedTokens [ 31 : 0 ] ;
integer index ;
integer StartIndex , EndIndex ;
integer TokenIndex ;
integer MarkerIndex ;
integer NumCSRM ;
// Memory stage expected values from trace
string RegWriteM ;
integer ExpectedRegAdrM ;
logic [ `XLEN - 1 : 0 ] ExpectedRegValueM ;
string MemOpM ;
logic [ `XLEN - 1 : 0 ] ExpectedMemAdrM , ExpectedMemReadDataM , ExpectedMemWriteDataM ;
2021-08-13 19:39:05 +00:00
string ExpectedCSRArrayM [ integer ] ;
2021-08-06 21:06:50 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedCSRArrayValueM [ integer ] ;
// Write back stage expected values from trace
logic [ `XLEN - 1 : 0 ] ExpectedPCW ;
logic [ 31 : 0 ] ExpectedInstrW ;
string textW ;
string RegWriteW ;
integer ExpectedRegAdrW ;
logic [ `XLEN - 1 : 0 ] ExpectedRegValueW ;
string MemOpW ;
logic [ `XLEN - 1 : 0 ] ExpectedMemAdrW , ExpectedMemReadDataW , ExpectedMemWriteDataW ;
integer NumCSRW ;
2021-08-13 19:39:05 +00:00
string ExpectedCSRArrayW [ integer ] ;
2021-08-06 21:06:50 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedCSRArrayValueW [ integer ] ;
2021-08-13 19:39:05 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedIntType ;
integer NumCSRMIndex ;
integer NumCSRWIndex ;
integer NumCSRPostWIndex ;
2021-07-30 01:26:50 +00:00
2021-06-24 05:42:35 +00:00
// -----------
// Error Macro
// -----------
`define ERROR \
$display ( " processed %0d instructions with %0d warnings " , instrs , warningCount ) ; \
$stop ;
2021-07-30 01:26:50 +00:00
initial begin
data_file_all = $fopen ( { `LINUX_TEST_VECTORS , " all.txt " } , " r " ) ;
end
2021-08-08 05:28:18 +00:00
assign checkInstrM = dut . hart . ieu . InstrValidM & ~ dut . hart . priv . trap . InstrPageFaultM & ~ dut . hart . StallM ;
// trapW will already be invalid in there was an InstrPageFault in the previous instruction.
assign checkInstrW = dut . hart . ieu . InstrValidW & ~ dut . hart . StallW ;
2021-07-30 01:26:50 +00:00
flopenrc # ( `XLEN ) MemAdrWReg ( clk , reset , dut . hart . FlushW , ~ dut . hart . StallW , dut . hart . ieu . dp . MemAdrM , MemAdrW ) ;
flopenrc # ( `XLEN ) WriteDataWReg ( clk , reset , dut . hart . FlushW , ~ dut . hart . StallW , dut . hart . WriteDataM , WriteDataW ) ;
2021-08-06 21:06:50 +00:00
flopenrc # ( `XLEN ) PCWReg ( clk , reset , dut . hart . FlushW , ~ dut . hart . ieu . dp . StallW , dut . hart . ifu . PCM , PCW ) ;
2021-08-05 21:49:03 +00:00
flopenr # ( 1 ) TrapWReg ( clk , reset , ~ dut . hart . StallW , dut . hart . hzu . TrapM , TrapW ) ;
2021-07-30 01:26:50 +00:00
2021-08-06 21:06:50 +00:00
// because qemu does not match exactly to wally it is necessary to read the the
// trace in the memory stage and detect if anything in wally must be overwritten.
// This includes mtimer, interrupts, and various bits in mstatus and xtval.
// then on the next posedge the expected state is registered.
// on the next falling edge the expected state is compared to the wally state.
// step 0: read the expected state
2021-07-30 01:26:50 +00:00
always @ ( negedge clk ) begin
// always check PC, instruction bits
2021-08-06 21:06:50 +00:00
if ( checkInstrM ) begin
2021-07-30 01:26:50 +00:00
// read 1 line of the trace file
matchCount = $fgets ( line , data_file_all ) ;
2021-08-05 21:49:03 +00:00
if ( `DEBUG_TRACE > 0 ) $display ( " Time %t, line %x " , $time , line ) ;
2021-08-06 21:06:50 +00:00
matchCount = $sscanf ( line , " %x %x %s " , ExpectedPCM , ExpectedInstrM , textM ) ;
//$display("matchCount %d, PCM %x ExpectedInstrM %x textM %x", matchCount, ExpectedPCM, ExpectedInstrM, textM);
2021-07-30 01:26:50 +00:00
// for the life of me I cannot get any build in C or C++ string parsing functions/methods to work.
2021-07-30 22:57:03 +00:00
// strtok was the best idea but it cannot be used correctly as system verilog does not have null
// terminated strings.
2021-07-30 01:26:50 +00:00
// Just going to do this char by char.
StartIndex = 0 ;
TokenIndex = 0 ;
//$display("len = %d", line.len());
for ( index = 0 ; index < line . len ( ) ; index + + ) begin
//$display("char = %s", line[index]);
if ( line [ index ] = = " " | | line [ index ] = = " \n " ) begin
EndIndex = index ;
ExpectedTokens [ TokenIndex ] = line . substr ( StartIndex , EndIndex - 1 ) ;
//$display("In Tokenizer %s", line.substr(StartIndex, EndIndex-1));
StartIndex = EndIndex + 1 ;
TokenIndex + + ;
end
end
2021-08-06 21:06:50 +00:00
MarkerIndex = 3 ;
NumCSRM = 0 ;
MemOpM = " " ;
RegWriteM = " " ;
# 2 ;
2021-08-13 19:39:05 +00:00
2021-08-06 21:06:50 +00:00
while ( TokenIndex > MarkerIndex ) begin
// parse the GPR
if ( ExpectedTokens [ MarkerIndex ] = = " GPR " ) begin
RegWriteM = ExpectedTokens [ MarkerIndex ] ;
matchCount = $sscanf ( ExpectedTokens [ MarkerIndex + 1 ] , " %d " , ExpectedRegAdrM ) ;
matchCount = $sscanf ( ExpectedTokens [ MarkerIndex + 2 ] , " %x " , ExpectedRegValueM ) ;
MarkerIndex + = 3 ;
2021-07-30 01:26:50 +00:00
2021-08-06 21:06:50 +00:00
// parse memory address, read data, and/or write data
end else if ( ExpectedTokens [ MarkerIndex ] . substr ( 0 , 2 ) = = " Mem " ) begin
MemOpM = ExpectedTokens [ MarkerIndex ] ;
matchCount = $sscanf ( ExpectedTokens [ MarkerIndex + 1 ] , " %x " , ExpectedMemAdrM ) ;
matchCount = $sscanf ( ExpectedTokens [ MarkerIndex + 2 ] , " %x " , ExpectedMemWriteDataM ) ;
matchCount = $sscanf ( ExpectedTokens [ MarkerIndex + 3 ] , " %x " , ExpectedMemReadDataM ) ;
MarkerIndex + = 4 ;
2021-08-13 19:53:43 +00:00
// parse CSRs, because there are 1 or more CSRs after the CSR token
// we check if the CSR token or the number of CSRs is greater than 0.
// if so then we want to parse for a CSR.
2021-08-06 21:06:50 +00:00
end else if ( ExpectedTokens [ MarkerIndex ] = = " CSR " | | NumCSRM > 0 ) begin
2021-08-13 19:53:43 +00:00
if ( ExpectedTokens [ MarkerIndex ] = = " CSR " ) begin
// all additional CSR's won't have this token.
MarkerIndex + + ;
end
2021-08-06 21:06:50 +00:00
matchCount = $sscanf ( ExpectedTokens [ MarkerIndex ] , " %s " , ExpectedCSRArrayM [ NumCSRM ] ) ;
matchCount = $sscanf ( ExpectedTokens [ MarkerIndex + 1 ] , " %x " , ExpectedCSRArrayValueM [ NumCSRM ] ) ;
2021-08-13 19:39:05 +00:00
2021-08-13 19:53:43 +00:00
MarkerIndex + = 2 ;
2021-08-13 19:39:05 +00:00
// if we get an xcause with the interrupt bit set we must generate an interrupt as interrupts
// are imprecise. Forcing the trap at this time will allow wally to track what qemu does.
// the msb of xcause will be set.
// bits 1:0 select mode; 0 = user, 1 = superviser, 3 = machine
// bits 3:2 select the type of interrupt, 0 = software, 1 = timer, 2 = external
if ( ExpectedCSRArrayM [ NumCSRM ] . substr ( 1 , 5 ) = = " cause " & & ( ExpectedCSRArrayValueM [ NumCSRM ] [ `XLEN - 1 ] = = 1 'b1 ) ) begin
//what type?
ExpectedIntType = ExpectedCSRArrayValueM [ NumCSRM ] & 64 'h0000 _000C ;
$display ( " %t: CSR = %s. Forcing interrupt of cause = %x " , $time , ExpectedCSRArrayM [ NumCSRM ] , ExpectedCSRArrayValueM [ NumCSRM ] ) ;
if ( ExpectedIntType = = 0 ) begin
force dut . hart . priv . SwIntM = 1 'b1 ;
$display ( " Force SwIntM " ) ;
end
else if ( ExpectedIntType = = 4 ) begin
force dut . hart . priv . TimerIntM = 1 'b1 ;
$display ( " Force TimeIntM " ) ;
end
else if ( ExpectedIntType = = 8 ) begin
force dut . hart . priv . ExtIntM = 1 'b1 ;
$display ( " Force ExtIntM " ) ;
end
end
2021-08-06 21:06:50 +00:00
NumCSRM + + ;
end
end
2021-08-06 21:41:34 +00:00
// override on special conditions
if ( ExpectedMemAdrM = = 'h10000005 ) begin
2021-08-09 03:50:31 +00:00
//$display("%t: Overwriting read data from CLINT.", $time);
2021-08-06 21:41:34 +00:00
force dut . hart . ieu . dp . ReadDataM = ExpectedMemReadDataM ;
end
2021-08-13 19:39:05 +00:00
if ( textM . substr ( 0 , 5 ) = = " rdtime " ) begin
$display ( " %t: Overwrite read value of CSR on read of MTIME in memory stage. " , $time ) ;
force dut . hart . priv . csr . CSRReadValM = ExpectedRegValueM ;
//dut.hart.ieu.dp.regf.wd3
end
2021-08-06 21:41:34 +00:00
2021-08-06 21:06:50 +00:00
end // if (checkInstrM)
end
// step 1: register expected state into the write back stage.
always @ ( posedge clk ) begin
2021-08-09 03:50:31 +00:00
if ( reset ) begin
2021-08-06 21:06:50 +00:00
ExpectedPCW < = '0 ;
ExpectedInstrW < = '0 ;
textW < = " " ;
RegWriteW < = " " ;
ExpectedRegAdrW < = '0 ;
ExpectedRegValueW < = '0 ;
ExpectedMemAdrW < = '0 ;
MemOpW < = " " ;
ExpectedMemWriteDataW < = '0 ;
ExpectedMemReadDataW < = '0 ;
NumCSRW < = '0 ;
end
else if ( ~ dut . hart . StallW ) begin
2021-08-09 03:50:31 +00:00
if ( dut . hart . FlushW ) begin
ExpectedPCW < = '0 ;
ExpectedInstrW < = '0 ;
textW < = " " ;
RegWriteW < = " " ;
ExpectedRegAdrW < = '0 ;
ExpectedRegValueW < = '0 ;
ExpectedMemAdrW < = '0 ;
MemOpW < = " " ;
ExpectedMemWriteDataW < = '0 ;
ExpectedMemReadDataW < = '0 ;
NumCSRW < = '0 ;
end else begin
ExpectedPCW < = ExpectedPCM ;
ExpectedInstrW < = ExpectedInstrM ;
textW < = textM ;
RegWriteW < = RegWriteM ;
ExpectedRegAdrW < = ExpectedRegAdrM ;
ExpectedRegValueW < = ExpectedRegValueM ;
ExpectedMemAdrW < = ExpectedMemAdrM ;
MemOpW < = MemOpM ;
ExpectedMemWriteDataW < = ExpectedMemWriteDataM ;
ExpectedMemReadDataW < = ExpectedMemReadDataM ;
NumCSRW < = NumCSRM ;
2021-08-13 19:39:05 +00:00
for ( NumCSRWIndex = 0 ; NumCSRWIndex < NumCSRW ; NumCSRWIndex + + ) begin
ExpectedCSRArrayW [ NumCSRWIndex ] = ExpectedCSRArrayM [ NumCSRWIndex ] ;
ExpectedCSRArrayValueW [ NumCSRWIndex ] = ExpectedCSRArrayValueM [ NumCSRWIndex ] ;
end
2021-08-09 03:50:31 +00:00
end
2021-08-06 21:06:50 +00:00
// override on special conditions
# 1 ;
2021-08-06 21:41:34 +00:00
2021-08-13 19:39:05 +00:00
if ( textW . substr ( 0 , 5 ) = = " rdtime " ) begin
$display ( " %t:Releasing force of CSRReadValM. " , $time ) ;
release dut . hart . priv . csr . CSRReadValM ;
//release dut.hart.ieu.dp.regf.wd3;
end
2021-08-06 21:41:34 +00:00
if ( ExpectedMemAdrM = = 'h10000005 ) begin
2021-08-09 03:50:31 +00:00
//$display("%t: releasing force of ReadDataM.", $time);
2021-08-06 21:41:34 +00:00
release dut . hart . ieu . dp . ReadDataM ;
2021-08-06 21:16:39 +00:00
end
2021-08-13 19:39:05 +00:00
// remove forces on interrupts
for ( NumCSRMIndex = 0 ; NumCSRMIndex < NumCSRM ; NumCSRMIndex + + ) begin
if ( ExpectedCSRArrayM [ NumCSRMIndex ] . substr ( 1 , 5 ) = = " cause " & & ( ExpectedCSRArrayValueM [ NumCSRMIndex ] [ `XLEN - 1 ] = = 1 'b1 ) ) begin
//what type?
$display ( " $t: Releasing all forces on interrupts " , $time ) ;
release dut . hart . priv . SwIntM ;
release dut . hart . priv . TimerIntM ;
release dut . hart . priv . ExtIntM ;
end
end
2021-08-06 21:06:50 +00:00
end
end
// step2: make all checks in the write back stage.
always @ ( negedge clk ) begin
// always check PC, instruction bits
if ( checkInstrW ) begin
2021-07-30 01:26:50 +00:00
// check PCW
2021-08-06 21:06:50 +00:00
fault = 0 ;
2021-07-30 01:26:50 +00:00
if ( PCW ! = ExpectedPCW ) begin
$display ( " PCW: %016x does not equal ExpectedPCW: %016x " , PCW , ExpectedPCW ) ;
2021-08-06 21:06:50 +00:00
fault = 1 ;
2021-07-30 01:26:50 +00:00
end
// check instruction value
if ( dut . hart . ifu . InstrW ! = ExpectedInstrW ) begin
$display ( " InstrW: %x does not equal ExpectedInstrW: %x " , dut . hart . ifu . InstrW , ExpectedInstrW ) ;
2021-08-06 21:06:50 +00:00
fault = 1 ;
2021-07-30 01:26:50 +00:00
end
2021-08-06 15:16:06 +00:00
2021-08-06 21:06:50 +00:00
# 2 ; // delay 2 ns.
2021-07-30 01:26:50 +00:00
2021-08-06 21:06:50 +00:00
if ( `DEBUG_TRACE > 1 ) begin
$display ( " Reg Write Address: %02d ? expected value: %02d " , dut . hart . ieu . dp . regf . a3 , ExpectedRegAdrW ) ;
$display ( " RF[%02d]: %016x ? expected value: %016x " , ExpectedRegAdrW , dut . hart . ieu . dp . regf . rf [ ExpectedRegAdrW ] , ExpectedRegValueW ) ;
end
if ( RegWriteW = = " GPR " ) begin
if ( dut . hart . ieu . dp . regf . a3 ! = ExpectedRegAdrW ) begin
$display ( " Reg Write Address: %02d does not equal expected value: %02d " , dut . hart . ieu . dp . regf . a3 , ExpectedRegAdrW ) ;
fault = 1 ;
end
if ( dut . hart . ieu . dp . regf . rf [ ExpectedRegAdrW ] ! = ExpectedRegValueW ) begin
$display ( " RF[%02d]: %016x does not equal expected value: %016x " , ExpectedRegAdrW , dut . hart . ieu . dp . regf . rf [ ExpectedRegAdrW ] , ExpectedRegValueW ) ;
fault = 1 ;
end
end
2021-08-06 15:16:06 +00:00
2021-08-06 21:06:50 +00:00
if ( MemOpW . substr ( 0 , 2 ) = = " Mem " ) begin
2021-08-13 19:39:05 +00:00
if ( `DEBUG_TRACE > 2 ) $display ( " \t MemAdrW: %016x ? expected: %016x " , MemAdrW , ExpectedMemAdrW ) ;
2021-08-06 21:06:50 +00:00
// always check address
2021-08-13 19:39:05 +00:00
if ( MemAdrW ! = ExpectedMemAdrW ) begin
$display ( " MemAdrW: %016x does not equal expected value: %016x " , MemAdrW , ExpectedMemAdrW ) ;
2021-08-06 21:06:50 +00:00
fault = 1 ;
end
// check read data
if ( MemOpW = = " MemR " | | MemOpW = = " MemRW " ) begin
2021-08-08 05:28:18 +00:00
if ( `DEBUG_TRACE > 2 ) $display ( " \t ReadDataW: %016x ? expected: %016x " , dut . hart . ieu . dp . ReadDataW , ExpectedMemReadDataW ) ;
if ( dut . hart . ieu . dp . ReadDataW ! = ExpectedMemReadDataW ) begin
$display ( " ReadDataW: %016x does not equal expected value: %016x " , dut . hart . ieu . dp . ReadDataW , ExpectedMemReadDataW ) ;
2021-08-06 21:06:50 +00:00
fault = 1 ;
end
/ * - - - - - \ / - - - - - EXCLUDED - - - - - \ / - - - - -
if ( ExpectedMemAdr = = 'h10000005 ) begin
force dut . hart . ieu . dp . ReadDataW = ExpectedMemReadData ;
force dut . hart . ieu . dp . regf . wd3 = RegValue ;
end else begin
end
- - - - - / \ - - - - - EXCLUDED - - - - - / \ - - - - - */
end
// check write data
else if ( ExpectedTokens [ MarkerIndex ] = = " MemW " | | ExpectedTokens [ MarkerIndex ] = = " MemRW " ) begin
2021-08-08 05:28:18 +00:00
if ( `DEBUG_TRACE > 2 ) $display ( " \t WriteDataW: %016x ? expected: %016x " , WriteDataW , ExpectedMemWriteDataW ) ;
if ( WriteDataW ! = ExpectedMemWriteDataW ) begin
$display ( " WriteDataW: %016x does not equal expected value: %016x " , WriteDataW , ExpectedMemWriteDataW ) ;
2021-08-06 21:06:50 +00:00
fault = 1 ;
end
end
2021-07-30 01:26:50 +00:00
2021-08-13 19:39:05 +00:00
// check csr
2021-07-30 01:26:50 +00:00
2021-08-13 19:39:05 +00:00
for ( NumCSRPostWIndex = 0 ; NumCSRPostWIndex < NumCSRW ; NumCSRPostWIndex + + ) begin
case ( ExpectedCSRArrayW [ NumCSRPostWIndex ] )
2021-07-30 01:26:50 +00:00
" mhartid " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MHARTID_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MHARTID_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MHARTID_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" mstatus " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MSTATUS_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( ( dut . hart . priv . csr . genblk1 . csrm . MSTATUS_REGW ) ! = ( ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MSTATUS_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" mtvec " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MTVEC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MTVEC_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MTVEC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" mip " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MIP_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MIP_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MIP_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" mie " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MIE_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MIE_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MIE_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" mideleg " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MIDELEG_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MIDELEG_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MIDELEG_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" medeleg " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MEDELEG_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MEDELEG_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MEDELEG_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" mepc " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MEPC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MEPC_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MEPC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" mtval " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MTVAL_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrm . MTVAL_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrm . MTVAL_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" sepc " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . SEPC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrs . SEPC_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . SEPC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" scause " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . genblk1 . SCAUSE_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrs . genblk1 . SCAUSE_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . genblk1 . SCAUSE_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" stvec " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . STVEC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrs . STVEC_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . STVEC_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
" stval " : begin
if ( `DEBUG_TRACE > 3 ) begin
2021-08-13 19:39:05 +00:00
$display ( " CSR: %s = %016x, expected = %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . genblk1 . STVAL_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
end
2021-08-13 19:39:05 +00:00
if ( dut . hart . priv . csr . genblk1 . csrs . genblk1 . STVAL_REGW ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin
$display ( " CSR: %s = %016x, does not equal expected value %016x " , ExpectedCSRArrayW [ NumCSRPostWIndex ] , dut . hart . priv . csr . genblk1 . csrs . genblk1 . STVAL_REGW , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ;
2021-07-30 01:26:50 +00:00
fault = 1 ;
end
end
endcase
end
2021-08-13 19:39:05 +00:00
end
2021-07-30 01:26:50 +00:00
if ( fault = = 1 ) begin
`ERROR
end
2021-08-13 19:39:05 +00:00
end // if (checkInstrW)
end // always @ (negedge clk)
2021-06-24 05:42:35 +00:00
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Testbench Core ///////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// --------------
// Initialization
// --------------
initial
2021-06-07 16:37:46 +00:00
begin
2021-06-24 05:42:35 +00:00
instrs = 0 ;
reset < = 1 ; # 22 ; reset < = 0 ;
end
// initial loading of memories
initial begin
2021-07-20 21:55:44 +00:00
$readmemh ( { `LINUX_TEST_VECTORS , " bootmem.txt " } , dut . uncore . bootdtim . bootdtim . RAM , 'h1000 > > 3 ) ;
2021-06-24 05:42:35 +00:00
$readmemh ( { `LINUX_TEST_VECTORS , " ram.txt " } , dut . uncore . dtim . RAM ) ;
$readmemb ( `TWO_BIT_PRELOAD , dut . hart . ifu . bpred . bpred . Predictor . DirPredictor . PHT . memory ) ;
$readmemb ( `BTB_PRELOAD , dut . hart . ifu . bpred . bpred . TargetPredictor . memory . memory ) ;
end
// -------
// Running
// -------
always
begin
clk < = 1 ; # 5 ; clk < = 0 ; # 5 ;
end
2021-06-07 16:37:46 +00:00
2021-07-19 19:13:03 +00:00
2021-06-07 16:37:46 +00:00
2021-06-24 05:42:35 +00:00
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Miscellaneous ///////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Instr Opcode Tracking
// For waveview convenience
string InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ;
logic [ 31 : 0 ] InstrW ;
2021-07-30 19:24:50 +00:00
instrTrackerTB it ( clk , reset , dut . hart . ieu . dp . FlushE ,
2021-06-24 05:42:35 +00:00
dut . hart . ifu . icache . controller . FinalInstrRawF ,
dut . hart . ifu . InstrD , dut . hart . ifu . InstrE ,
dut . hart . ifu . InstrM , dut . hart . ifu . InstrW ,
InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ) ;
2021-06-07 16:37:46 +00:00
2021-06-24 05:42:35 +00:00
// ------------------
// Address Translator
// ------------------
/ * *
* Walk the page table stored in dtim according to sv39 logic and translate a
* virtual address to a physical address .
*
* See section 4.3 .2 of the RISC - V Privileged specification for a full
* explanation of the below algorithm .
*/
2021-07-21 23:47:13 +00:00
logic SvMode , PTE_R , PTE_X ;
logic [ `XLEN - 1 : 0 ] SATP , PTE ;
logic [ 55 : 0 ] BaseAdr , PAdr ;
logic [ 8 : 0 ] VPN [ 2 : 0 ] ;
logic [ 11 : 0 ] Offset ;
2021-06-24 05:42:35 +00:00
function logic [ `XLEN - 1 : 0 ] adrTranslator (
input logic [ `XLEN - 1 : 0 ] adrIn ) ;
begin
int i ;
// Grab the SATP register from privileged unit
SATP = dut . hart . priv . csr . SATP_REGW ;
// Split the virtual address into page number segments and offset
VPN [ 2 ] = adrIn [ 38 : 30 ] ;
VPN [ 1 ] = adrIn [ 29 : 21 ] ;
VPN [ 0 ] = adrIn [ 20 : 12 ] ;
Offset = adrIn [ 11 : 0 ] ;
// We do not support sv48; only sv39
SvMode = SATP [ 63 ] ;
// Only perform translation if translation is on and the processor is not
// in machine mode
if ( SvMode & & ( dut . hart . priv . PrivilegeModeW ! = `M_MODE ) ) begin
BaseAdr = SATP [ 43 : 0 ] < < 12 ;
for ( i = 2 ; i > = 0 ; i - - ) begin
PAdr = BaseAdr + ( VPN [ i ] < < 3 ) ;
// dtim.RAM is 64-bit addressed. PAdr specifies a byte. We right shift
// by 3 (the PTE size) to get the requested 64-bit PTE.
PTE = dut . uncore . dtim . RAM [ PAdr > > 3 ] ;
PTE_R = PTE [ 1 ] ;
PTE_X = PTE [ 3 ] ;
if ( PTE_R | | PTE_X ) begin
// Leaf page found
break ;
end else begin
// Go to next level of table
BaseAdr = PTE [ 53 : 10 ] < < 12 ;
2021-06-07 16:37:46 +00:00
end
end
2021-06-24 05:42:35 +00:00
// Determine which parts of the PTE page number to use based on the
// level of the page table we reached.
if ( i = = 2 ) begin
// Gigapage
assign adrTranslator = { 8 'b0 , PTE [ 53 : 28 ] , VPN [ 1 ] , VPN [ 0 ] , Offset } ;
end else if ( i = = 1 ) begin
// Megapage
assign adrTranslator = { 8 'b0 , PTE [ 53 : 19 ] , VPN [ 0 ] , Offset } ;
end else begin
// Kilopage
assign adrTranslator = { 8 'b0 , PTE [ 53 : 10 ] , Offset } ;
end
end else begin
// Direct translation if address translation is not on
assign adrTranslator = adrIn ;
2021-06-07 16:37:46 +00:00
end
end
2021-06-24 05:42:35 +00:00
endfunction
endmodule
2021-06-07 16:37:46 +00:00