From 27f6f00402c0e50a176201ba62ee82493a3b047c Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Fri, 7 Jul 2023 18:22:28 -0500 Subject: [PATCH 1/5] Changes for xcelium. --- sim/wally.xrun | 2 ++ src/fpu/fdivsqrt/fdivsqrtfsm.sv | 2 +- src/mmu/pmpchecker.sv | 2 +- testbench/common/functionName.sv | 6 +++--- testbench/common/loggers.sv | 26 +++++++++++++++----------- testbench/common/shadowmem.sv | 8 ++++---- testbench/common/wallyTracer.sv | 2 +- testbench/testbench.sv | 2 +- 8 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 sim/wally.xrun diff --git a/sim/wally.xrun b/sim/wally.xrun new file mode 100644 index 000000000..9e20e7fee --- /dev/null +++ b/sim/wally.xrun @@ -0,0 +1,2 @@ +xrun -setenv CADENCE_ENABLE_AVSREQ_44905_PHASE_1=1 -incdir ../config/rv64gc -incdir ../config/shared -incdir ../testbench -compile ../src/cvw.sv ../testbench/testbench.sv ../testbench/common/*.sv ../src/*/*.sv ../src/*/*/*.sv +xrun -elaborate -top testbench ../testbench/testbench.sv -incdir ../config/rv64gc -incdir ../config/shared -incdir ../testbench diff --git a/src/fpu/fdivsqrt/fdivsqrtfsm.sv b/src/fpu/fdivsqrt/fdivsqrtfsm.sv index a727e5536..0e2cba90e 100644 --- a/src/fpu/fdivsqrt/fdivsqrtfsm.sv +++ b/src/fpu/fdivsqrt/fdivsqrtfsm.sv @@ -55,7 +55,7 @@ module fdivsqrtfsm import cvw::*; #(parameter cvw_t P) ( assign FDivBusyE = (state == BUSY) | IFDivStartE; // terminate immediately on special cases - assign FSpecialCaseE = XZeroE | | XInfE | XNaNE | (XsE&SqrtE) | (YZeroE | YInfE | YNaNE)&~SqrtE; + assign FSpecialCaseE = XZeroE | XInfE | XNaNE | (XsE&SqrtE) | (YZeroE | YInfE | YNaNE)&~SqrtE; if (P.IDIV_ON_FPU) assign SpecialCaseE = IntDivE ? ISpecialCaseE : FSpecialCaseE; else assign SpecialCaseE = FSpecialCaseE; flopenr #(1) SpecialCaseReg(clk, reset, IFDivStartE, SpecialCaseE, SpecialCaseM); // save SpecialCase for checking in fdivsqrtpostproc diff --git a/src/mmu/pmpchecker.sv b/src/mmu/pmpchecker.sv index fd1243031..89c22c486 100644 --- a/src/mmu/pmpchecker.sv +++ b/src/mmu/pmpchecker.sv @@ -67,7 +67,7 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) ( priorityonehot #(P.PMP_ENTRIES) pmppriority(.a(Match), .y(FirstMatch)); // combine the match signal from all the adress decoders to find the first one that matches. // Only enforce PMP checking for S and U modes or in Machine mode when L bit is set in selected region - assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | |(L & FirstMatch); // *** switch to this logic when PMP is initialized for non-machine mode + assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | (|(L & FirstMatch)); // *** switch to this logic when PMP is initialized for non-machine mode assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|(X & FirstMatch) ; assign PMPStoreAmoAccessFaultM = EnforcePMP & WriteAccessM & ~|(W & FirstMatch) ; diff --git a/testbench/common/functionName.sv b/testbench/common/functionName.sv index 90157f255..8498a425d 100644 --- a/testbench/common/functionName.sv +++ b/testbench/common/functionName.sv @@ -119,8 +119,8 @@ module FunctionName import cvw::*; #(parameter cvw_t P) ( // initial begin always @ (negedge reset) begin // clear out the old mapping between programs. - foreach(ProgramAddrMapMemory[i]) ProgramAddrMapMemory.delete(i); - foreach(ProgramLabelMapMemory[i]) ProgramLabelMapMemory.delete(i); + ProgramAddrMapMemory.delete(); + ProgramLabelMapMemory.delete(); $readmemh(ProgramAddrMapFile, ProgramAddrMapMemory); // we need to count the number of lines in the file so we can set FunctionRadixLineCount. @@ -169,7 +169,7 @@ module FunctionName import cvw::*; #(parameter cvw_t P) ( assign AnyUnknown = (OrReducedAdr === 1'bx) ? 1'b1 : 1'b0; initial ProgramAddrIndex = '0; - assign FunctionName = AnyUnknown ? "Unknown!" : ProgramLabelMapMemory[ProgramAddrIndex]; + always @(*) FunctionName = AnyUnknown ? "Unknown!" : ProgramLabelMapMemory[ProgramAddrIndex]; endmodule // function_radix diff --git a/testbench/common/loggers.sv b/testbench/common/loggers.sv index cf42fe4ec..18aa2de34 100644 --- a/testbench/common/loggers.sv +++ b/testbench/common/loggers.sv @@ -151,8 +151,10 @@ module loggers import cvw::*; #(parameter cvw_t P, $fwrite(file, "BEGIN %s\n", memfilename); end string AccessTypeString, HitMissString; - assign HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" : - dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M"; + always @(*) begin + HitMissString = dut.core.ifu.bus.icache.icache.CacheHit ? "H" : + dut.core.ifu.bus.icache.icache.vict.cacheLRU.AllValid ? "E" : "M"; + end always @(posedge clk) begin if(resetEdge) $fwrite(file, "TRAIN\n"); if(BeginSample) $fwrite(file, "BEGIN %s\n", memfilename); @@ -174,15 +176,17 @@ module loggers import cvw::*; #(parameter cvw_t P, flop #(1) ResetDReg(clk, reset, resetD); assign resetEdge = ~reset & resetD; - assign HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" : - (!dut.core.lsu.bus.dcache.dcache.vict.cacheLRU.AllValid) ? "M" : - dut.core.lsu.bus.dcache.dcache.LineDirty ? "D" : "E"; - assign AccessTypeString = dut.core.lsu.bus.dcache.FlushDCache ? "F" : - dut.core.lsu.bus.dcache.CacheAtomicM[1] ? "A" : - dut.core.lsu.bus.dcache.CacheRWM == 2'b10 ? "R" : - dut.core.lsu.bus.dcache.CacheRWM == 2'b01 ? "W" : - "NULL"; - + always @(*) begin + HitMissString = dut.core.lsu.bus.dcache.dcache.CacheHit ? "H" : + (!dut.core.lsu.bus.dcache.dcache.vict.cacheLRU.AllValid) ? "M" : + dut.core.lsu.bus.dcache.dcache.LineDirty ? "D" : "E"; + AccessTypeString = dut.core.lsu.bus.dcache.FlushDCache ? "F" : + dut.core.lsu.bus.dcache.CacheAtomicM[1] ? "A" : + dut.core.lsu.bus.dcache.CacheRWM == 2'b10 ? "R" : + dut.core.lsu.bus.dcache.CacheRWM == 2'b01 ? "W" : + "NULL"; + end + assign Enabled = dut.core.lsu.bus.dcache.dcache.cachefsm.LRUWriteEn & ~dut.core.lsu.bus.dcache.dcache.cachefsm.FlushStage & dut.core.lsu.dmmu.dmmu.pmachecker.Cacheable & diff --git a/testbench/common/shadowmem.sv b/testbench/common/shadowmem.sv index 021d4b82f..19884390d 100644 --- a/testbench/common/shadowmem.sv +++ b/testbench/common/shadowmem.sv @@ -39,10 +39,10 @@ module DCacheFlushFSM import cvw::*; #(parameter cvw_t P) logic startD; if(P.DCACHE_SUPPORTED) begin - localparam numlines = testbench.dut.core.lsu.bus.dcache.dcache.NUMLINES; - localparam numways = testbench.dut.core.lsu.bus.dcache.dcache.NUMWAYS; - localparam linebytelen = testbench.dut.core.lsu.bus.dcache.dcache.LINEBYTELEN; - localparam linelen = testbench.dut.core.lsu.bus.dcache.dcache.LINELEN; + localparam numlines = P.DCACHE_WAYSIZEINBYTES*8/P.DCACHE_LINELENINBITS; + localparam numways = P.DCACHE_NUMWAYS; + localparam linelen = P.DCACHE_LINELENINBITS; + localparam linebytelen = linelen/8; localparam sramlen = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].SRAMLEN; localparam cachesramwords = testbench.dut.core.lsu.bus.dcache.dcache.CacheWays[0].NUMSRAM; localparam numwords = sramlen/P.XLEN; diff --git a/testbench/common/wallyTracer.sv b/testbench/common/wallyTracer.sv index a1dc318ec..66accfc9f 100644 --- a/testbench/common/wallyTracer.sv +++ b/testbench/common/wallyTracer.sv @@ -163,7 +163,7 @@ module wallyTracer import cvw::*; #(parameter cvw_t P) (rvviTrace rvvi); CSRArray[12'h140] = testbench.dut.core.priv.priv.csr.csrs.csrs.SSCRATCH_REGW; CSRArray[12'h143] = testbench.dut.core.priv.priv.csr.csrs.csrs.STVAL_REGW; CSRArray[12'h142] = testbench.dut.core.priv.priv.csr.csrs.csrs.SCAUSE_REGW; - CSRArray[12'h144] = testbench.dut.core.priv.priv.csr.csrm.MIP_REGW & & 12'h222 & testbench.dut.core.priv.priv.csr.csrm.MIDELEG_REGW; + CSRArray[12'h144] = testbench.dut.core.priv.priv.csr.csrm.MIP_REGW & 12'h222 & testbench.dut.core.priv.priv.csr.csrm.MIDELEG_REGW; CSRArray[12'h14D] = testbench.dut.core.priv.priv.csr.csrs.csrs.STIMECMP_REGW; // user CSRs CSRArray[12'h001] = testbench.dut.core.priv.priv.csr.csru.csru.FFLAGS_REGW; diff --git a/testbench/testbench.sv b/testbench/testbench.sv index 0bcc34079..caa60e23c 100644 --- a/testbench/testbench.sv +++ b/testbench/testbench.sv @@ -466,7 +466,7 @@ module testbench; integer i; logic [31:0] sig32[0:SIGNATURESIZE]; logic [P.XLEN-1:0] signature[0:SIGNATURESIZE]; - string signame, pathname; + string signame; logic [P.XLEN-1:0] testadr, testadrNoBase; // for tests with no self checking mechanism, read .signature.output file and compare to check for errors From 12beada55b5125924b39ac7d286bc840d123a05a Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Mon, 10 Jul 2023 17:00:06 -0500 Subject: [PATCH 2/5] Fixed the privilege decoder bug which prevented the fpga linux boot. --- src/ieu/controller.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ieu/controller.sv b/src/ieu/controller.sv index c543348e5..ede8f258e 100644 --- a/src/ieu/controller.sv +++ b/src/ieu/controller.sv @@ -200,7 +200,7 @@ module controller import cvw::*; #(parameter cvw_t P) ( ((P.XLEN == 64) & (Funct3D == 3'b011)); assign BFunctD = Funct3D[2:1] != 2'b01; // legal branches assign JRFunctD = Funct3D == 3'b000; - assign PFunctD = Funct3D == 3'b000 & Rs1D == 5'b0 & RdD == 5'b0; + assign PFunctD = Funct3D == 3'b000 & RdD == 5'b0; assign CSRFunctD = Funct3D[1:0] != 2'b00; assign IWValidFunct3D = Funct3D == 3'b000 | Funct3D == 3'b001 | Funct3D == 3'b101; end else begin:legalcheck2 From 4c4eb080ee31482208437c8f1c8ac95925c7e863 Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Tue, 11 Jul 2023 10:51:02 -0500 Subject: [PATCH 3/5] RTL changes for Xcelium. --- src/fpu/fdivsqrt/fdivsqrtfsm.sv | 2 +- src/mmu/pmpchecker.sv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fpu/fdivsqrt/fdivsqrtfsm.sv b/src/fpu/fdivsqrt/fdivsqrtfsm.sv index a727e5536..0e2cba90e 100644 --- a/src/fpu/fdivsqrt/fdivsqrtfsm.sv +++ b/src/fpu/fdivsqrt/fdivsqrtfsm.sv @@ -55,7 +55,7 @@ module fdivsqrtfsm import cvw::*; #(parameter cvw_t P) ( assign FDivBusyE = (state == BUSY) | IFDivStartE; // terminate immediately on special cases - assign FSpecialCaseE = XZeroE | | XInfE | XNaNE | (XsE&SqrtE) | (YZeroE | YInfE | YNaNE)&~SqrtE; + assign FSpecialCaseE = XZeroE | XInfE | XNaNE | (XsE&SqrtE) | (YZeroE | YInfE | YNaNE)&~SqrtE; if (P.IDIV_ON_FPU) assign SpecialCaseE = IntDivE ? ISpecialCaseE : FSpecialCaseE; else assign SpecialCaseE = FSpecialCaseE; flopenr #(1) SpecialCaseReg(clk, reset, IFDivStartE, SpecialCaseE, SpecialCaseM); // save SpecialCase for checking in fdivsqrtpostproc diff --git a/src/mmu/pmpchecker.sv b/src/mmu/pmpchecker.sv index fd1243031..89c22c486 100644 --- a/src/mmu/pmpchecker.sv +++ b/src/mmu/pmpchecker.sv @@ -67,7 +67,7 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) ( priorityonehot #(P.PMP_ENTRIES) pmppriority(.a(Match), .y(FirstMatch)); // combine the match signal from all the adress decoders to find the first one that matches. // Only enforce PMP checking for S and U modes or in Machine mode when L bit is set in selected region - assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | |(L & FirstMatch); // *** switch to this logic when PMP is initialized for non-machine mode + assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | (|(L & FirstMatch)); // *** switch to this logic when PMP is initialized for non-machine mode assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|(X & FirstMatch) ; assign PMPStoreAmoAccessFaultM = EnforcePMP & WriteAccessM & ~|(W & FirstMatch) ; From 4653f8e704592117d0b4aeae46789dd9062c61f8 Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Tue, 11 Jul 2023 10:51:17 -0500 Subject: [PATCH 4/5] Simplificaiton of function tracker. --- testbench/common/functionName.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testbench/common/functionName.sv b/testbench/common/functionName.sv index 90157f255..84ed99928 100644 --- a/testbench/common/functionName.sv +++ b/testbench/common/functionName.sv @@ -119,8 +119,8 @@ module FunctionName import cvw::*; #(parameter cvw_t P) ( // initial begin always @ (negedge reset) begin // clear out the old mapping between programs. - foreach(ProgramAddrMapMemory[i]) ProgramAddrMapMemory.delete(i); - foreach(ProgramLabelMapMemory[i]) ProgramLabelMapMemory.delete(i); + ProgramAddrMapMemory.delete(); + ProgramLabelMapMemory.delete(); $readmemh(ProgramAddrMapFile, ProgramAddrMapMemory); // we need to count the number of lines in the file so we can set FunctionRadixLineCount. From 38f32805ae1e5613a0b8eeef80e82f876a3a0c35 Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Tue, 11 Jul 2023 15:07:33 -0500 Subject: [PATCH 5/5] Created separate temporary testbench for xcelium. --- src/cache/cacheway.sv | 2 +- testbench/testbench-xcelium.sv | 606 +++++++++++++++++++++++++++++++++ 2 files changed, 607 insertions(+), 1 deletion(-) create mode 100644 testbench/testbench-xcelium.sv diff --git a/src/cache/cacheway.sv b/src/cache/cacheway.sv index 0a5c7b6e5..4438ea2c7 100644 --- a/src/cache/cacheway.sv +++ b/src/cache/cacheway.sv @@ -124,7 +124,7 @@ module cacheway import cvw::*; #(parameter cvw_t P, genvar words; - localparam SRAMLEN = 128; + localparam SRAMLEN = 128; // *** make this a global parameter localparam NUMSRAM = LINELEN/SRAMLEN; localparam SRAMLENINBYTES = SRAMLEN/8; localparam LOGNUMSRAM = $clog2(NUMSRAM); diff --git a/testbench/testbench-xcelium.sv b/testbench/testbench-xcelium.sv new file mode 100644 index 000000000..368cc3f07 --- /dev/null +++ b/testbench/testbench-xcelium.sv @@ -0,0 +1,606 @@ +/////////////////////////////////////////// +// 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 +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// 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 +// +// 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. +//////////////////////////////////////////////////////////////////////////////////////////////// + +`include "config.vh" +`include "tests.vh" + +import cvw::*; + +module testbench; + /* verilator lint_off WIDTHTRUNC */ + /* verilator lint_off WIDTHEXPAND */ + parameter DEBUG=0; + parameter TEST="none"; + parameter PrintHPMCounters=1; + parameter BPRED_LOGGER=0; + parameter I_CACHE_ADDR_LOGGER=0; + parameter D_CACHE_ADDR_LOGGER=0; + +`include "parameter-defs.vh" + + logic clk; + logic reset_ext, reset; + logic ResetMem; + + // DUT signals + logic [P.AHBW-1:0] HRDATAEXT; + logic HREADYEXT, HRESPEXT; + logic [P.PA_BITS-1:0] HADDR; + logic [P.AHBW-1:0] HWDATA; + logic [P.XLEN/8-1:0] HWSTRB; + logic HWRITE; + logic [2:0] HSIZE; + logic [2:0] HBURST; + logic [3:0] HPROT; + logic [1:0] HTRANS; + logic HMASTLOCK; + logic HCLK, HRESETn; + + logic [31:0] GPIOIN, GPIOOUT, GPIOEN; + logic UARTSin, UARTSout; + + logic SDCCLK; + logic SDCCmdIn; + logic SDCCmdOut; + logic SDCCmdOE; + logic [3:0] SDCDatIn; + tri1 [3:0] SDCDat; + tri1 SDCCmd; + + logic HREADY; + logic HSELEXT; + + + string ProgramAddrMapFile, ProgramLabelMapFile; + integer ProgramAddrLabelArray [string]; + + int test, i, errors, totalerrors; + + string outputfile; + integer outputFilePointer; + + string tests[]; + logic DCacheFlushDone, DCacheFlushStart; + logic riscofTest; + logic Validate; + logic SelectTest; + + + + // pick tests based on modes supported + initial begin + $display("TEST is %s", TEST); + //tests = '{}; + if (P.XLEN == 64) begin // RV64 + case (TEST) + "arch64i": tests = arch64i; + "arch64priv": tests = arch64priv; + "arch64c": if (P.C_SUPPORTED) + if (P.ZICSR_SUPPORTED) tests = {arch64c, arch64cpriv}; + else tests = {arch64c}; + "arch64m": if (P.M_SUPPORTED) tests = arch64m; + "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; + "imperas64i": tests = imperas64i; + "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; + else tests = imperas64iNOc; + "custom": tests = custom; + "wally64i": tests = wally64i; + "wally64priv": tests = wally64priv; + "wally64periph": tests = wally64periph; + "coremark": tests = coremark; + "fpga": tests = fpga; + "ahb" : tests = ahb; + "coverage64gc" : tests = coverage64gc; + "arch64zba": if (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; + endcase + end else begin // RV32 + case (TEST) + "arch32i": tests = arch32i; + "arch32priv": tests = arch32priv; + "arch32c": if (P.C_SUPPORTED) + if (P.ZICSR_SUPPORTED) tests = {arch32c, arch32cpriv}; + else tests = {arch32c}; + "arch32m": if (P.M_SUPPORTED) tests = arch32m; + "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; + "imperas32i": tests = imperas32i; + "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; + else tests = imperas32iNOc; + "wally32i": tests = wally32i; + "wally32e": tests = wally32e; + "wally32priv": tests = wally32priv; + "wally32periph": tests = wally32periph; + "embench": tests = embench; + "coremark": tests = coremark; + "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; + endcase + end + if (tests.size() == 0) begin + $display("TEST %s not supported in this configuration", TEST); + $stop; + end + 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 + + typedef enum logic [3:0]{STATE_TESTBENCH_RESET, + STATE_INIT_TEST, + STATE_RESET_MEMORIES, + STATE_RESET_MEMORIES2, + STATE_LOAD_MEMORIES, + STATE_RESET_TEST, + STATE_RUN_TEST, + STATE_CHECK_TEST, + STATE_CHECK_TEST_WAIT, + STATE_VALIDATE, + STATE_INCR_TEST} statetype; + statetype CurrState, NextState; + logic TestBenchReset; + logic [2:0] ResetCount, ResetThreshold; + logic LoadMem; + logic ResetCntEn; + logic ResetCntRst; + + + string signame, memfilename, pathname; + integer begin_signature_addr; + + assign ResetThreshold = 3'd5; + + initial begin + TestBenchReset = 1; + # 100; + TestBenchReset = 0; + end + + always_ff @(posedge clk) + if (TestBenchReset) CurrState <= #1 STATE_TESTBENCH_RESET; + else CurrState <= #1 NextState; + + // fsm next state logic + always_comb begin + // 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) + 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; + STATE_RUN_TEST: if(DCacheFlushStart) NextState = STATE_CHECK_TEST; + else NextState = STATE_RUN_TEST; + 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; + endcase + end // always_comb + // 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; + + // fsm reset counter + counter #(3) RstCounter(clk, ResetCntRst, ResetCntEn, ResetCount); + + //////////////////////////////////////////////////////////////////////////////// + // Find the test vector files and populate the PC to function label converter + //////////////////////////////////////////////////////////////////////////////// + logic [P.XLEN-1:0] testadr; + assign begin_signature_addr = ProgramAddrLabelArray["begin_signature"]; + 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) + if(!P.FPGA) begin + updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray); + end + end + + //////////////////////////////////////////////////////////////////////////////// + // Verify the test ran correctly by checking the memory against a known signature. + //////////////////////////////////////////////////////////////////////////////// + if(TestBenchReset) test = 1; + if (TEST == "coremark") + if (dut.core.EcallFaultM) begin + $display("Benchmark: coremark is done."); + $stop; + end + if(Validate) begin + if (TEST == "embench") begin + // Writes contents of begin_signature to .sim.output file + // this contains instret and cycles for start and end of test run, used by embench + // python speed script to calculate embench speed score. + // also, begin_signature contains the results of the self checking mechanism, + // which will be read by the python script for error checking + $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; + 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 + $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 + + if (!begin_signature_addr) + $display("begin_signature addr not found in %s", ProgramLabelMapFile); + else if (TEST != "embench") begin // *** quick hack for embench. need a better long term solution + CheckSignature(pathname, tests[test], riscofTest, begin_signature_addr, errors); + end + if(errors > 0) totalerrors = totalerrors + 1; + test = test + 1; // *** this probably needs to be moved. + 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 + + + //////////////////////////////////////////////////////////////////////////////// + // Some memories are not reset, but should be zeros or set to some initial value for simulation + //////////////////////////////////////////////////////////////////////////////// + integer adrindex; + + if (P.UNCORE_RAM_SUPPORTED) `define TB_UNCORE_RAM_SUPPORTED; + if (P.BPRED_SUPPORTED) `define TB_BPRED_SUPPORTED; + if (P.BPRED_TYPE == BP_LOCAL_AHEAD | P.BPRED_TYPE == BP_LOCAL_REPAIR) `define TB_BHT; + + always @(posedge clk) begin + if (ResetMem) // program memory is sometimes reset + if (P.UNCORE_RAM_SUPPORTED) begin + `ifdef TB_UNCORE_RAM_SUPPORTED + for (adrindex=0; adrindex<(P.UNCORE_RAM_RANGE>>1+(P.XLEN/32)); adrindex = adrindex+1) + dut.uncore.uncore.ram.ram.memory.RAM[adrindex] = '0; + `endif + end + if(reset) begin // branch predictor must always be reset + if (P.BPRED_SUPPORTED) begin + `ifdef TB_BPRED_SUPPORTED + // local history only + if (P.BPRED_TYPE == BP_LOCAL_AHEAD | P.BPRED_TYPE == BP_LOCAL_REPAIR) begin + `ifdef TB_BHT + for(adrindex = 0; adrindex < 2**P.BPRED_NUM_LHR; adrindex++) + dut.core.ifu.bpred.bpred.Predictor.DirPredictor.BHT.mem[adrindex] = 0; + `endif + end + // these are both always included if there is a bpred + for(adrindex = 0; adrindex < 2**P.BTB_SIZE; adrindex++) + dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex] = 0; + for(adrindex = 0; adrindex < 2**P.BPRED_SIZE; adrindex++) + dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex] = 0; + `endif + end + end + end + + //////////////////////////////////////////////////////////////////////////////// + // load memories with program image + //////////////////////////////////////////////////////////////////////////////// + if (P.FPGA) `define TB_FPGA // this is a gross hack for xcelium and verilator + if (P.IROM_SUPPORTED) `define TB_IROM_SUPPORTED + if (P.DTIM_SUPPORTED) `define TB_DTIM_SUPPORTED + if (P.BUS_SUPPORTED) `define TB_BUS_SUPPORTED + always @(posedge clk) begin + if (LoadMem) begin + if (P.FPGA) begin + `ifdef TB_FPGA + string romfilename, sdcfilename; + romfilename = {"../tests/custom/fpga-test-sdc/bin/fpga-test-sdc.memfile"}; + sdcfilename = {"../testbench/sdc/ramdisk2.hex"}; + $readmemh(romfilename, dut.uncore.uncore.bootrom.bootrom.memory.ROM); + $readmemh(sdcfilename, sdcard.sdcard.FLASHmem); + // shorten sdc timers for simulation + dut.uncore.uncore.sdc.SDC.LimitTimers = 1; + `endif + end + else if (P.IROM_SUPPORTED) begin + `ifdef TB_IROM_SUPPORTED + $readmemh(memfilename, dut.core.ifu.irom.irom.rom.ROM); + `endif + end + else if (P.BUS_SUPPORTED) begin + `ifdef TB_BUS_SUPPORTED + $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM); + `endif + end + if (P.DTIM_SUPPORTED) begin + `ifdef TB_DTIM_SUPPORTED + $readmemh(memfilename, dut.core.lsu.dtim.dtim.ram.RAM); + `endif + end + $display("Read memfile %s", memfilename); + end + end + + //////////////////////////////////////////////////////////////////////////////// + // Actual hardware + //////////////////////////////////////////////////////////////////////////////// + + // instantiate device to be tested + assign GPIOIN = 0; + assign UARTSin = 1; + + if(P.EXT_MEM_SUPPORTED) begin + ram_ahb #(.BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE)) + ram (.HCLK, .HRESETn, .HADDR, .HWRITE, .HTRANS, .HWDATA, .HSELRam(HSELEXT), + .HREADRam(HRDATAEXT), .HREADYRam(HREADYEXT), .HRESPRam(HRESPEXT), .HREADY, .HWSTRB); + end else begin + assign HREADYEXT = 1; + assign {HRESPEXT, HRDATAEXT} = '0; + end + + if(P.FPGA) begin : sdcard + sdModel sdcard + (.sdClk(SDCCLK), + .cmd(SDCCmd), + .dat(SDCDat)); + + assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz; + assign SDCCmdIn = SDCCmd; + assign SDCDatIn = SDCDat; + end else begin + assign SDCCmd = '0; + assign SDCDat = '0; + end + + wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT,.HREADYEXT, .HRESPEXT,.HSELEXT, + .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, + .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, + .UARTSin, .UARTSout, .SDCCmdIn, .SDCCmdOut, .SDCCmdOE, .SDCDatIn, .SDCCLK); + + // generate clock to sequence tests + always begin + clk = 1; # 5; clk = 0; # 5; + end + + //////////////////////////////////////////////////////////////////////////////// + // Support logic + //////////////////////////////////////////////////////////////////////////////// + + // Track names of instructions + string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; + logic [31:0] InstrW; + flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW); + instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, + dut.core.ifu.InstrRawF[31:0], + dut.core.ifu.InstrD, dut.core.ifu.InstrE, + dut.core.ifu.InstrM, InstrW, + InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); + + // watch for problems such as lockup, reading unitialized memory, bad configs + watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset); // check if PCW is stuck + ramxdetector #(P.XLEN, P.LLEN) ramxdetector(clk, dut.core.lsu.MemRWM[1], dut.core.lsu.LSULoadAccessFaultM, dut.core.lsu.ReadDataM, + dut.core.ifu.PCM, dut.core.ifu.InstrM, dut.core.lsu.IEUAdrM, InstrMName); + 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); + + // track the current function or global label + if (DEBUG == 1 | (PrintHPMCounters & P.ZICNTR_SUPPORTED)) begin : FunctionName + FunctionName #(P) FunctionName(.reset(reset_ext | TestBenchReset), + .clk(clk), .ProgramAddrMapFile(ProgramAddrMapFile), .ProgramLabelMapFile(ProgramLabelMapFile)); + end + + + // Termination condition + // terminate on a specific ECALL after li x3,1 for old Imperas tests, *** remove this when old imperas tests are removed + // or sw gp,-56(t0) for new Imperas tests + // or sd gp, -56(t0) + // or on a jump to self infinite loop (6f) for RISC-V Arch tests + logic ecf; // remove this once we don't rely on old Imperas tests with Ecalls + if (P.ZICSR_SUPPORTED) assign ecf = dut.core.priv.priv.EcallFaultM; + else assign ecf = 0; + assign DCacheFlushStart = ecf & + (dut.core.ieu.dp.regf.rf[3] == 1 | + (dut.core.ieu.dp.regf.we3 & + dut.core.ieu.dp.regf.a3 == 3 & + dut.core.ieu.dp.regf.wd3 == 1)) | + ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | + ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" ); + + DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), .reset(reset), .start(DCacheFlushStart), .done(DCacheFlushDone)); + + 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. + + 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]; + string signame; + logic [P.XLEN-1:0] testadr, testadrNoBase; + + if (P.DTIM_SUPPORTED) `define TB_DTIM_SUPPORTED2 + + // 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