2021-06-07 16:37:46 +00:00
///////////////////////////////////////////
// testbench-linux.sv
//
// Written: nboorstin@g.hmc.edu 2021
// Modified:
//
2022-02-02 20:28:21 +00:00
// Purpose: Testbench for Buildroot Linux
2021-06-07 16:37:46 +00:00
//
// 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-06-07 16:37:46 +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-06-07 16:37:46 +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.
////////////////////////////////////////////////////////////////////////////////////////////////
2021-06-07 16:37:46 +00:00
`include " wally-config.vh "
2022-06-02 19:45:21 +00:00
`define DEBUG_TRACE 0
2022-06-02 19:43:59 +00:00
// Debug Levels
// 0: don't check against QEMU
// 1: print disagreements with QEMU, but only halt on PCW disagreements
// 2: halt on any disagreement with QEMU except CSRs
// 3: halt on all disagreements with QEMU
// 4: print memory accesses whenever they happen
// 5: print everything
2022-01-05 16:25:08 +00:00
module testbench ;
2021-10-25 17:04:30 +00:00
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// CONFIG ////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
2022-04-08 19:32:30 +00:00
// Recommend setting all of these in 'do' script using -G option
2021-10-25 19:25:32 +00:00
parameter INSTR_LIMIT = 0 ; // # of instructions at which to stop
parameter INSTR_WAVEON = 0 ; // # of instructions at which to turn on waves in graphical sim
parameter CHECKPOINT = 0 ;
2022-03-01 03:11:43 +00:00
parameter RISCV_DIR = " /opt/riscv " ;
2022-05-21 01:42:38 +00:00
parameter NO_SPOOFING = 0 ;
2022-05-28 10:35:17 +00:00
2022-04-10 18:27:54 +00:00
2021-06-07 16:37:46 +00:00
2021-12-07 21:12:06 +00:00
2021-06-07 16:37:46 +00:00
2022-04-08 19:32:30 +00:00
2022-06-02 19:43:59 +00:00
2022-04-08 19:32:30 +00:00
////////////////////////////////////////////////////////////////////////////////////
//////////////////////// SIGNAL / VAR / MACRO DECLARATIONS /////////////////////////
////////////////////////////////////////////////////////////////////////////////////
// ========== Testbench Core ==========
2021-06-24 05:42:35 +00:00
integer warningCount = 0 ;
2021-09-04 23:49:26 +00:00
integer errorCount = 0 ;
2021-10-25 17:04:30 +00:00
integer fault ;
string ProgramAddrMapFile , ProgramLabelMapFile ;
2022-04-08 19:32:30 +00:00
// ========== Initialization ==========
2022-03-01 03:11:43 +00:00
string testvectorDir ;
string linuxImageDir ;
2022-04-08 19:32:30 +00:00
integer memFile ;
integer readResult ;
// ========== Checkpointing ==========
2021-10-25 19:25:32 +00:00
string checkpointDir ;
logic [ 1 : 0 ] initPriv ;
2022-04-08 19:32:30 +00:00
// ========== Trace parsing & checking ==========
integer garbageInt ;
string garbageString ;
2021-11-03 04:19:12 +00:00
`define DECLARE_TRACE_SCANNER_SIGNALS(STAGE) \
integer traceFile ` `STAGE ; \
integer matchCount ` `STAGE ; \
string line ` `STAGE ; \
string token ` `STAGE ; \
string ExpectedTokens ` `STAGE [ 31 : 0 ] ; \
integer index ` `STAGE ; \
integer StartIndex ` `STAGE , EndIndex ` `STAGE ; \
integer TokenIndex ` `STAGE ; \
integer MarkerIndex ` `STAGE ; \
integer NumCSR ` `STAGE ; \
logic [ `XLEN - 1 : 0 ] ExpectedPC ` `STAGE ; \
logic [ 31 : 0 ] ExpectedInstr ` `STAGE ; \
string text ` `STAGE ; \
string MemOp ` `STAGE ; \
string RegWrite ` `STAGE ; \
integer ExpectedRegAdr ` `STAGE ; \
logic [ `XLEN - 1 : 0 ] ExpectedRegValue ` `STAGE ; \
2021-12-20 00:24:40 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedIEUAdr ` `STAGE , ExpectedMemReadData ` `STAGE , ExpectedMemWriteData ` `STAGE ; \
2021-11-03 04:19:12 +00:00
string ExpectedCSRArray ` `STAGE [ 10 : 0 ] ; \
2022-05-21 01:42:38 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedCSRArrayValue ` `STAGE [ 10 : 0 ] ; // *** might be redundant?
2021-11-03 04:19:12 +00:00
`DECLARE_TRACE_SCANNER_SIGNALS ( E )
`DECLARE_TRACE_SCANNER_SIGNALS ( M )
2022-04-08 19:32:30 +00:00
// M-stage expected values
2021-10-25 17:04:30 +00:00
logic checkInstrM ;
2022-03-23 02:28:34 +00:00
integer MIPexpected , SIPexpected ;
2021-11-03 04:19:12 +00:00
string name ;
2021-10-25 17:04:30 +00:00
logic [ `AHBW - 1 : 0 ] readDataExpected ;
2022-04-08 19:32:30 +00:00
// W-stage expected values
2021-10-25 17:04:30 +00:00
logic checkInstrW ;
2021-08-06 21:06:50 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedPCW ;
2021-09-04 23:49:26 +00:00
logic [ 31 : 0 ] ExpectedInstrW ;
string textW ;
string RegWriteW ;
integer ExpectedRegAdrW ;
2021-08-06 21:06:50 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedRegValueW ;
2021-09-04 23:49:26 +00:00
string MemOpW ;
2021-12-20 00:24:40 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedIEUAdrW , ExpectedMemReadDataW , ExpectedMemWriteDataW ;
2021-09-04 23:49:26 +00:00
integer NumCSRW ;
string ExpectedCSRArrayW [ 10 : 0 ] ;
2021-08-15 16:13:32 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedCSRArrayValueW [ 10 : 0 ] ;
2021-08-13 19:39:05 +00:00
logic [ `XLEN - 1 : 0 ] ExpectedIntType ;
2021-09-04 23:49:26 +00:00
integer NumCSRWIndex ;
2021-09-22 16:33:11 +00:00
integer NumCSRPostWIndex ;
2021-08-23 17:24:03 +00:00
logic [ `XLEN - 1 : 0 ] InstrCountW ;
2022-04-08 19:32:30 +00:00
// ========== Interrupt parsing & spoofing ==========
string interrupt ;
string interruptLine ;
integer interruptFile ;
integer interruptInstrCount ;
integer interruptHartVal ;
integer interruptAsyncVal ;
longint interruptCauseVal ;
longint interruptEpcVal ;
longint interruptTVal ;
string interruptDesc ;
integer NextMIPexpected , NextSIPexpected ;
integer NextMepcExpected ;
2022-03-26 21:28:57 +00:00
logic [ `XLEN - 1 : 0 ] AttemptedInstructionCount ;
2022-04-08 19:32:30 +00:00
// ========== Misc Aliases ==========
`define RF dut.core.ieu.dp.regf.rf
`define PC dut.core.ifu.pcreg.q
2022-04-08 20:45:27 +00:00
`define PRIV_BASE dut.core.priv.priv
2022-05-12 16:16:42 +00:00
`define PRIV `PRIV_BASE.privmode.privmode.privmodereg.q
2022-04-08 20:45:27 +00:00
`define CSR_BASE `PRIV_BASE.csr
2022-05-11 14:41:55 +00:00
`define MEIP `PRIV_BASE.MExtInt
`define SEIP `PRIV_BASE.SExtInt
2022-05-11 15:08:33 +00:00
`define MTIP `PRIV_BASE.MTimerInt
2021-12-30 20:55:48 +00:00
`define HPMCOUNTER `CSR_BASE.counters.counters.HPMCOUNTER_REGW
2021-12-30 03:01:21 +00:00
`define MEDELEG `CSR_BASE.csrm.deleg.MEDELEGreg.q
`define MIDELEG `CSR_BASE.csrm.deleg.MIDELEGreg.q
2022-05-12 15:10:10 +00:00
`define MIE `CSR_BASE.csri.MIE_REGW
`define MIP `CSR_BASE.csri.MIP_REGW_writeable
2021-10-25 17:04:30 +00:00
`define MCAUSE `CSR_BASE.csrm.MCAUSEreg.q
2021-12-30 20:55:48 +00:00
`define SCAUSE `CSR_BASE.csrs.csrs.SCAUSEreg.q
2021-10-25 17:04:30 +00:00
`define MEPC `CSR_BASE.csrm.MEPCreg.q
2021-12-30 20:55:48 +00:00
`define SEPC `CSR_BASE.csrs.csrs.SEPCreg.q
2023-01-14 05:25:55 +00:00
`define MCOUNTEREN `CSR_BASE.csrm.mcounteren.MCOUNTERENreg.q
2022-02-02 20:28:21 +00:00
`define SCOUNTEREN `CSR_BASE.csrs.csrs.SCOUNTERENreg.q
2021-10-25 17:04:30 +00:00
`define MSCRATCH `CSR_BASE.csrm.MSCRATCHreg.q
2023-01-17 21:43:39 +00:00
`define SSCRATCH `CSR_BASE.csrs.csrs.SSCRATCHreg.q
2021-10-25 17:04:30 +00:00
`define MTVEC `CSR_BASE.csrm.MTVECreg.q
2021-12-30 20:55:48 +00:00
`define STVEC `CSR_BASE.csrs.csrs.STVECreg.q
`define SATP `CSR_BASE.csrs.csrs.genblk1.SATPreg.q
2022-04-08 19:32:30 +00:00
`define INSTRET `CSR_BASE.counters.counters.HPMCOUNTER_REGW[2]
2021-10-25 17:04:30 +00:00
`define MSTATUS `CSR_BASE.csrsr.MSTATUS_REGW
2022-03-23 02:28:34 +00:00
`define SSTATUS `CSR_BASE.csrsr.SSTATUS_REGW
2021-10-25 17:04:30 +00:00
`define STATUS_TSR `CSR_BASE.csrsr.STATUS_TSR_INT
`define STATUS_TW `CSR_BASE.csrsr.STATUS_TW_INT
`define STATUS_TVM `CSR_BASE.csrsr.STATUS_TVM_INT
`define STATUS_MXR `CSR_BASE.csrsr.STATUS_MXR_INT
`define STATUS_SUM `CSR_BASE.csrsr.STATUS_SUM_INT
`define STATUS_MPRV `CSR_BASE.csrsr.STATUS_MPRV_INT
`define STATUS_FS `CSR_BASE.csrsr.STATUS_FS_INT
`define STATUS_MPP `CSR_BASE.csrsr.STATUS_MPP
`define STATUS_SPP `CSR_BASE.csrsr.STATUS_SPP
`define STATUS_MPIE `CSR_BASE.csrsr.STATUS_MPIE
`define STATUS_SPIE `CSR_BASE.csrsr.STATUS_SPIE
`define STATUS_MIE `CSR_BASE.csrsr.STATUS_MIE
`define STATUS_SIE `CSR_BASE.csrsr.STATUS_SIE
2022-08-25 15:35:24 +00:00
`define UART dut.uncore.uncore.uart.uart.u
2022-04-08 19:32:30 +00:00
`define UART_IER `UART.IER
`define UART_LCR `UART.LCR
`define UART_MCR `UART.MCR
`define UART_SCR `UART.SCR
2022-04-13 10:37:53 +00:00
`define UART_IP `UART.INTR
2022-08-25 15:35:24 +00:00
`define PLIC dut.uncore.uncore.plic.plic
2022-03-08 07:48:47 +00:00
`define PLIC_INT_PRIORITY `PLIC.intPriority
`define PLIC_INT_ENABLE `PLIC.intEn
`define PLIC_THRESHOLD `PLIC.intThreshold
2022-04-08 19:32:30 +00:00
`define PCM dut.core.ifu.PCM
// ========== COMMON MACROS ==========
// Needed for initialization and core
`define SCAN_NEW_INTERRUPT \
2021-09-22 16:33:11 +00:00
begin \
2022-04-08 19:32:30 +00:00
$fgets ( interruptLine , interruptFile ) ; \
/ / $display ( " Time %t, interruptLine %x " , $time , interruptLine ) ; \
$fgets ( interruptLine , interruptFile ) ; \
$sscanf ( interruptLine , " %d " , interruptInstrCount ) ; \
$fgets ( interruptLine , interruptFile ) ; \
$sscanf ( interruptLine , " %d " , interruptHartVal ) ; \
$fgets ( interruptLine , interruptFile ) ; \
$sscanf ( interruptLine , " %d " , interruptAsyncVal ) ; \
$fgets ( interruptLine , interruptFile ) ; \
$sscanf ( interruptLine , " %x " , interruptCauseVal ) ; \
$fgets ( interruptLine , interruptFile ) ; \
$sscanf ( interruptLine , " %x " , interruptEpcVal ) ; \
$fgets ( interruptLine , interruptFile ) ; \
$sscanf ( interruptLine , " %x " , interruptTVal ) ; \
$fgets ( interruptLine , interruptFile ) ; \
$sscanf ( interruptLine , " %s " , interruptDesc ) ; \
end
2022-04-10 18:41:27 +00:00
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////// Cache Issue ///////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
logic probe ;
2022-05-21 01:42:38 +00:00
if ( NO_SPOOFING )
2022-04-10 18:41:27 +00:00
assign probe = testbench . dut . core . PCM = = 64 'hffffffff80200c8c
& testbench . dut . core . InstrM ! = 32 'h14021273
& testbench . dut . core . InstrValidM ;
2022-04-08 19:32:30 +00:00
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////// HARDWARE ///////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Clock and Reset
logic clk , reset_ext ;
logic reset ;
initial begin reset_ext < = 1 ; # 22 ; reset_ext < = 0 ; end
always begin clk < = 1 ; # 5 ; clk < = 0 ; # 5 ; end
// Wally Interface
logic [ `AHBW - 1 : 0 ] HRDATAEXT ;
logic HREADYEXT , HRESPEXT ;
logic HCLK , HRESETn ;
logic HREADY ;
logic HSELEXT ;
2022-08-25 20:11:36 +00:00
logic [ `PA_BITS - 1 : 0 ] HADDR ;
2022-04-08 19:32:30 +00:00
logic [ `AHBW - 1 : 0 ] HWDATA ;
2022-08-25 10:39:57 +00:00
logic [ `XLEN / 8 - 1 : 0 ] HWSTRB ;
2022-04-08 19:32:30 +00:00
logic HWRITE ;
logic [ 2 : 0 ] HSIZE ;
logic [ 2 : 0 ] HBURST ;
logic [ 3 : 0 ] HPROT ;
logic [ 1 : 0 ] HTRANS ;
logic HMASTLOCK ;
2023-03-24 23:55:43 +00:00
logic [ 31 : 0 ] GPIOIN ;
logic [ 31 : 0 ] GPIOOUT , GPIOEN ;
2022-04-08 19:32:30 +00:00
logic UARTSin , UARTSout ;
// FPGA-specific Stuff
logic SDCCLK ;
logic SDCCmdIn ;
logic SDCCmdOut ;
logic SDCCmdOE ;
logic [ 3 : 0 ] SDCDatIn ;
// Hardwire UART, GPIO pins
2023-03-24 23:55:43 +00:00
assign GPIOIN = 0 ;
2022-04-08 19:32:30 +00:00
assign UARTSin = 1 ;
// Wally
wallypipelinedsoc dut ( . clk , . reset , . reset_ext ,
. HRDATAEXT , . HREADYEXT , . HREADY , . HSELEXT , . HRESPEXT , . HCLK ,
2022-08-25 10:39:57 +00:00
. HRESETn , . HADDR , . HWDATA , . HWRITE , . HWSTRB , . HSIZE , . HBURST , . HPROT ,
2022-04-08 19:32:30 +00:00
. HTRANS , . HMASTLOCK ,
2023-03-24 23:55:43 +00:00
. TIMECLK ( '0 ) , . GPIOIN , . GPIOOUT , . GPIOEN ,
2022-04-08 19:32:30 +00:00
. UARTSin , . UARTSout ,
. SDCCLK , . SDCCmdIn , . SDCCmdOut , . SDCCmdOE , . SDCDatIn ) ;
// W-stage hardware not needed by Wally itself
parameter nop = 'h13 ;
logic [ `XLEN - 1 : 0 ] PCW ;
logic [ 31 : 0 ] InstrW ;
logic InstrValidW ;
logic [ `XLEN - 1 : 0 ] IEUAdrW , WriteDataW ;
logic TrapW ;
`define FLUSHW dut.core.FlushW
`define STALLW dut.core.StallW
flopenrc # ( `XLEN ) PCWReg ( clk , reset , `FLUSHW , ~ `STALLW , `PCM , PCW ) ;
flopenr # ( 32 ) InstrWReg ( clk , reset , ~ `STALLW , `FLUSHW ? nop : dut . core . ifu . InstrM , InstrW ) ;
flopenrc # ( 1 ) controlregW ( clk , reset , `FLUSHW , ~ `STALLW , dut . core . ieu . c . InstrValidM , InstrValidW ) ;
flopenrc # ( `XLEN ) IEUAdrWReg ( clk , reset , `FLUSHW , ~ `STALLW , dut . core . IEUAdrM , IEUAdrW ) ;
flopenrc # ( `XLEN ) WriteDataWReg ( clk , reset , `FLUSHW , ~ `STALLW , dut . core . lsu . WriteDataM , WriteDataW ) ;
flopenr # ( 1 ) TrapWReg ( clk , reset , ~ `STALLW , dut . core . hzu . TrapM , TrapW ) ;
2021-09-22 16:33:11 +00:00
2021-10-25 17:04:30 +00:00
///////////////////////////////////////////////////////////////////////////////
/////////////////////////////// INITIALIZATION ////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
2022-04-08 19:32:30 +00:00
// ========== CHECKPOINTING ==========
2021-10-25 19:25:32 +00:00
`define MAKE_CHECKPOINT_INIT_SIGNAL(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \
logic DIM init ` `SIGNAL [ ARRAY_MAX: ARRAY_MIN ] ; \
initial begin \
# 1 ; \
if ( CHECKPOINT ! = 0 ) $readmemh ( { checkpointDir , " checkpoint- " , ` " SIGNAL` " } , init ` `SIGNAL ) ; \
end
`define INIT_CHECKPOINT_SIMPLE_ARRAY(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \
`MAKE_CHECKPOINT_INIT_SIGNAL ( SIGNAL , DIM , ARRAY_MAX , ARRAY_MIN ) \
initial begin \
if ( CHECKPOINT ! = 0 ) begin \
force `SIGNAL = init ` `SIGNAL [ ARRAY_MAX: ARRAY_MIN ] ; \
2021-10-25 20:26:44 +00:00
while ( reset ! = = 1 ) # 1 ; \
while ( reset ! = = 0 ) # 1 ; \
# 1 ; \
2021-10-25 19:25:32 +00:00
release `SIGNAL ; \
end \
end
2022-03-25 01:02:22 +00:00
`define INIT_CHECKPOINT_PACKED_ARRAY(SIGNAL,DIM,ARRAY_MAX,ARRAY_MIN) \
`MAKE_CHECKPOINT_INIT_SIGNAL ( SIGNAL , DIM , ARRAY_MAX , ARRAY_MIN ) \
for ( i = ARRAY_MIN ; i < ARRAY_MAX + 1 ; i = i + 1 ) begin \
initial begin \
if ( CHECKPOINT ! = 0 ) begin \
force `SIGNAL [ i ] = init ` `SIGNAL [ i ] ; \
while ( reset ! = = 1 ) # 1 ; \
while ( reset ! = = 0 ) # 1 ; \
# 1 ; \
release `SIGNAL [ i ] ; \
end \
end \
end
2021-10-25 19:25:32 +00:00
// Note that dimension usage is very intentional here.
// We are dancing around (un)packed type requirements.
`define INIT_CHECKPOINT_VAL(SIGNAL,DIM) \
`MAKE_CHECKPOINT_INIT_SIGNAL ( SIGNAL , DIM , 0 , 0 ) \
initial begin \
if ( CHECKPOINT ! = 0 ) begin \
force `SIGNAL = init ` `SIGNAL [ 0 ] ; \
2021-10-25 20:26:44 +00:00
while ( reset ! = = 1 ) # 1 ; \
while ( reset ! = = 0 ) # 1 ; \
# 1 ; \
2021-10-25 19:25:32 +00:00
release `SIGNAL ; \
end \
end
2022-06-02 02:51:51 +00:00
// Initializing all zeroes into the branch predictor memory.
genvar adrindex ;
for ( adrindex = 0 ; adrindex < 1024 ; adrindex + + ) begin
initial begin
force dut . core . ifu . bpred . bpred . Predictor . DirPredictor . PHT . mem [ adrindex ] = 0 ;
force dut . core . ifu . bpred . bpred . TargetPredictor . memory . mem [ adrindex ] = 0 ;
# 1 ;
release dut . core . ifu . bpred . bpred . Predictor . DirPredictor . PHT . mem [ adrindex ] ;
release dut . core . ifu . bpred . bpred . TargetPredictor . memory . mem [ adrindex ] ;
end
end
2022-03-25 01:02:22 +00:00
genvar i ;
2021-10-25 19:25:32 +00:00
`INIT_CHECKPOINT_SIMPLE_ARRAY ( RF , [ `XLEN - 1 : 0 ] , 31 , 1 ) ;
2022-01-06 04:19:36 +00:00
`INIT_CHECKPOINT_SIMPLE_ARRAY ( HPMCOUNTER , [ `XLEN - 1 : 0 ] , `COUNTERS - 1 , 0 ) ;
2021-10-25 19:25:32 +00:00
`INIT_CHECKPOINT_VAL ( PC , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( MEDELEG , [ `XLEN - 1 : 0 ] ) ;
2021-11-06 10:44:23 +00:00
`INIT_CHECKPOINT_VAL ( MIDELEG , [ `XLEN - 1 : 0 ] ) ;
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING ) begin
2022-04-10 18:27:54 +00:00
`INIT_CHECKPOINT_VAL ( MIE , [ 11 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( MIP , [ 11 : 0 ] ) ;
2022-04-10 18:41:27 +00:00
end
2021-10-25 19:25:32 +00:00
`INIT_CHECKPOINT_VAL ( MCAUSE , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( SCAUSE , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( MEPC , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( SEPC , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( MCOUNTEREN , [ 31 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( SCOUNTEREN , [ 31 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( MSCRATCH , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( SSCRATCH , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( MTVEC , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( STVEC , [ `XLEN - 1 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( SATP , [ `XLEN - 1 : 0 ] ) ;
2021-11-15 22:49:00 +00:00
`INIT_CHECKPOINT_VAL ( PRIV , [ 1 : 0 ] ) ;
2022-04-08 19:32:30 +00:00
`INIT_CHECKPOINT_PACKED_ARRAY ( PLIC_INT_PRIORITY , [ 2 : 0 ] , `PLIC_NUM_SRC , 1 ) ;
2022-04-13 10:37:53 +00:00
`MAKE_CHECKPOINT_INIT_SIGNAL ( PLIC_INT_ENABLE , [ `PLIC_NUM_SRC : 0 ] , 1 , 0 ) ;
2022-04-08 19:32:30 +00:00
`INIT_CHECKPOINT_PACKED_ARRAY ( PLIC_THRESHOLD , [ 2 : 0 ] , 1 , 0 ) ;
// UART checkpointing does not cover entire UART state
// Many UART registers are difficult to initialize because under the hood
// they are not simple registers. Instead some are generated by interesting
// combinational blocks such that they depend upon a variety of different
// underlying flops. See for example how RBR might be the actual RXBR
// register, but it could also just as well be 0 or the tail of the fifo
// array.
2022-03-08 07:48:47 +00:00
`INIT_CHECKPOINT_VAL ( UART_IER , [ 7 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( UART_LCR , [ 7 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( UART_MCR , [ 4 : 0 ] ) ;
`INIT_CHECKPOINT_VAL ( UART_SCR , [ 7 : 0 ] ) ;
2022-04-08 19:32:30 +00:00
// xSTATUS need to be handled manually because the most upstream signals
// are made of individual bits, not registers
`MAKE_CHECKPOINT_INIT_SIGNAL ( MSTATUS , [ `XLEN - 1 : 0 ] , 0 , 0 ) ;
`MAKE_CHECKPOINT_INIT_SIGNAL ( SSTATUS , [ `XLEN - 1 : 0 ] , 0 , 0 ) ;
2021-10-25 19:25:32 +00:00
2022-04-08 19:32:30 +00:00
// ========== INITIALIZATION ==========
2021-07-30 01:26:50 +00:00
initial begin
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING ) begin
2022-04-10 18:41:27 +00:00
force `MEIP = 0 ;
force `SEIP = 0 ;
2022-04-13 10:37:53 +00:00
force `UART_IP = 0 ;
2022-04-10 18:41:27 +00:00
force `MTIP = 0 ;
end
2022-03-01 03:11:43 +00:00
$sformat ( testvectorDir , " %s/linux-testvectors/ " , RISCV_DIR ) ;
$sformat ( linuxImageDir , " %s/buildroot/output/images/ " , RISCV_DIR ) ;
2022-03-02 16:00:19 +00:00
if ( CHECKPOINT ! = 0 )
$sformat ( checkpointDir , " %s/linux-testvectors/checkpoint%0d/ " , RISCV_DIR , CHECKPOINT ) ;
2022-03-08 04:04:08 +00:00
ProgramAddrMapFile = { linuxImageDir , " disassembly/vmlinux.objdump.addr " } ;
ProgramLabelMapFile = { linuxImageDir , " disassembly/vmlinux.objdump.lab " } ;
2022-03-01 03:11:43 +00:00
// initialize bootrom
memFile = $fopen ( { testvectorDir , " bootmem.bin " } , " rb " ) ;
2022-08-25 15:35:24 +00:00
readResult = $fread ( dut . uncore . uncore . bootrom . bootrom . memory . ROM , memFile ) ;
2022-03-01 03:11:43 +00:00
$fclose ( memFile ) ;
2022-08-25 00:23:08 +00:00
// initialize RAM and ROM
2022-03-02 16:00:19 +00:00
if ( CHECKPOINT = = 0 )
memFile = $fopen ( { testvectorDir , " ram.bin " } , " rb " ) ;
else
memFile = $fopen ( { checkpointDir , " ram.bin " } , " rb " ) ;
2022-08-25 15:35:24 +00:00
readResult = $fread ( dut . uncore . uncore . ram . ram . memory . RAM , memFile ) ;
2022-03-01 03:11:43 +00:00
$fclose ( memFile ) ;
2022-04-08 19:32:30 +00:00
// ---------- Ground-Zero -----------
if ( CHECKPOINT = = 0 ) begin
2022-03-01 03:11:43 +00:00
traceFileM = $fopen ( { testvectorDir , " all.txt " } , " r " ) ;
traceFileE = $fopen ( { testvectorDir , " all.txt " } , " r " ) ;
2022-04-08 19:32:30 +00:00
interruptFile = $fopen ( { testvectorDir , " interrupts.txt " } , " r " ) ;
`SCAN_NEW_INTERRUPT
2021-10-24 13:47:35 +00:00
InstrCountW = '0 ;
2022-04-27 17:45:40 +00:00
AttemptedInstructionCount = 1 ; // offset needed here when running from ground zero
2022-04-08 19:32:30 +00:00
// ---------- Checkpoint ----------
end else begin
2022-08-25 15:35:24 +00:00
//$readmemh({checkpointDir,"ram.txt"}, dut.uncore.uncore.ram.ram.memory.RAM);
2021-11-03 04:19:12 +00:00
traceFileE = $fopen ( { checkpointDir , " all.txt " } , " r " ) ;
traceFileM = $fopen ( { checkpointDir , " all.txt " } , " r " ) ;
2022-04-08 19:32:30 +00:00
interruptFile = $fopen ( { testvectorDir , " interrupts.txt " } , " r " ) ;
`SCAN_NEW_INTERRUPT
while ( interruptInstrCount < CHECKPOINT ) begin
`SCAN_NEW_INTERRUPT
end
2021-10-25 19:25:32 +00:00
InstrCountW = CHECKPOINT ;
2022-03-26 21:28:57 +00:00
AttemptedInstructionCount = CHECKPOINT ;
2022-04-08 19:32:30 +00:00
// manual checkpoint initializations
2021-10-25 19:25:32 +00:00
force { `STATUS_TSR , `STATUS_TW , `STATUS_TVM , `STATUS_MXR , `STATUS_SUM , `STATUS_MPRV } = initMSTATUS [ 0 ] [ 22 : 17 ] ;
force { `STATUS_FS , `STATUS_MPP } = initMSTATUS [ 0 ] [ 14 : 11 ] ;
force { `STATUS_SPP , `STATUS_MPIE } = initMSTATUS [ 0 ] [ 8 : 7 ] ;
2022-04-25 14:49:00 +00:00
// force {`STATUS_SPIE,`STATUS_UPIE,`STATUS_MIE} = initMSTATUS[0][5:3]; // dh removed UPIE and UIE 4/25/22 from depricated n-mode
force { `STATUS_SPIE } = initMSTATUS [ 0 ] [ 5 ] ;
force { `STATUS_MIE } = initMSTATUS [ 0 ] [ 3 ] ;
force { `STATUS_SIE } = initMSTATUS [ 0 ] [ 1 ] ;
2022-04-13 10:37:53 +00:00
force `PLIC_INT_ENABLE = { initPLIC_INT_ENABLE [ 1 ] [ `PLIC_NUM_SRC : 1 ] , initPLIC_INT_ENABLE [ 0 ] [ `PLIC_NUM_SRC : 1 ] } ; // would need to expand into a generate loop to cover an arbitrary number of contexts
2021-10-25 19:25:32 +00:00
force `INSTRET = CHECKPOINT ;
2021-10-25 20:26:44 +00:00
while ( reset ! = = 1 ) # 1 ;
while ( reset ! = = 0 ) # 1 ;
# 1 ;
2021-10-25 19:25:32 +00:00
release { `STATUS_TSR , `STATUS_TW , `STATUS_TVM , `STATUS_MXR , `STATUS_SUM , `STATUS_MPRV } ;
release { `STATUS_FS , `STATUS_MPP } ;
release { `STATUS_SPP , `STATUS_MPIE } ;
2022-04-25 14:49:00 +00:00
release { `STATUS_SPIE , `STATUS_MIE } ;
release { `STATUS_SIE } ;
2022-04-13 10:37:53 +00:00
release `PLIC_INT_ENABLE ;
2021-10-25 19:25:32 +00:00
release `INSTRET ;
end
2021-11-03 04:19:12 +00:00
// Get the E-stage trace reader ahead of the M-stage trace reader
2022-05-21 01:42:38 +00:00
matchCountE = $fgets ( lineE , traceFileE ) ; // *** look at removing?
2021-07-30 01:26:50 +00:00
end
2021-10-25 17:04:30 +00:00
///////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// CORE /////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
2022-04-08 19:32:30 +00:00
// =========== TRACE PARSING MACRO ==========
2021-09-04 23:49:26 +00:00
// Because qemu does not match exactly to wally it is necessary to read the the
2021-08-06 21:06:50 +00:00
// 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-11-03 04:19:12 +00:00
`define SCAN_NEW_INSTR_FROM_TRACE(STAGE) \
/ / always check PC , instruction bits \
if ( checkInstrM ) begin \
/ / read 1 line of the trace file \
matchCount ` `STAGE = $fgets ( line ` `STAGE , traceFile ` `STAGE ) ; \
2022-06-02 19:45:21 +00:00
if ( `DEBUG_TRACE > = 5 ) $display ( " Time %t, line %x " , $time , line ` `STAGE ) ; \
2021-11-03 04:19:12 +00:00
/ / extract PC , Instr \
matchCount ` `STAGE = $sscanf ( line ` `STAGE , " %x %x %s " , ExpectedPC ` `STAGE , ExpectedInstr ` `STAGE , text ` `STAGE ) ; \
2022-04-13 07:49:37 +00:00
if ( ` " STAGE` " = = " M " ) begin \
AttemptedInstructionCount + = 1 ; \
end \
2021-11-03 04:19:12 +00:00
\
/ / for the life of me I cannot get any build in C or C + + string parsing functions / methods to work . \
/ / strtok was the best idea but it cannot be used correctly as system verilog does not have null \
/ / terminated strings . \
\
/ / Just going to do this char by char . \
StartIndex ` `STAGE = 0 ; \
TokenIndex ` `STAGE = 0 ; \
/ / $display ( " len = %d " , line ` `STAGE . len ( ) ) ; \
for ( index ` `STAGE = 0 ; index ` `STAGE < line ` `STAGE . len ( ) ; index ` `STAGE + + ) begin \
/ / $display ( " char = %s " , line ` `STAGE [ index ] ) ; \
2022-01-31 01:07:35 +00:00
if ( line ` `STAGE [ index ` `STAGE ] = = " " | line ` `STAGE [ index ` `STAGE ] = = " \n " ) begin \
2021-11-03 04:19:12 +00:00
EndIndex ` `STAGE = index ` `STAGE ; \
ExpectedTokens ` `STAGE [ TokenIndex ` `STAGE ] = line ` `STAGE . substr ( StartIndex ` `STAGE , EndIndex ` `STAGE - 1 ) ; \
/ / $display ( " In Tokenizer %s " , line ` `STAGE . substr ( StartIndex , EndIndex - 1 ) ) ; \
StartIndex ` `STAGE = EndIndex ` `STAGE + 1 ; \
TokenIndex ` `STAGE + + ; \
end \
end \
\
MarkerIndex ` `STAGE = 3 ; \
NumCSR ` `STAGE = 0 ; \
MemOp ` `STAGE = " " ; \
RegWrite ` `STAGE = " " ; \
\
# 2 ; \
\
while ( TokenIndex ` `STAGE > MarkerIndex ` `STAGE ) begin \
/ / parse the GPR \
if ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE ] = = " GPR " ) begin \
RegWrite ` `STAGE = ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE ] ; \
matchCount ` `STAGE = $sscanf ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE + 1 ] , " %d " , ExpectedRegAdr ` `STAGE ) ; \
matchCount ` `STAGE = $sscanf ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE + 2 ] , " %x " , ExpectedRegValue ` `STAGE ) ; \
MarkerIndex ` `STAGE + = 3 ; \
/ / parse memory address , read data , and / or write data \
end else if ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE ] . substr ( 0 , 2 ) = = " Mem " ) begin \
MemOp ` `STAGE = ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE ] ; \
2021-12-20 00:24:40 +00:00
matchCount ` `STAGE = $sscanf ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE + 1 ] , " %x " , ExpectedIEUAdr ` `STAGE ) ; \
2021-11-03 04:19:12 +00:00
matchCount ` `STAGE = $sscanf ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE + 2 ] , " %x " , ExpectedMemWriteData ` `STAGE ) ; \
matchCount ` `STAGE = $sscanf ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE + 3 ] , " %x " , ExpectedMemReadData ` `STAGE ) ; \
MarkerIndex ` `STAGE + = 4 ; \
/ / 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 . \
2022-01-31 01:07:35 +00:00
end else if ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE ] = = " CSR " | NumCSR ` `STAGE > 0 ) begin \
2021-11-03 04:19:12 +00:00
if ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE ] = = " CSR " ) begin \
/ / all additional CSR ' s won ' t have this token . \
MarkerIndex ` `STAGE + + ; \
end \
matchCount ` `STAGE = $sscanf ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE ] , " %s " , ExpectedCSRArray ` `STAGE [ NumCSR ` `STAGE ] ) ; \
matchCount ` `STAGE = $sscanf ( ExpectedTokens ` `STAGE [ MarkerIndex ` `STAGE + 1 ] , " %x " , ExpectedCSRArrayValue ` `STAGE [ NumCSR ` `STAGE ] ) ; \
MarkerIndex ` `STAGE + = 2 ; \
\
NumCSR ` `STAGE + + ; \
end \
end \
if ( ` " STAGE` " = = " M " ) begin \
/ / override on special conditions \
2022-09-13 16:47:39 +00:00
if ( ( dut . core . lsu . PAdrM = = 'h10000002 ) | ( dut . core . lsu . PAdrM = = 'h10000005 ) | ( dut . core . lsu . PAdrM = = 'h10000006 ) ) begin \
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING ) begin \
$display ( " %tns, %d instrs: Overwrite UART's Register in memory stage. " , $time , AttemptedInstructionCount ) ; \
2022-06-20 22:53:13 +00:00
force dut . core . lsu . ReadDataM = ExpectedMemReadDataM ; \
2022-04-17 22:49:51 +00:00
end \
2022-04-13 22:32:00 +00:00
end else \
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING ) \
2022-06-20 22:53:13 +00:00
release dut . core . lsu . ReadDataM ; \
2021-12-21 03:26:38 +00:00
if ( textM . substr ( 0 , 5 ) = = " rdtime " ) begin \
2021-12-08 22:11:43 +00:00
/ / $display ( " %tns, %d instrs: Overwrite MTIME_CLINT on read of MTIME in memory stage. " , $time , InstrCountW - 1 ) ; \
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING ) \
2022-08-25 15:35:24 +00:00
force dut . uncore . uncore . clint . clint . MTIME = ExpectedRegValueM ; \
2021-11-03 04:19:12 +00:00
end \
end \
end \
2022-04-08 19:32:30 +00:00
// ========== VALUE-CHECKING MACROS ==========
`define checkEQ(NAME, VAL, EXPECTED) \
if ( VAL ! = EXPECTED ) begin \
2022-04-13 04:22:08 +00:00
$display ( " %tns, %d instrs: %s %x differs from expected %x " , $time , AttemptedInstructionCount , NAME , VAL , EXPECTED ) ; \
2022-06-02 19:45:21 +00:00
if ( ( NAME = = " PCW " ) | ( `DEBUG_TRACE > = 2 ) ) fault = 1 ; \
2022-04-08 19:32:30 +00:00
end
`define checkCSR(CSR) \
begin \
if ( CSR ! = ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) begin \
2022-04-13 04:22:08 +00:00
$display ( " %tns, %d instrs: CSR %s = %016x, does not equal expected value %016x " , $time , AttemptedInstructionCount , ExpectedCSRArrayW [ NumCSRPostWIndex ] , CSR , ExpectedCSRArrayValueW [ NumCSRPostWIndex ] ) ; \
2022-06-02 19:45:21 +00:00
if ( `DEBUG_TRACE > = 3 ) fault = 1 ; \
2022-04-08 19:32:30 +00:00
end \
end
2021-08-13 19:39:05 +00:00
2022-04-08 19:32:30 +00:00
// =========== CORE ===========
assign checkInstrM = dut . core . ieu . InstrValidM & ~ dut . core . priv . priv . trap . InstrPageFaultM & ~ dut . core . priv . priv . trap . InterruptM & ~ dut . core . StallM ;
2021-11-03 04:19:12 +00:00
always @ ( negedge clk ) begin
2022-04-08 19:32:30 +00:00
`SCAN_NEW_INSTR_FROM_TRACE ( E )
2021-11-03 04:19:12 +00:00
`SCAN_NEW_INSTR_FROM_TRACE ( M )
end
2021-08-06 21:06:50 +00:00
// 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 ;
2021-12-20 00:24:40 +00:00
ExpectedIEUAdrW < = '0 ;
2021-08-06 21:06:50 +00:00
MemOpW < = " " ;
ExpectedMemWriteDataW < = '0 ;
ExpectedMemReadDataW < = '0 ;
NumCSRW < = '0 ;
2022-01-20 16:02:08 +00:00
end else if ( ~ dut . core . StallW ) begin
if ( dut . core . FlushW ) begin
2021-09-07 02:59:54 +00:00
ExpectedPCW < = '0 ;
ExpectedInstrW < = '0 ;
textW < = " " ;
RegWriteW < = " " ;
ExpectedRegAdrW < = '0 ;
ExpectedRegValueW < = '0 ;
2021-12-20 00:24:40 +00:00
ExpectedIEUAdrW < = '0 ;
2021-09-07 02:59:54 +00:00
MemOpW < = " " ;
ExpectedMemWriteDataW < = '0 ;
ExpectedMemReadDataW < = '0 ;
NumCSRW < = '0 ;
2022-01-20 16:02:08 +00:00
end else if ( dut . core . ieu . c . InstrValidM ) begin
2021-09-07 02:59:54 +00:00
ExpectedPCW < = ExpectedPCM ;
ExpectedInstrW < = ExpectedInstrM ;
textW < = textM ;
RegWriteW < = RegWriteM ;
ExpectedRegAdrW < = ExpectedRegAdrM ;
ExpectedRegValueW < = ExpectedRegValueM ;
2021-12-20 00:24:40 +00:00
ExpectedIEUAdrW < = ExpectedIEUAdrM ;
2021-09-07 02:59:54 +00:00
MemOpW < = MemOpM ;
ExpectedMemWriteDataW < = ExpectedMemWriteDataM ;
ExpectedMemReadDataW < = ExpectedMemReadDataM ;
NumCSRW < = NumCSRM ;
for ( NumCSRWIndex = 0 ; NumCSRWIndex < NumCSRM ; 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
# 1 ;
2021-09-22 16:33:11 +00:00
// override on special conditions
2022-01-20 16:02:08 +00:00
if ( ~ dut . core . StallW ) begin
2021-12-21 03:26:38 +00:00
if ( textW . substr ( 0 , 5 ) = = " rdtime " ) begin
2022-04-13 04:22:08 +00:00
//$display("%tns, %d instrs: Releasing force of MTIME_CLINT.", $time, AttemptedInstructionCount);
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING )
2022-08-25 15:35:24 +00:00
release dut . uncore . uncore . clint . clint . MTIME ;
2021-09-22 16:33:11 +00:00
end
2021-12-20 00:24:40 +00:00
//if (ExpectedIEUAdrM == 'h10000005) begin
2022-04-13 04:22:08 +00:00
//$display("%tns, %d instrs: releasing force of ReadDataM.", $time, AttemptedInstructionCount);
2022-01-20 16:02:08 +00:00
//release dut.core.ieu.dp.ReadDataM;
2021-12-08 22:11:43 +00:00
//end
2021-08-13 19:39:05 +00:00
end
2021-08-06 21:06:50 +00:00
end
end
// step2: make all checks in the write back stage.
2022-04-08 19:32:30 +00:00
assign checkInstrW = InstrValidW & ~ dut . core . StallW ; // trapW will already be invalid in there was an InstrPageFault in the previous instruction.
2021-08-06 21:06:50 +00:00
always @ ( negedge clk ) begin
2022-04-13 11:31:23 +00:00
# 1 ; // small delay allows interrupt spoofing to happen first
2021-08-06 21:06:50 +00:00
// always check PC, instruction bits
if ( checkInstrW ) begin
2021-08-23 17:24:03 +00:00
InstrCountW + = 1 ;
2021-09-15 21:30:59 +00:00
// print progress message
2022-04-13 04:22:08 +00:00
if ( AttemptedInstructionCount % 'd100000 = = 0 ) $display ( " Reached %d instructions " , AttemptedInstructionCount ) ;
2021-10-23 20:17:30 +00:00
// turn on waves
2022-04-13 04:22:08 +00:00
if ( AttemptedInstructionCount = = INSTR_WAVEON ) $stop ;
2021-10-23 20:17:30 +00:00
// end sim
2022-06-04 01:56:24 +00:00
if ( ( AttemptedInstructionCount = = INSTR_LIMIT ) & ( INSTR_LIMIT ! = 0 ) ) begin $stop ; $stop ; end
2021-08-06 21:06:50 +00:00
fault = 0 ;
2022-06-02 19:45:21 +00:00
if ( `DEBUG_TRACE > = 1 ) begin
2021-09-27 07:03:11 +00:00
`checkEQ ( " PCW " , PCW , ExpectedPCW )
2021-10-25 17:04:30 +00:00
//`checkEQ("InstrW",InstrW,ExpectedInstrW) <-- not viable because of
// compressed to uncompressed conversion
2022-04-18 02:45:46 +00:00
`checkEQ ( " Instr Count " , dut . core . priv . priv . csr . counters . counters . HPMCOUNTER_REGW [ 2 ] , InstrCountW )
2021-09-27 07:03:11 +00:00
# 2 ; // delay 2 ns.
2022-06-02 19:45:21 +00:00
if ( `DEBUG_TRACE > = 5 ) begin
2022-04-13 04:22:08 +00:00
$display ( " %tns, %d instrs: Reg Write Address %02d ? expected value: %02d " , $time , AttemptedInstructionCount , dut . core . ieu . dp . regf . a3 , ExpectedRegAdrW ) ;
$display ( " %tns, %d instrs: RF[%02d] %016x ? expected value: %016x " , $time , AttemptedInstructionCount , ExpectedRegAdrW , dut . core . ieu . dp . regf . rf [ ExpectedRegAdrW ] , ExpectedRegValueW ) ;
2021-09-22 16:33:11 +00:00
end
2021-09-27 07:03:11 +00:00
if ( RegWriteW = = " GPR " ) begin
2022-01-20 16:02:08 +00:00
`checkEQ ( " Reg Write Address " , dut . core . ieu . dp . regf . a3 , ExpectedRegAdrW )
2021-10-10 17:09:59 +00:00
$sformat ( name , " RF[%02d] " , ExpectedRegAdrW ) ;
2022-01-20 16:02:08 +00:00
`checkEQ ( name , dut . core . ieu . dp . regf . rf [ ExpectedRegAdrW ] , ExpectedRegValueW )
2021-09-15 21:30:59 +00:00
end
2021-09-27 07:03:11 +00:00
if ( MemOpW . substr ( 0 , 2 ) = = " Mem " ) begin
2022-06-02 19:45:21 +00:00
if ( `DEBUG_TRACE > = 4 ) $display ( " \t IEUAdrW: %016x ? expected: %016x " , IEUAdrW , ExpectedIEUAdrW ) ;
2021-12-20 00:24:40 +00:00
`checkEQ ( " IEUAdrW " , IEUAdrW , ExpectedIEUAdrW )
2022-01-31 01:07:35 +00:00
if ( MemOpW = = " MemR " | MemOpW = = " MemRW " ) begin
2022-06-02 19:45:21 +00:00
if ( `DEBUG_TRACE > = 4 ) $display ( " \t ReadDataW: %016x ? expected: %016x " , dut . core . ieu . dp . ReadDataW , ExpectedMemReadDataW ) ;
2022-01-20 16:02:08 +00:00
`checkEQ ( " ReadDataW " , dut . core . ieu . dp . ReadDataW , ExpectedMemReadDataW )
2022-01-31 01:07:35 +00:00
end else if ( MemOpW = = " MemW " | MemOpW = = " MemRW " ) begin
2022-06-02 19:45:21 +00:00
if ( `DEBUG_TRACE > = 4 ) $display ( " \t WriteDataW: %016x ? expected: %016x " , WriteDataW , ExpectedMemWriteDataW ) ;
2021-09-27 07:03:11 +00:00
`checkEQ ( " WriteDataW " , ExpectedMemWriteDataW , ExpectedMemWriteDataW )
2021-09-22 16:33:11 +00:00
end
end
2021-09-27 07:03:11 +00:00
// check csr
for ( NumCSRPostWIndex = 0 ; NumCSRPostWIndex < NumCSRW ; NumCSRPostWIndex + + ) begin
case ( ExpectedCSRArrayW [ NumCSRPostWIndex ] )
2022-04-08 20:45:27 +00:00
" mhartid " : `checkCSR ( `CSR_BASE . csrm . MHARTID_REGW )
" mstatus " : `checkCSR ( `CSR_BASE . csrm . MSTATUS_REGW )
2023-01-14 06:12:06 +00:00
" sstatus " : `checkCSR ( `CSR_BASE . csrs . csrs . SSTATUS_REGW )
2022-04-08 20:45:27 +00:00
" mtvec " : `checkCSR ( `CSR_BASE . csrm . MTVEC_REGW )
" mie " : `checkCSR ( `CSR_BASE . csrm . MIE_REGW )
" mideleg " : `checkCSR ( `CSR_BASE . csrm . MIDELEG_REGW )
" medeleg " : `checkCSR ( `CSR_BASE . csrm . MEDELEG_REGW )
" mepc " : `checkCSR ( `CSR_BASE . csrm . MEPC_REGW )
" mtval " : `checkCSR ( `CSR_BASE . csrm . MTVAL_REGW )
2023-01-14 06:12:06 +00:00
" sepc " : `checkCSR ( `CSR_BASE . csrs . csrs . SEPC_REGW )
2022-04-08 20:45:27 +00:00
" scause " : `checkCSR ( `CSR_BASE . csrs . csrs . SCAUSE_REGW )
2023-01-14 06:12:06 +00:00
" stvec " : `checkCSR ( `CSR_BASE . csrs . csrs . STVEC_REGW )
2022-04-08 20:45:27 +00:00
" stval " : `checkCSR ( `CSR_BASE . csrs . csrs . STVAL_REGW )
" mip " : begin
`checkCSR ( `CSR_BASE . csrm . MIP_REGW )
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING ) begin
2022-04-10 18:41:27 +00:00
if ( ( ExpectedCSRArrayValueW [ NumCSRPostWIndex ] & 1 < < 11 ) = = 0 )
2022-04-08 20:45:27 +00:00
force `MEIP = 0 ;
2022-04-10 18:41:27 +00:00
if ( ( ExpectedCSRArrayValueW [ NumCSRPostWIndex ] & 1 < < 09 ) = = 0 )
2022-04-08 20:45:27 +00:00
force `SEIP = 0 ;
2022-04-13 10:37:53 +00:00
if ( ( ExpectedCSRArrayValueW [ NumCSRPostWIndex ] & ( ( 1 < < 11 ) | ( 1 < < 09 ) ) ) = = 0 )
force `UART_IP = 0 ;
2022-04-10 18:41:27 +00:00
if ( ( ExpectedCSRArrayValueW [ NumCSRPostWIndex ] & 1 < < 07 ) = = 0 )
2022-04-08 20:45:27 +00:00
force `MTIP = 0 ;
2022-04-10 18:41:27 +00:00
end
2022-04-08 20:45:27 +00:00
end
2021-09-27 07:03:11 +00:00
endcase
end
if ( fault = = 1 ) begin
errorCount + = 1 ;
2022-04-13 04:22:08 +00:00
$display ( " processed %0d instructions with %0d warnings " , AttemptedInstructionCount , warningCount ) ;
2022-05-21 01:42:38 +00:00
$stop ; $stop ;
2021-09-27 07:03:11 +00:00
end
2022-06-02 19:45:21 +00:00
end // if (`DEBUG_TRACE >= 1)
2021-08-13 19:39:05 +00:00
end // if (checkInstrW)
end // always @ (negedge clk)
2021-08-24 16:08:46 +00:00
2022-04-08 19:32:30 +00:00
// New IP spoofing
2022-04-13 11:31:23 +00:00
logic globalIntsBecomeEnabled ;
2023-01-14 06:12:06 +00:00
assign globalIntsBecomeEnabled = ( `CSR_BASE . csrm . WriteMSTATUSM | | `CSR_BASE . csrs . csrs . WriteSSTATUSM ) & & ( | ( `CSR_BASE . CSRWriteValM & ( ~ `CSR_BASE . csrm . MSTATUS_REGW ) & 32 'h22 ) ) ;
2022-04-14 16:23:21 +00:00
logic checkInterruptM ;
assign checkInterruptM = dut . core . ieu . InstrValidM & ~ dut . core . priv . priv . trap . InstrPageFaultM & ~ dut . core . priv . priv . trap . InterruptM ;
2022-04-13 11:31:23 +00:00
always @ ( negedge clk ) begin
2022-04-14 16:23:21 +00:00
if ( checkInterruptM ) begin
2022-04-08 19:32:30 +00:00
if ( ( interruptInstrCount + 1 ) = = AttemptedInstructionCount ) begin
2022-05-21 01:42:38 +00:00
if ( ! NO_SPOOFING ) begin
2022-04-10 18:41:27 +00:00
case ( interruptCauseVal )
2022-04-13 10:37:53 +00:00
11 : begin
force `MEIP = 1 ;
force `UART_IP = 1 ;
end
09 : begin
force `SEIP = 1 ;
force `UART_IP = 1 ;
end
2022-04-08 20:45:27 +00:00
07 : force `MTIP = 1 ;
default : $display ( " Unsupported interrupt in interrupts.txt. cause = %0d " , interruptCauseVal ) ;
2022-04-10 18:41:27 +00:00
endcase
$display ( " Forcing interrupt. " ) ;
end
2022-04-08 19:32:30 +00:00
`SCAN_NEW_INTERRUPT
2022-04-13 11:31:23 +00:00
if ( globalIntsBecomeEnabled ) begin
2022-04-13 10:37:53 +00:00
$display ( " Enabled global interrupts " ) ;
2022-04-13 11:31:23 +00:00
// The idea here is if a CSR instruction causes an interrupt by
// enabling interrupts, that CSR instruction will commit.
2022-04-13 10:37:53 +00:00
end else begin
2022-04-13 11:31:23 +00:00
// Other instructions, however, will get interrupted and not
// commit, so we don't want our W-stage checker to look for them
// and get confused when it doesn't find them.
2022-04-13 10:37:53 +00:00
garbageInt = $fgets ( garbageString , traceFileE ) ;
garbageInt = $fgets ( garbageString , traceFileM ) ;
AttemptedInstructionCount + = 1 ;
end
2022-04-08 19:32:30 +00:00
end
end
end
2022-05-21 01:42:38 +00:00
2021-06-24 05:42:35 +00:00
2022-04-08 19:32:30 +00:00
2021-06-07 16:37:46 +00:00
2021-06-24 05:42:35 +00:00
///////////////////////////////////////////////////////////////////////////////
2021-10-25 17:04:30 +00:00
//////////////////////////////// Extra Features ///////////////////////////////
2021-06-24 05:42:35 +00:00
///////////////////////////////////////////////////////////////////////////////
2022-04-08 19:32:30 +00:00
// Function Tracking
FunctionName FunctionName ( . reset ( reset ) ,
. clk ( clk ) ,
. ProgramAddrMapFile ( ProgramAddrMapFile ) ,
. ProgramLabelMapFile ( ProgramLabelMapFile ) ) ;
2021-06-24 05:42:35 +00:00
// Instr Opcode Tracking
// For waveview convenience
string InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ;
2022-01-20 16:02:08 +00:00
instrTrackerTB it ( clk , reset , dut . core . ieu . dp . FlushE ,
2023-01-20 18:09:21 +00:00
dut . core . ifu . InstrRawF [ 31 : 0 ] ,
2022-01-20 16:02:08 +00:00
dut . core . ifu . InstrD , dut . core . ifu . InstrE ,
dut . core . ifu . InstrM , InstrW ,
2021-06-24 05:42:35 +00:00
InstrFName , InstrDName , InstrEName , InstrMName , InstrWName ) ;
2021-06-07 16:37:46 +00:00
2021-06-24 05:42:35 +00:00
// ------------------
// Address Translator
// ------------------
/ * *
2021-12-14 21:43:06 +00:00
* Walk the page table stored in ram according to sv39 logic and translate a
2021-06-24 05:42:35 +00:00
* 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
2022-01-20 16:02:08 +00:00
SATP = dut . core . priv . priv . csr . SATP_REGW ;
2021-06-24 05:42:35 +00:00
// 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
2022-01-20 16:02:08 +00:00
if ( SvMode & ( dut . core . priv . priv . PrivilegeModeW ! = `M_MODE ) ) begin
2021-06-24 05:42:35 +00:00
BaseAdr = SATP [ 43 : 0 ] < < 12 ;
for ( i = 2 ; i > = 0 ; i - - ) begin
PAdr = BaseAdr + ( VPN [ i ] < < 3 ) ;
2022-03-30 04:48:19 +00:00
// ram.memory.RAM is 64-bit addressed. PAdr specifies a byte. We right shift
2021-06-24 05:42:35 +00:00
// by 3 (the PTE size) to get the requested 64-bit PTE.
2022-08-25 15:35:24 +00:00
PTE = dut . uncore . uncore . ram . ram . memory . RAM [ PAdr > > 3 ] ;
2021-06-24 05:42:35 +00:00
PTE_R = PTE [ 1 ] ;
PTE_X = PTE [ 3 ] ;
2022-01-31 01:07:35 +00:00
if ( PTE_R | PTE_X ) begin
2021-06-24 05:42:35 +00:00
// 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