This commit is contained in:
Madeleine Masser-Frye 2023-02-01 05:23:04 +00:00
commit a8ed39ecbe
16 changed files with 799 additions and 136 deletions

2
.gitignore vendored
View File

@ -134,3 +134,5 @@ fpga/src/CopiedFiles_do_not_add_to_repo/*
/fpga/generator/sim/imp-timesim.sdf
/fpga/generator/sim/imp-timesim.v
/fpga/generator/sim/syn-funcsim.v
external
pipelined/regression/results

54
bin/imperas-one-time.sh Executable file
View File

@ -0,0 +1,54 @@
#!/bin/bash
###########################################
## imperas-one-time.sh
##
## Written: Ross Thompson (ross1728@gmail.com) and Lee Moore (moore@imperas.com)
## Created: 31 January 2023
## Modified: 31 January 2023
##
## Purpose: One time setup script for running imperas.
##
## A component of the CORE-V-WALLY configurable RISC-V project.
##
## Copyright (C) 2021-23 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.
################################################################################################
IMP_HASH=56b1479
# clone the Imperas repo
cd $WALY
if [ ! -d external ]; then
mkdir -p external
fi
pushd external
if [ ! -d ImperasDV-HMC ]; then
git clone git@github.com:Imperas/ImperasDV-HMC.git
fi
pushd ImperasDV-HMC
git checkout $IMP_HASH
popd
popd
# Setup Imperas
source ${WALLY}/external/ImperasDV-HMC/Imperas/bin/setup.sh
setupImperas ${WALLY}/external/ImperasDV-HMC/Imperas
export IMPERAS_PERSONALITY=CPUMAN_DV_ASYNC
# setup QUESTA (Imperas only command, YMMV)
#svsetup -questa

View File

@ -0,0 +1,26 @@
#--showoverrides
--override cpu/show_c_prefix=T
--override cpu/unaligned=F
--override cpu/mstatus_FS=1
# Enable the Imperas instruction coverage
-extlib refRoot/cpu/cv=imperas.com/intercept/riscvInstructionCoverage/1.0
-override refRoot/cpu/cv/cover=basic
-override refRoot/cpu/cv/extensions=RV32I
# Add Imperas simulator application instruction tracing
--trace
--tracechange
--traceshowicount
--tracemode
--monitornetschange
# Turn on verbose output for Imperas simulator
--verbose
# Turn on verbose output for RISCV model
--override cpu/verbose=1
# Store simulator output to logfile
--output imperas.log

View File

@ -0,0 +1,22 @@
#!/bin/bash
if [ -d results ]; then
rm -rf results
fi
mkdir -p results
ALL=$(find ${WALLY}/external/ImperasDV-HMC/tests/riscof/work/riscv-arch-test/rv64i_m -name "ref" -type d)
export IMPERAS_TOOLS=$(pwd)/imperas.ic
export OTHERFLAGS="+TRACE2LOG_ENABLE=1 VERBOSE=1"
for t in $ALL; do
export TESTDIR=$(dirname ${t})
OUTLOG=$(echo ${TESTDIR} | sed "s|${WALLY}/external/ImperasDV-HMC/tests/riscof/work|results|").log
OUTDIR=$(dirname ${OUTLOG})
echo "Running test ${TESTDIR} -> ${OUTDIR} :: ${OUTLOG}"
mkdir -p ${OUTDIR}
vsim -c -do "do wally-pipelined-imperas.do rv64gc"
mv transcript ${OUTLOG}
done

View File

@ -0,0 +1,32 @@
#!/bin/bash
###########################################
## imperas-one-time.sh
##
## Written: Ross Thompson (ross1728@gmail.com) and Lee Moore (moore@imperas.com)
## Created: 31 January 2023
## Modified: 31 January 2023
##
## Purpose: Run wally with imperas
##
## A component of the CORE-V-WALLY configurable RISC-V project.
##
## Copyright (C) 2021-23 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.
################################################################################################
IMPERAS_TOOLS=$(pwd)/imperas.ic \
OTHERFLAGS="+TRACE2LOG_ENABLE=1 VERBOSE=1" \
TESTDIR=${WALLY}/external/ImperasDV-HMC/tests/riscof/work/riscv-arch-test/rv64i_m/F/src/fadd_b1-01.S \
vsim -c -do "do wally-pipelined-imperas.do rv64gc"

View File

@ -0,0 +1,55 @@
# wally-pipelined.do
#
# Modification by Oklahoma State University & Harvey Mudd College
# Use with Testbench
# James Stine, 2008; David Harris 2021
# Go Cowboys!!!!!!
#
# Takes 1:10 to run RV64IC tests using gui
# run with vsim -do "do wally-pipelined.do rv64ic riscvarchtest-64m"
# Use this wally-pipelined.do file to run this example.
# Either bring up ModelSim and type the following at the "ModelSim>" prompt:
# do wally-pipelined.do
# or, to run from a shell, type the following at the shell prompt:
# vsim -do wally-pipelined.do -c
# (omit the "-c" to see the GUI while running from the shell)
onbreak {resume}
# create library
if [file exists work] {
vdel -all
}
vlib work
# compile source files
# suppress spurious warnngs about
# "Extra checking for conflicts with always_comb done at vopt time"
# because vsim will run vopt
# start and run simulation
# remove +acc flag for faster sim during regressions if there is no need to access internal signals
# *** modelsim won't take `PA_BITS, but will take other defines for the lengths of DTIM_RANGE and IROM_LEN. For now just live with the warnings.
vlog +incdir+../config/$1 \
+incdir+../config/shared \
../../external/ImperasDV-HMC/Imperas/ImpPublic/source/host/rvvi/rvvi-trace.sv \
../testbench/testbench_imperas.sv \
../testbench/common/*.sv \
../src/*/*.sv \
../src/*/*/*.sv \
-suppress 2583 \
-suppress 7063
vopt +acc work.testbench -G DEBUG=1 -o workopt
vsim workopt +nowarn3829 -fatal 7 \
+testDir=$env(TESTDIR) $env(OTHERFLAGS)
view wave
#-- display input and output signals as hexidecimal values
add log -recursive /*
do wave.do
run -all
noview ../testbench/testbench_imperas.sv
view wave

View File

@ -0,0 +1,63 @@
# wally-pipelined.do
#
# Modification by Oklahoma State University & Harvey Mudd College
# Use with Testbench
# James Stine, 2008; David Harris 2021
# Go Cowboys!!!!!!
#
# Takes 1:10 to run RV64IC tests using gui
# run with vsim -do "do wally-pipelined.do rv64ic riscvarchtest-64m"
# Use this wally-pipelined.do file to run this example.
# Either bring up ModelSim and type the following at the "ModelSim>" prompt:
# do wally-pipelined.do
# or, to run from a shell, type the following at the shell prompt:
# vsim -do wally-pipelined.do -c
# (omit the "-c" to see the GUI while running from the shell)
onbreak {resume}
# create library
if [file exists work] {
vdel -all
}
vlib work
# compile source files
# suppress spurious warnngs about
# "Extra checking for conflicts with always_comb done at vopt time"
# because vsim will run vopt
# start and run simulation
# remove +acc flag for faster sim during regressions if there is no need to access internal signals
# *** modelsim won't take `PA_BITS, but will take other defines for the lengths of DTIM_RANGE and IROM_LEN. For now just live with the warnings.
vlog +incdir+../config/$1 \
+incdir+../config/shared \
+define+USE_IMPERAS_DV \
+incdir+$env(IMPERAS_HOME)/ImpPublic/include/host \
+incdir+$env(IMPERAS_HOME)/ImpProprietary/include/host \
$env(IMPERAS_HOME)/ImpPublic/source/host/rvvi/rvvi-api-pkg.sv \
$env(IMPERAS_HOME)/ImpPublic/source/host/rvvi/rvvi-trace.sv \
$env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/rvvi-pkg.sv \
$env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/trace2api.sv \
$env(IMPERAS_HOME)/ImpProprietary/source/host/rvvi/trace2log.sv \
../testbench/testbench_imperas.sv \
../testbench/common/*.sv \
../src/*/*.sv \
../src/*/*/*.sv \
-suppress 2583 \
-suppress 7063
vopt +acc work.testbench -G DEBUG=1 -o workopt
vsim workopt +nowarn3829 -fatal 7 \
-sv_lib $env(IMPERAS_HOME)/lib/Linux64/ImperasLib/imperas.com/verification/riscv/1.0/model \
+testDir=$env(TESTDIR) $env(OTHERFLAGS)
view wave
#-- display input and output signals as hexidecimal values
add log -recursive /*
do wave.do
run -all
noview ../testbench/testbench_imperas.sv
view wave

View File

@ -6,28 +6,28 @@ add wave -noupdate /testbench/reset
add wave -noupdate /testbench/reset_ext
add wave -noupdate /testbench/memfilename
add wave -noupdate /testbench/dut/core/SATP_REGW
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/hzu/BPPredWrongE
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/hzu/RetM
add wave -noupdate -group HDU -expand -group hazards -color Pink /testbench/dut/core/hzu/TrapM
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/hzu/LoadStallD
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/ifu/IFUStallF
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/hzu/LSUStallM
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/MDUStallD
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/hzu/DivBusyE
add wave -noupdate -group HDU -expand -group hazards /testbench/dut/core/hzu/FDivBusyE
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/InstrMisalignedFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/InstrAccessFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/IllegalInstrFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/BreakpointFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/LoadMisalignedFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/StoreAmoMisalignedFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/LoadAccessFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/StoreAmoAccessFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/EcallFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/InstrPageFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/LoadPageFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/StoreAmoPageFaultM
add wave -noupdate -group HDU -expand -group traps /testbench/dut/core/priv/priv/trap/InterruptM
add wave -noupdate -group HDU -group hazards /testbench/dut/core/hzu/BPPredWrongE
add wave -noupdate -group HDU -group hazards /testbench/dut/core/hzu/RetM
add wave -noupdate -group HDU -group hazards -color Pink /testbench/dut/core/hzu/TrapM
add wave -noupdate -group HDU -group hazards /testbench/dut/core/hzu/LoadStallD
add wave -noupdate -group HDU -group hazards /testbench/dut/core/ifu/IFUStallF
add wave -noupdate -group HDU -group hazards /testbench/dut/core/hzu/LSUStallM
add wave -noupdate -group HDU -group hazards /testbench/dut/core/MDUStallD
add wave -noupdate -group HDU -group hazards /testbench/dut/core/hzu/DivBusyE
add wave -noupdate -group HDU -group hazards /testbench/dut/core/hzu/FDivBusyE
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/InstrMisalignedFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/InstrAccessFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/IllegalInstrFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/BreakpointFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/LoadMisalignedFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/StoreAmoMisalignedFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/LoadAccessFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/StoreAmoAccessFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/EcallFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/InstrPageFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/LoadPageFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/StoreAmoPageFaultM
add wave -noupdate -group HDU -group traps /testbench/dut/core/priv/priv/trap/InterruptM
add wave -noupdate -group HDU -expand -group Flush -color Yellow /testbench/dut/core/FlushD
add wave -noupdate -group HDU -expand -group Flush -color Yellow /testbench/dut/core/FlushE
add wave -noupdate -group HDU -expand -group Flush -color Yellow /testbench/dut/core/FlushM

View File

@ -42,7 +42,7 @@ module RASPredictor #(parameter int StackSize = 16 )(
logic CounterEn;
localparam Depth = $clog2(StackSize);
logic [Depth-1:0] PtrD, PtrQ, PtrP1, PtrM1;
logic [Depth-1:0] NextPtr, CurrPtr, PtrP1, PtrM1;
logic [StackSize-1:0] [`XLEN-1:0] memory;
integer index;
@ -52,30 +52,31 @@ module RASPredictor #(parameter int StackSize = 16 )(
logic IncrRepairD, DecRepairD;
logic DecrementPtr;
logic FlushedRetDE;
logic WrongPredRetD;
assign PopF = PredInstrClassF[2] & ~StallD & ~FlushD;
assign RepairD = ((WrongPredInstrClassD[2]) & ~StallE & ~FlushE) | // Wrong class undo increment or decrement.
(~StallE & FlushE & InstrClassD[2]) | // ret in decode flushed
(~StallM & FlushM & InstrClassE[2]) ; // ret in execution flushed
assign IncrRepairD = (~StallE & FlushE & InstrClassD[2]) | // ret in decode flushed
(~StallM & FlushM & InstrClassE[2]) | // ret in execution flushed
(WrongPredInstrClassD[2] & ~InstrClassD[2] & ~StallE & ~FlushE); // Guessed it was a ret, but its not
assign DecRepairD = (WrongPredInstrClassD[2] & InstrClassD[2] & ~StallE & ~FlushE); // Guessed non ret but is a ret.
assign PushE = InstrClassE[3] & ~StallM & ~FlushM;
assign WrongPredRetD = (WrongPredInstrClassD[2]) & ~StallE & ~FlushE;
assign FlushedRetDE = (~StallE & FlushE & InstrClassD[2]) | (~StallM & FlushM & InstrClassE[2]); // flushed ret
assign RepairD = WrongPredRetD | FlushedRetDE ;
assign IncrRepairD = FlushedRetDE | (WrongPredRetD & ~InstrClassD[2]); // Guessed it was a ret, but its not
assign DecRepairD = WrongPredRetD & InstrClassD[2]; // Guessed non ret but is a ret.
assign CounterEn = PopF | PushE | RepairD;
assign DecrementPtr = (PopF | DecRepairD) & ~IncrRepairD;
mux2 #(Depth) PtrMux(PtrP1, PtrM1, DecrementPtr, PtrD);
mux2 #(Depth) PtrMux(PtrP1, PtrM1, DecrementPtr, NextPtr);
assign PtrM1 = PtrQ - 1'b1;
assign PtrP1 = PtrQ + 1'b1;
assign PtrM1 = CurrPtr - 1'b1;
assign PtrP1 = CurrPtr + 1'b1;
flopenr #(Depth) PTR(clk, reset, CounterEn, PtrD, PtrQ);
flopenr #(Depth) PTR(clk, reset, CounterEn, NextPtr, CurrPtr);
// RAS must be reset.
always_ff @ (posedge clk) begin
@ -87,7 +88,7 @@ module RASPredictor #(parameter int StackSize = 16 )(
end
end
assign RASPCF = memory[PtrQ];
assign RASPCF = memory[CurrPtr];
endmodule

View File

@ -117,8 +117,7 @@ module bpred (
end else if (`BPRED_TYPE == "BPSPECULATIVEGSHARE") begin:Predictor
speculativegshare #(`BPRED_SIZE) DirPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .StallW, .FlushD, .FlushE, .FlushM, .FlushW,
.PCNextF, .PCF, .PCD, .PCE, .PCM, .DirPredictionF, .DirPredictionWrongE,
.BranchInstrF(PredInstrClassF[0]), .BranchInstrD(InstrClassD[0]), .BranchInstrE(InstrClassE[0]), .BranchInstrM(InstrClassM[0]),
.BranchInstrW(InstrClassW[0]), .WrongPredInstrClassD, .PCSrcE);
.PredInstrClassF, .InstrClassD, .InstrClassE, .WrongPredInstrClassD, .PCSrcE);
end else if (`BPRED_TYPE == "BPLOCALPAg") begin:Predictor
// *** Fix me
@ -152,15 +151,6 @@ module bpred (
.IEUAdrE,
.InstrClassE);
// Part 3 RAS
// *** need to add the logic to restore RAS on flushes. We will use incr for this.
// *** needs to include flushX
RASPredictor RASPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .FlushD, .FlushE, .FlushM,
.PredInstrClassF, .InstrClassD, .InstrClassE,
.WrongPredInstrClassD, .RASPCF, .PCLinkE);
assign BPPredPCF = PredInstrClassF[2] ? RASPCF : PredPCF;
// the branch predictor needs a compact decoding of the instruction class.
if (`INSTR_CLASS_PRED == 0) begin : DirectClassDecode
logic [4:0] CompressedOpcF;
@ -197,12 +187,19 @@ module bpred (
(PredInstrClassF[1] & PredValidF) ;
end
// Part 3 RAS
RASPredictor RASPredictor(.clk, .reset, .StallF, .StallD, .StallE, .StallM, .FlushD, .FlushE, .FlushM,
.PredInstrClassF, .InstrClassD, .InstrClassE,
.WrongPredInstrClassD, .RASPCF, .PCLinkE);
assign BPPredPCF = PredInstrClassF[2] ? RASPCF : PredPCF;
assign InstrClassD[3] = (InstrD[6:0] & 7'h77) == 7'h67 & (InstrD[11:07] & 5'h1B) == 5'h01; // jal(r) must link to ra or x5
assign InstrClassD[2] = InstrD[6:0] == 7'h67 & (InstrD[19:15] & 5'h1B) == 5'h01; // return must return to ra or r5
assign InstrClassD[1] = (InstrD[6:0] == 7'h67 & (InstrD[19:15] & 5'h1B) != 5'h01 & (InstrD[11:7] & 5'h1B) != 5'h01) | // jump register, but not return
(InstrD[6:0] == 7'h6F & (InstrD[11:7] & 5'h1B) != 5'h01); // jump, RD != x1 or x5
assign InstrClassD[0] = InstrD[6:0] == 7'h63; // branch
flopenrc #(4) InstrClassRegE(clk, reset, FlushE, ~StallE, InstrClassD, InstrClassE);
flopenrc #(4) InstrClassRegM(clk, reset, FlushM, ~StallM, InstrClassE, InstrClassM);
flopenrc #(4) InstrClassRegW(clk, reset, FlushW, ~StallW, InstrClassM, InstrClassW);

View File

@ -29,36 +29,32 @@
`include "wally-config.vh"
module speculativegshare #(parameter int k = 10 ) (
input logic clk,
input logic reset,
input logic StallF, StallD, StallE, StallM, StallW,
input logic FlushD, FlushE, FlushM, FlushW,
output logic [1:0] DirPredictionF,
output logic DirPredictionWrongE,
input logic clk,
input logic reset,
input logic StallF, StallD, StallE, StallM, StallW,
input logic FlushD, FlushE, FlushM, FlushW,
output logic [1:0] DirPredictionF,
output logic DirPredictionWrongE,
// update
input logic [`XLEN-1:0] PCNextF, PCF, PCD, PCE, PCM,
input logic BranchInstrF, BranchInstrD, BranchInstrE, BranchInstrM, BranchInstrW,
input logic [3:0] WrongPredInstrClassD,
input logic PCSrcE
input logic [3:0] PredInstrClassF, InstrClassD, InstrClassE,
input logic [3:0] WrongPredInstrClassD,
input logic PCSrcE
);
logic MatchF, MatchD, MatchE;
logic MatchNextX, MatchXF;
logic [1:0] TableDirPredictionF, DirPredictionD, DirPredictionE;
logic [1:0] NewDirPredictionF, NewDirPredictionD, NewDirPredictionE;
logic [k-1:0] GHRF;
logic GHRExtraF;
logic [k-1:0] GHRD, GHRE, GHRM, GHRW;
logic [k-1:0] GHRNextF;
logic [k-1:0] GHRNextD;
logic [k-1:0] GHRNextE, GHRNextM, GHRNextW;
logic [k-1:0] IndexNextF, IndexF;
logic [k-1:0] IndexD, IndexE;
logic [1:0] NewDirPredictionE;
logic [k-1:0] GHRF, GHRD, GHRE;
logic GHRLastF;
logic [k-1:0] GHRNextF, GHRNextD, GHRNextE;
logic [k-1:0] IndexNextF, IndexF, IndexD, IndexE;
logic [1:0] ForwardNewDirPrediction, ForwardDirPredictionF;
logic FlushDOrDirWrong;
assign IndexNextF = GHRNextF ^ {PCNextF[k+1] ^ PCNextF[1], PCNextF[k:2]};
assign IndexF = GHRF ^ {PCF[k+1] ^ PCF[1], PCF[k:2]};
@ -71,20 +67,20 @@ module speculativegshare #(parameter int k = 10 ) (
.rd1(TableDirPredictionF),
.wa2(IndexE),
.wd2(NewDirPredictionE),
.we2(BranchInstrE & ~StallM & ~FlushM),
.we2(InstrClassE[0]),
.bwe2(1'b1));
// if there are non-flushed branches in the pipeline we need to forward the prediction from that stage to the NextF demi stage
// and then register for use in the Fetch stage.
assign MatchF = BranchInstrF & ~FlushD & (IndexNextF == IndexF);
assign MatchD = BranchInstrD & ~FlushE & (IndexNextF == IndexD);
assign MatchE = BranchInstrE & ~FlushM & (IndexNextF == IndexE);
assign MatchF = PredInstrClassF[0] & ~FlushD & (IndexNextF == IndexF);
assign MatchD = InstrClassD[0] & ~FlushE & (IndexNextF == IndexD);
assign MatchE = InstrClassE[0] & ~FlushM & (IndexNextF == IndexE);
assign MatchNextX = MatchF | MatchD | MatchE;
flopenr #(1) MatchReg(clk, reset, ~StallF, MatchNextX, MatchXF);
assign ForwardNewDirPrediction = MatchF ? NewDirPredictionF :
MatchD ? NewDirPredictionD :
assign ForwardNewDirPrediction = MatchF ? {2{DirPredictionF[1]}} :
MatchD ? {2{DirPredictionD[1]}} :
NewDirPredictionE ;
flopenr #(2) ForwardDirPredicitonReg(clk, reset, ~StallF, ForwardNewDirPrediction, ForwardDirPredictionF);
@ -95,49 +91,37 @@ module speculativegshare #(parameter int k = 10 ) (
flopenr #(2) PredictionRegD(clk, reset, ~StallD, DirPredictionF, DirPredictionD);
flopenr #(2) PredictionRegE(clk, reset, ~StallE, DirPredictionD, DirPredictionE);
// New prediction pipeline
assign NewDirPredictionF = {DirPredictionF[1], DirPredictionF[1]};
flopenr #(2) NewPredDReg(clk, reset, ~StallD, NewDirPredictionF, NewDirPredictionD);
satCounter2 BPDirUpdateE(.BrDir(PCSrcE), .OldState(DirPredictionE), .NewState(NewDirPredictionE));
// GHR pipeline
// this version fails the regression test do to pessimistic x propagation.
// assign GHRNextF = FlushD | DirPredictionWrongE ? GHRNextD[k-1:0] :
// BranchInstrF ? {DirPredictionF[1], GHRF[k-1:1]} :
// GHRF;
always_comb begin
if(FlushD | DirPredictionWrongE) begin
GHRNextF = GHRNextD[k-1:0];
end else if(BranchInstrF) GHRNextF = {DirPredictionF[1], GHRF[k-1:1]};
else GHRNextF = GHRF;
end
// If Fetch has a branch, speculatively insert prediction into the GHR
// If the front end is flushed or the direction prediction is wrong, reset to
// most recent valid GHR. For a BP wrong this is GHRD with the correct prediction shifted in.
// For FlushE this is GHRE. GHRNextE is both.
assign FlushDOrDirWrong = FlushD | DirPredictionWrongE;
mux3 #(k) GHRFMux(GHRF, {DirPredictionF[1], GHRF[k-1:1]}, GHRNextE[k-1:0],
{FlushDOrDirWrong, PredInstrClassF[0]}, GHRNextF);
flopenr #(k) GHRFReg(clk, reset, (~StallF) | FlushD, GHRNextF, GHRF);
flopenr #(1) GHRFExtraReg(clk, reset, (~StallF) | FlushD, GHRF[0], GHRExtraF);
// Need 1 extra bit to store the shifted out GHRF if repair needs to back shift.
flopenr #(k) GHRFReg(clk, reset, ~StallF | FlushDOrDirWrong, GHRNextF, GHRF);
flopenr #(1) GHRFLastReg(clk, reset, ~StallF | FlushDOrDirWrong, GHRF[0], GHRLastF);
// use with out instruction class prediction
//assign GHRNextD = FlushD ? GHRNextE[k-1:0] : GHRF[k-1:0];
// with instruction class prediction
assign GHRNextD = (FlushD | DirPredictionWrongE) ? GHRNextE[k-1:0] :
WrongPredInstrClassD[0] & BranchInstrD ? {DirPredictionD[1], GHRF[k-1:1]} : // shift right
WrongPredInstrClassD[0] & ~BranchInstrD ? {GHRF[k-2:0], GHRExtraF}: // shift left
GHRF[k-1:0];
// With instruction class prediction, the class could be wrong and is checked in Decode.
// If it is wrong and branch does exist then shift right and insert the prediction.
// If the branch does not exist then shift left and use GHRLastF to restore the LSB.
logic [k-1:0] GHRClassWrong;
mux2 #(k) GHRClassWrongMux({DirPredictionD[1], GHRF[k-1:1]}, {GHRF[k-2:0], GHRLastF}, InstrClassD[0], GHRClassWrong);
// As with GHRF FlushD and wrong direction prediction flushes the pipeline and restores to GHRNextE.
mux3 #(k) GHRDMux(GHRF, GHRClassWrong, GHRNextE, {FlushDOrDirWrong, WrongPredInstrClassD[0]}, GHRNextD);
flopenr #(k) GHRDReg(clk, reset, (~StallD) | FlushD, GHRNextD, GHRD);
flopenr #(k) GHRDReg(clk, reset, ~StallD | FlushDOrDirWrong, GHRNextD, GHRD);
assign GHRNextE = BranchInstrE & ~FlushM ? {PCSrcE, GHRD[k-2:0]} : // if the branch is not flushed
FlushE ? GHRE : // branch is flushed
GHRD;
flopenr #(k) GHREReg(clk, reset, (BranchInstrE & ~StallE) | FlushE, GHRNextE, GHRE);
mux3 #(k) GHREMux(GHRD, GHRE, {PCSrcE, GHRD[k-2:0]}, {InstrClassE[0] & ~FlushM, FlushE}, GHRNextE);
//assign GHRNextM = FlushM ? GHRM : GHRE;
//flopenr #(k) GHRMReg(clk, reset, (BranchInstrM & ~StallM) | FlushM, GHRNextM, GHRM);
//assign GHRNextW = FlushW ? GHRW : GHRM;
//flopenr #(k) GHRWReg(clk, reset, (BranchInstrW & ~StallW) | FlushW, GHRNextW, GHRW);
flopenr #(k) GHREReg(clk, reset, ((InstrClassE[0] & ~FlushM) & ~StallE) | FlushE, GHRNextE, GHRE);
assign DirPredictionWrongE = PCSrcE != DirPredictionE[1] & BranchInstrE;
assign DirPredictionWrongE = PCSrcE != DirPredictionE[1] & InstrClassE[0];
endmodule

View File

@ -68,6 +68,7 @@ module csrsr (
STATUS_XS, STATUS_FS, /*STATUS_MPP, 2'b0*/ 4'b0,
STATUS_SPP, /*STATUS_MPIE*/ 1'b0, STATUS_UBE, STATUS_SPIE,
/*1'b0, STATUS_MIE, 1'b0*/ 3'b0, STATUS_SIE, 1'b0};
assign MSTATUSH_REGW = '0; // *** does not exist when XLEN=64, but don't want it to have an undefined value. Spec is not clear what it should be.
end else begin: csrsr32 // RV32
assign MSTATUS_REGW = {STATUS_SD, 8'b0,
STATUS_TSR, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_MPRV,

View File

@ -0,0 +1,291 @@
`include "wally-config.vh"
`define NUM_REGS 32
`define NUM_CSRS 4096
`define PRINT_PC_INSTR 0
`define PRINT_MOST 0
`define PRINT_ALL 0
`define PRINT_CSRS 0
module wallyTracer(rvviTrace rvvi);
localparam NUMREGS = `E_SUPPORTED ? 16 : 32;
// wally specific signals
logic reset;
logic [`XLEN-1:0] PCNextF, PCF, PCD, PCE, PCM, PCW;
logic [`XLEN-1:0] InstrRawD, InstrRawE, InstrRawM, InstrRawW;
logic InstrValidM, InstrValidW;
logic StallE, StallM, StallW;
logic FlushD, FlushE, FlushM, FlushW;
logic TrapM, TrapW;
logic IntrF, IntrD, IntrE, IntrM, IntrW;
logic HaltM, HaltW;
logic [1:0] PrivilegeModeW;
logic [`XLEN-1:0] rf[NUMREGS];
logic [NUMREGS-1:0] rf_wb;
logic [4:0] rf_a3;
logic rf_we3;
logic [`XLEN-1:0] frf[32];
logic [`NUM_REGS-1:0] frf_wb;
logic [4:0] frf_a4;
logic frf_we4;
logic [`XLEN-1:0] CSRArray [logic[11:0]];
logic [`XLEN-1:0] CSRArrayOld [logic[11:0]];
logic [`NUM_CSRS-1:0] CSR_W;
logic CSRWriteM, CSRWriteW;
logic [11:0] CSRAdrM, CSRAdrW;
assign clk = testbench.dut.clk;
// assign InstrValidF = testbench.dut.core.ieu.InstrValidF; // not needed yet
assign InstrValidD = testbench.dut.core.ieu.c.InstrValidD;
assign InstrValidE = testbench.dut.core.ieu.c.InstrValidE;
assign InstrValidM = testbench.dut.core.ieu.InstrValidM;
assign InstrRawD = testbench.dut.core.ifu.InstrRawD;
assign PCNextF = testbench.dut.core.ifu.PCNextF;
assign PCF = testbench.dut.core.ifu.PCF;
assign PCD = testbench.dut.core.ifu.PCD;
assign PCE = testbench.dut.core.ifu.PCE;
assign PCM = testbench.dut.core.ifu.PCM;
assign reset = testbench.reset;
assign StallF = testbench.dut.core.StallF;
assign StallD = testbench.dut.core.StallD;
assign StallE = testbench.dut.core.StallE;
assign StallM = testbench.dut.core.StallM;
assign StallW = testbench.dut.core.StallW;
assign FlushD = testbench.dut.core.FlushD;
assign FlushE = testbench.dut.core.FlushE;
assign FlushM = testbench.dut.core.FlushM;
assign FlushW = testbench.dut.core.FlushW;
assign TrapM = testbench.dut.core.TrapM;
assign HaltM = testbench.DCacheFlushStart;
assign PrivilegeModeW = testbench.dut.core.priv.priv.privmode.PrivilegeModeW;
assign STATUS_SXL = testbench.dut.core.priv.priv.csr.csrsr.STATUS_SXL;
assign STATUS_UXL = testbench.dut.core.priv.priv.csr.csrsr.STATUS_UXL;
logic valid;
always_comb begin
// Since we are detected the CSR change by comparing the old value we need to
// ensure the CSR is detected when the pipeline's Writeback stage is not
// stalled. If it is stalled we want CSRArray to hold the old value.
if(valid) begin
// machine CSRs
// *** missing PMP and performance counters.
CSRArray[12'h300] = testbench.dut.core.priv.priv.csr.csrm.MSTATUS_REGW;
CSRArray[12'h310] = testbench.dut.core.priv.priv.csr.csrm.MSTATUSH_REGW;
CSRArray[12'h305] = testbench.dut.core.priv.priv.csr.csrm.MTVEC_REGW;
CSRArray[12'h341] = testbench.dut.core.priv.priv.csr.csrm.MEPC_REGW;
CSRArray[12'h306] = testbench.dut.core.priv.priv.csr.csrm.MCOUNTEREN_REGW;
CSRArray[12'h320] = testbench.dut.core.priv.priv.csr.csrm.MCOUNTINHIBIT_REGW;
CSRArray[12'h302] = testbench.dut.core.priv.priv.csr.csrm.MEDELEG_REGW;
CSRArray[12'h303] = testbench.dut.core.priv.priv.csr.csrm.MIDELEG_REGW;
CSRArray[12'h344] = testbench.dut.core.priv.priv.csr.csrm.MIP_REGW;
CSRArray[12'h304] = testbench.dut.core.priv.priv.csr.csrm.MIE_REGW;
CSRArray[12'h301] = testbench.dut.core.priv.priv.csr.csrm.MISA_REGW;
CSRArray[12'hF14] = testbench.dut.core.priv.priv.csr.csrm.MHARTID_REGW;
CSRArray[12'h340] = testbench.dut.core.priv.priv.csr.csrm.MSCRATCH_REGW;
CSRArray[12'h342] = testbench.dut.core.priv.priv.csr.csrm.MCAUSE_REGW;
CSRArray[12'h343] = testbench.dut.core.priv.priv.csr.csrm.MTVAL_REGW;
CSRArray[12'hF11] = 0;
CSRArray[12'hF12] = 0;
CSRArray[12'hF13] = `XLEN'h100;
CSRArray[12'hF15] = 0;
CSRArray[12'h34A] = 0;
// MCYCLE and MINSTRET
CSRArray[12'hB00] = testbench.dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[0];
CSRArray[12'hB02] = testbench.dut.core.priv.priv.csr.counters.counters.HPMCOUNTER_REGW[2];
// supervisor CSRs
CSRArray[12'h100] = testbench.dut.core.priv.priv.csr.csrs.csrs.SSTATUS_REGW;
CSRArray[12'h104] = testbench.dut.core.priv.priv.csr.csrm.MIE_REGW & 12'h222;
CSRArray[12'h105] = testbench.dut.core.priv.priv.csr.csrs.csrs.STVEC_REGW;
CSRArray[12'h141] = testbench.dut.core.priv.priv.csr.csrs.csrs.SEPC_REGW;
CSRArray[12'h106] = testbench.dut.core.priv.priv.csr.csrs.csrs.SCOUNTEREN_REGW;
CSRArray[12'h180] = testbench.dut.core.priv.priv.csr.csrs.csrs.SATP_REGW;
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;
// user CSRs
CSRArray[12'h001] = testbench.dut.core.priv.priv.csr.csru.csru.FFLAGS_REGW;
CSRArray[12'h002] = testbench.dut.core.priv.priv.csr.csru.csru.FRM_REGW;
CSRArray[12'h003] = {testbench.dut.core.priv.priv.csr.csru.csru.FRM_REGW, testbench.dut.core.priv.priv.csr.csru.csru.FFLAGS_REGW};
end else begin // hold the old value if the pipeline is stalled.
CSRArray[12'h300] = CSRArrayOld[12'h300];
CSRArray[12'h310] = CSRArrayOld[12'h310];
CSRArray[12'h305] = CSRArrayOld[12'h305];
CSRArray[12'h341] = CSRArrayOld[12'h341];
CSRArray[12'h306] = CSRArrayOld[12'h306];
CSRArray[12'h320] = CSRArrayOld[12'h320];
CSRArray[12'h302] = CSRArrayOld[12'h302];
CSRArray[12'h303] = CSRArrayOld[12'h303];
CSRArray[12'h344] = CSRArrayOld[12'h344];
CSRArray[12'h304] = CSRArrayOld[12'h304];
CSRArray[12'h301] = CSRArrayOld[12'h301];
CSRArray[12'hF14] = CSRArrayOld[12'hF14];
CSRArray[12'h340] = CSRArrayOld[12'h340];
CSRArray[12'h342] = CSRArrayOld[12'h342];
CSRArray[12'h343] = CSRArrayOld[12'h343];
CSRArray[12'hF11] = CSRArrayOld[12'hF11];
CSRArray[12'hF12] = CSRArrayOld[12'hF12];
CSRArray[12'hF13] = CSRArrayOld[12'hF13];
CSRArray[12'hF15] = CSRArrayOld[12'hF15];
CSRArray[12'h34A] = CSRArrayOld[12'h34A];
// MCYCLE and MINSTRET
CSRArray[12'hB00] = CSRArrayOld[12'hB00];
CSRArray[12'hB02] = CSRArrayOld[12'hB02];
// supervisor CSRs
CSRArray[12'h100] = CSRArrayOld[12'h100];
CSRArray[12'h104] = CSRArrayOld[12'h104];
CSRArray[12'h105] = CSRArrayOld[12'h105];
CSRArray[12'h141] = CSRArrayOld[12'h141];
CSRArray[12'h106] = CSRArrayOld[12'h106];
CSRArray[12'h180] = CSRArrayOld[12'h180];
CSRArray[12'h140] = CSRArrayOld[12'h140];
CSRArray[12'h143] = CSRArrayOld[12'h143];
CSRArray[12'h142] = CSRArrayOld[12'h142];
CSRArray[12'h144] = CSRArrayOld[12'h144];
// user CSRs
CSRArray[12'h001] = CSRArrayOld[12'h001];
CSRArray[12'h002] = CSRArrayOld[12'h002];
CSRArray[12'h003] = CSRArrayOld[12'h003];
end
end
genvar index;
assign rf[0] = '0;
for(index = 1; index < NUMREGS; index += 1)
assign rf[index] = testbench.dut.core.ieu.dp.regf.rf[index];
assign rf_a3 = testbench.dut.core.ieu.dp.regf.a3;
assign rf_we3 = testbench.dut.core.ieu.dp.regf.we3;
always_comb begin
rf_wb <= '0;
if(rf_we3)
rf_wb[rf_a3] <= 1'b1;
end
for(index = 0; index < NUMREGS; index += 1)
assign frf[index] = testbench.dut.core.fpu.fpu.fregfile.rf[index];
assign frf_a4 = testbench.dut.core.fpu.fpu.fregfile.a4;
assign frf_we4 = testbench.dut.core.fpu.fpu.fregfile.we4;
always_comb begin
frf_wb <= '0;
if(frf_we4)
frf_wb[frf_a4] <= 1'b1;
end
assign CSRAdrM = testbench.dut.core.priv.priv.csr.CSRAdrM;
assign CSRWriteM = testbench.dut.core.priv.priv.csr.CSRWriteM;
// pipeline to writeback stage
flopenrc #(`XLEN) InstrRawEReg (clk, reset, FlushE, ~StallE, InstrRawD, InstrRawE);
flopenrc #(`XLEN) InstrRawMReg (clk, reset, FlushM, ~StallM, InstrRawE, InstrRawM);
flopenrc #(`XLEN) InstrRawWReg (clk, reset, FlushW, ~StallW, InstrRawM, InstrRawW);
flopenrc #(`XLEN) PCWReg (clk, reset, FlushW, ~StallW, PCM, PCW);
flopenrc #(1) InstrValidMReg (clk, reset, FlushW, ~StallW, InstrValidM, InstrValidW);
flopenrc #(1) TrapWReg (clk, reset, 1'b0, ~StallW, TrapM, TrapW);
flopenrc #(1) HaltWReg (clk, reset, 1'b0, ~StallW, HaltM, HaltW);
flopenrc #(1) IntrFReg (clk, reset, 1'b0, ~StallF, TrapM, IntrF);
flopenrc #(1) IntrDReg (clk, reset, FlushD, ~StallD, IntrF, IntrD);
flopenrc #(1) IntrEReg (clk, reset, FlushE, ~StallE, IntrD, IntrE);
flopenrc #(1) IntrMReg (clk, reset, FlushM, ~StallM, IntrE, IntrM);
flopenrc #(1) IntrWReg (clk, reset, FlushW, ~StallW, IntrM, IntrW);
flopenrc #(12) CSRAdrWReg (clk, reset, FlushW, ~StallW, CSRAdrM, CSRAdrW);
flopenrc #(1) CSRWriteWReg (clk, reset, FlushW, ~StallW, CSRWriteM, CSRWriteW);
// Initially connecting the writeback stage signals, but may need to use M stage
// and gate on ~FlushW.
assign valid = InstrValidW & ~StallW;
assign rvvi.clk = clk;
assign #1 rvvi.valid[0][0] = valid;
assign rvvi.order[0][0] = CSRArray[12'hB02]; // TODO: IMPERAS Should be event order
assign rvvi.insn[0][0] = InstrRawW;
assign rvvi.pc_rdata[0][0] = PCW;
assign rvvi.trap[0][0] = 0; // TODO: IMPERAS TrapW;
assign rvvi.halt[0][0] = HaltW;
assign rvvi.intr[0][0] = IntrW;
assign rvvi.mode[0][0] = PrivilegeModeW;
assign rvvi.ixl[0][0] = PrivilegeModeW == 2'b11 ? 2'b10 :
PrivilegeModeW == 2'b01 ? STATUS_SXL : STATUS_UXL;
assign rvvi.pc_wdata[0][0] = ~FlushW ? PCM :
~FlushM ? PCE :
~FlushE ? PCD :
~FlushD ? PCF : PCNextF;
for(index = 0; index < `NUM_REGS; index += 1) begin
assign rvvi.x_wdata[0][0][index] = rf[index];
assign rvvi.x_wb[0][0][index] = rf_wb[index];
assign rvvi.f_wdata[0][0][index] = frf[index];
assign rvvi.f_wb[0][0][index] = frf_wb[index];
end
// record previous csr value.
integer index4;
always_ff @(posedge clk) begin
for (index4 = 0; index4 < `NUM_CSRS; index4 += 1) begin
// IMPERAS
//CSR_W[index4] = (CSRArrayOld[index4] != CSRArray[index4]) ? 1 : 0;
CSRArrayOld[index4] = CSRArray[index4];
end
end
// check for csr value change.
genvar index5;
for(index5 = 0; index5 < `NUM_CSRS; index5 += 1) begin
// CSR_W should only indicate the change when the Writeback stage is not stalled and valid.
assign #2 CSR_W[index5] = (CSRArrayOld[index5] != CSRArray[index5]) ? 1 : 0;
assign rvvi.csr_wb[0][0][index5] = CSR_W[index5];
assign rvvi.csr[0][0][index5] = CSRArray[index5];
end
// always @rvvi.clk $display("%t @rvvi.clk=%X", $time, rvvi.clk);
// always @rvvi.csr[0][0]['h300] $display("%t rvvi.csr[0][0]['h300]=%X", $time, rvvi.csr[0][0]['h300]);
// always @rvvi.csr_wb[0][0]['h300] $display("%t rvvi.csr_wb[0][0]['h300]=%X", $time, rvvi.csr_wb[0][0]['h300]);
// always @rvvi.valid[0][0] $display("%t rvvi.valid[0][0]=%X", $time, rvvi.valid[0][0]);
// *** implementation only cancel? so sc does not clear?
assign rvvi.lrsc_cancel[0][0] = '0;
integer index2;
always_ff @(posedge clk) begin
if(rvvi.valid[0][0]) begin
if(`PRINT_PC_INSTR & !(`PRINT_ALL | `PRINT_MOST))
$display("order = %08d, PC = %08x, insn = %08x", rvvi.order[0][0], rvvi.pc_rdata[0][0], rvvi.insn[0][0]);
else if(`PRINT_MOST & !`PRINT_ALL)
$display("order = %08d, PC = %010x, insn = %08x, trap = %1d, halt = %1d, intr = %1d, mode = %1x, ixl = %1x, pc_wdata = %010x, x%02d = %016x, f%02d = %016x, csr%03x = %016x",
rvvi.order[0][0], rvvi.pc_rdata[0][0], rvvi.insn[0][0], rvvi.trap[0][0], rvvi.halt[0][0], rvvi.intr[0][0], rvvi.mode[0][0], rvvi.ixl[0][0], rvvi.pc_wdata[0][0], rf_a3, rvvi.x_wdata[0][0][rf_a3], frf_a4, rvvi.f_wdata[0][0][frf_a4], CSRAdrW, rvvi.csr[0][0][CSRAdrW]);
else if(`PRINT_ALL) begin
$display("order = %08d, PC = %08x, insn = %08x, trap = %1d, halt = %1d, intr = %1d, mode = %1x, ixl = %1x, pc_wdata = %08x",
rvvi.order[0][0], rvvi.pc_rdata[0][0], rvvi.insn[0][0], rvvi.trap[0][0], rvvi.halt[0][0], rvvi.intr[0][0], rvvi.mode[0][0], rvvi.ixl[0][0], rvvi.pc_wdata[0][0]);
for(index2 = 0; index2 < `NUM_REGS; index2 += 1) begin
$display("x%02d = %08x", index2, rvvi.x_wdata[0][0][index2]);
end
for(index2 = 0; index2 < `NUM_REGS; index2 += 1) begin
$display("f%02d = %08x", index2, rvvi.f_wdata[0][0][index2]);
end
end
if (`PRINT_CSRS) begin
for(index2 = 0; index2 < `NUM_CSRS; index2 += 1) begin
if(CSR_W[index2]) begin
$display("%t: CSR %03x = %x", $time(), index2, CSRArray[index2]);
end
end
end
end
if(HaltW) $finish;
end
endmodule

View File

@ -471,15 +471,20 @@ logic [3:0] dummy;
genvar adrindex;
// Initializing all zeroes into the branch predictor memory.
for(adrindex = 0; adrindex < 1024; adrindex++) begin
for(adrindex = 0; adrindex < 2**10; 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
for(adrindex = 0; adrindex < 2**`BPRED_SIZE; adrindex++) begin
initial begin
force dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex] = 0;
#1;
release dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex];
end
end
if (`BPRED_LOGGER) begin
string direction;

View File

@ -31,10 +31,21 @@
`include "wally-config.vh"
// This is set from the commsnd line script
// `define USE_IMPERAS_DV
`ifdef USE_IMPERAS_DV
`include "rvvi/imperasDV.svh"
`endif
module testbench;
parameter DEBUG=0;
`ifdef USE_IMPERAS_DV
import rvviPkg::*;
import rvviApiPkg::*;
`endif
logic clk;
logic reset_ext, reset;
@ -63,7 +74,7 @@ module testbench;
integer ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 };
logic DCacheFlushDone, DCacheFlushStart;
string testName;
string memfilename, pathname, adrstr;
string memfilename, testDir, adrstr, elffilename;
logic [31:0] GPIOPinsIn, GPIOPinsOut, GPIOPinsEn;
logic UARTSin, UARTSout;
@ -92,28 +103,90 @@ module testbench;
testadr = 0;
testadrNoBase = 0;
//testName = "rv64i_m/I/src/add-01.S";
testName = "rv64i_m/privilege/src/WALLY-mmu-sv48-01.S";
if ($value$plusargs("testDir=%s", testDir)) begin
memfilename = {testDir, "/ref/ref.elf.memfile"};
elffilename = {testDir, "/ref/ref.elf"};
$display($sformatf("%m @ t=%0t: loading testDir %0s", $time, testDir));
end else begin
$error("Must specify test directory using plusarg testDir");
end
//pathname = "../../tests/riscof/work/riscv-arch-test/";
pathname = "../../tests/riscof/work/wally-riscv-arch-test/";
memfilename = {pathname, testName, "/ref/ref.elf.memfile"};
if (`BUS_SUPPORTED) $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM);
else $error("Imperas test bench requires BUS_SUPPORTED.");
ProgramAddrMapFile = {pathname, testName, "/ref/ref.elf.objdump.addr"};
ProgramLabelMapFile = {pathname, testName, "/ref/ref.elf.objdump.lab"};
else $error("Imperas test bench requires BUS.");
ProgramAddrMapFile = {testDir, "/ref/ref.elf.objdump.addr"};
ProgramLabelMapFile = {testDir, "/ref/ref.elf.objdump.lab"};
// 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)
updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray);
$display("Read memfile %s", memfilename);
end
rvviTrace rvviTrace();
rvviTrace #(.XLEN(`XLEN), .FLEN(`FLEN)) rvvi();
wallyTracer wallyTracer(rvvi);
`ifdef USE_IMPERAS_DV
trace2log idv_trace2log(rvvi);
// enabling of comparison types
trace2api #(.CMP_PC (1),
.CMP_INS (1),
.CMP_GPR (1),
.CMP_FPR (1),
.CMP_VR (0),
.CMP_CSR (1)
) idv_trace2api(rvvi);
initial begin
MAX_ERRS = 3;
// Initialize REF (do this before initializing the DUT)
if (!rvviVersionCheck(RVVI_API_VERSION)) begin
msgfatal($sformatf("%m @ t=%0t: Expecting RVVI API version %0d.", $time, RVVI_API_VERSION));
end
void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VENDOR, "riscv.ovpworld.org"));
void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_NAME, "riscv"));
void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VARIANT, "RV64GC"));
if (!rvviRefInit(elffilename)) begin
msgfatal($sformatf("%m @ t=%0t: rvviRefInit failed", $time));
end
// Volatile CSRs
void'(rvviRefCsrSetVolatile(0, 32'hC00)); // CYCLE
void'(rvviRefCsrSetVolatile(0, 32'hB00)); // MCYCLE
void'(rvviRefCsrSetVolatile(0, 32'hC02)); // INSTRET
void'(rvviRefCsrSetVolatile(0, 32'hB02)); // MINSTRET
void'(rvviRefCsrSetVolatile(0, 32'hC01)); // TIME
if(`XLEN==32) begin
void'(rvviRefCsrSetVolatile(0, 32'hC80)); // CYCLEH
void'(rvviRefCsrSetVolatile(0, 32'hB80)); // MCYCLEH
void'(rvviRefCsrSetVolatile(0, 32'hC82)); // INSTRETH
void'(rvviRefCsrSetVolatile(0, 32'hB82)); // MINSTRETH
end
// // Temporary fix for inexact difference
// void'(rvviRefCsrSetVolatile(0, 32'h001)); // fflags
// void'(rvviRefCsrSetVolatile(0, 32'h003)); // fcsr
// Enable the trace2log module
if ($value$plusargs("TRACE2LOG_ENABLE=%d", TRACE2LOG_ENABLE)) begin
msgnote($sformatf("%m @ t=%0t: TRACE2LOG_ENABLE is %0d", $time, TRACE2LOG_ENABLE));
end
if ($value$plusargs("TRACE2COV_ENABLE=%d", TRACE2COV_ENABLE)) begin
msgnote($sformatf("%m @ t=%0t: TRACE2COV_ENABLE is %0d", $time, TRACE2COV_ENABLE));
end
end
final begin
void'(rvviRefShutdown());
end
`endif
flopenr #(`XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW);
flopenr #(32) InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.InstrM, InstrW);
@ -158,7 +231,7 @@ module testbench;
// Track names of instructions
instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE,
dut.core.ifu.FinalInstrRawF[31:0],
dut.core.ifu.InstrRawF[31:0],
dut.core.ifu.InstrD, dut.core.ifu.InstrE,
dut.core.ifu.InstrM, InstrW,
InstrFName, InstrDName, InstrEName, InstrMName, InstrWName);
@ -254,7 +327,6 @@ module testbench;
end
end
endmodule
module riscvassertions;
@ -267,17 +339,17 @@ module riscvassertions;
assert (`F_SUPPORTED | ~`ZFH_SUPPORTED) else $error("Can't support half-precision fp (ZFH) without supporting float (F)");
assert (`DCACHE_SUPPORTED | ~`F_SUPPORTED | `FLEN <= `XLEN) else $error("Data cache required to support FLEN > XLEN because AHB bus width is XLEN");
assert (`I_SUPPORTED ^ `E_SUPPORTED) else $error("Exactly one of I and E must be supported");
assert (`FLEN<=`XLEN | `DCACHE | `DTIM_SUPPORTED) else $error("Wally does not support FLEN > XLEN unleses data cache or DTIM is supported");
assert (`FLEN<=`XLEN | `DCACHE_SUPPORTED | `DTIM_SUPPORTED) else $error("Wally does not support FLEN > XLEN unleses data cache or DTIM is supported");
assert (`DCACHE_WAYSIZEINBYTES <= 4096 | (!`DCACHE_SUPPORTED) | `VIRTMEM_SUPPORTED == 0) else $error("DCACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing)");
assert (`DCACHE_LINELENINBITS >= 128 | (!`DCACH_SUPPORTED)) else $error("DCACHE_LINELENINBITS must be at least 128 when caches are enabled");
assert (`DCACHE_LINELENINBITS >= 128 | (!`DCACHE_SUPPORTED)) else $error("DCACHE_LINELENINBITS must be at least 128 when caches are enabled");
assert (`DCACHE_LINELENINBITS < `DCACHE_WAYSIZEINBYTES*8) else $error("DCACHE_LINELENINBITS must be smaller than way size");
assert (`ICACHE_WAYSIZEINBYTES <= 4096 | (!`ICACHE_SUPPORTED) | `VIRTMEM_SUPPORTED == 0) else $error("ICACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing)");
assert (`ICACHE_LINELENINBITS >= 32 | (!`ICACHE_SUPPORTED)) else $error("ICACHE_LINELENINBITS must be at least 32 when caches are enabled");
assert (`ICACHE_LINELENINBITS < `ICACHE_WAYSIZEINBYTES*8) else $error("ICACHE_LINELENINBITS must be smaller than way size");
assert (2**$clog2(`DCACHE_LINELENINBITS) == `DCACHE_LINELENINBITS | (!`DCACHE)) else $error("DCACHE_LINELENINBITS must be a power of 2");
assert (2**$clog2(`DCACHE_WAYSIZEINBYTES) == `DCACHE_WAYSIZEINBYTES | (!`DCACHE)) else $error("DCACHE_WAYSIZEINBYTES must be a power of 2");
assert (2**$clog2(`ICACHE_LINELENINBITS) == `ICACHE_LINELENINBITS | (!`ICACHE)) else $error("ICACHE_LINELENINBITS must be a power of 2");
assert (2**$clog2(`ICACHE_WAYSIZEINBYTES) == `ICACHE_WAYSIZEINBYTES | (!`ICACHE)) else $error("ICACHE_WAYSIZEINBYTES must be a power of 2");
assert (2**$clog2(`DCACHE_LINELENINBITS) == `DCACHE_LINELENINBITS | (!`DCACHE_SUPPORTED)) else $error("DCACHE_LINELENINBITS must be a power of 2");
assert (2**$clog2(`DCACHE_WAYSIZEINBYTES) == `DCACHE_WAYSIZEINBYTES | (!`DCACHE_SUPPORTED)) else $error("DCACHE_WAYSIZEINBYTES must be a power of 2");
assert (2**$clog2(`ICACHE_LINELENINBITS) == `ICACHE_LINELENINBITS | (!`ICACHE_SUPPORTED)) else $error("ICACHE_LINELENINBITS must be a power of 2");
assert (2**$clog2(`ICACHE_WAYSIZEINBYTES) == `ICACHE_WAYSIZEINBYTES | (!`ICACHE_SUPPORTED)) else $error("ICACHE_WAYSIZEINBYTES must be a power of 2");
assert (2**$clog2(`ITLB_ENTRIES) == `ITLB_ENTRIES | `VIRTMEM_SUPPORTED==0) else $error("ITLB_ENTRIES must be a power of 2");
assert (2**$clog2(`DTLB_ENTRIES) == `DTLB_ENTRIES | `VIRTMEM_SUPPORTED==0) else $error("DTLB_ENTRIES must be a power of 2");
assert (`UNCORE_RAM_RANGE >= 56'h07FFFFFF) else $warning("Some regression tests will fail if UNCORE_RAM_RANGE is less than 56'h07FFFFFF");
@ -288,7 +360,7 @@ module riscvassertions;
assert (`DCACHE_SUPPORTED | `VIRTMEM_SUPPORTED ==0) else $error("Virtual memory needs dcache");
assert (`ICACHE_SUPPORTED | `VIRTMEM_SUPPORTED ==0) else $error("Virtual memory needs icache");
assert ((`DCACHE_SUPPORTED == 0 & `ICACHE_SUPPORTED == 0) | `BUS_SUPPORTED) else $error("Dcache and Icache requires DBUS.");
assert (`DCACHE_LINELENINBITS <= `XLEN*16 | (!`DCACHE)) else $error("DCACHE_LINELENINBITS must not exceed 16 words because max AHB burst size is 1");
assert (`DCACHE_LINELENINBITS <= `XLEN*16 | (!`DCACHE_SUPPORTED)) else $error("DCACHE_LINELENINBITS must not exceed 16 words because max AHB burst size is 1");
assert (`DCACHE_LINELENINBITS % 4 == 0) else $error("DCACHE_LINELENINBITS must hold 4, 8, or 16 words");
assert (`DCACHE_SUPPORTED | `A_SUPPORTED == 0) else $error("Atomic extension (A) requires cache on Wally.");
assert (`IDIV_ON_FPU == 0 | `F_SUPPORTED) else $error("IDIV on FPU needs F_SUPPORTED");
@ -311,7 +383,7 @@ module DCacheFlushFSM
logic [`XLEN-1:0] ShadowRAM[`UNCORE_RAM_BASE>>(1+`XLEN/32):(`UNCORE_RAM_RANGE+`UNCORE_RAM_BASE)>>1+(`XLEN/32)];
if(`DCACHE) begin
if(`DCACHE_SUPPORTED) begin
localparam integer numlines = testbench.dut.core.lsu.bus.dcache.dcache.NUMLINES;
localparam integer numways = testbench.dut.core.lsu.bus.dcache.dcache.NUMWAYS;
localparam integer linebytelen = testbench.dut.core.lsu.bus.dcache.dcache.LINEBYTELEN;
@ -413,6 +485,7 @@ module copyShadow
end
end
endmodule
task automatic updateProgramAddrLabelArray;

57
setup.imperas.sh Normal file
View File

@ -0,0 +1,57 @@
#!/bin/bash
IMP_HASH=56b1479
REPO=davidharrishmc
REPO=eroom1966
git clone https://github.com/${REPO}/riscv-wally -b imperas
cd riscv-wally
WALLY=$(dirname ${BASH_SOURCE[0]:-$0})
export WALLY=$(cd "$WALLY" && pwd)
# clone the Imperas repo
if [ ! -d external ]; then
mkdir -p external
fi
pushd external
if [ ! -f ImperasDV-HMC ]; then
git clone git@github.com:Imperas/ImperasDV-HMC.git
fi
pushd ImperasDV-HMC
git checkout $IMP_HASH
popd
popd
# Setup Imperas
source ${WALLY}/external/ImperasDV-HMC/Imperas/bin/setup.sh
setupImperas ${WALLY}/external/ImperasDV-HMC/Imperas
export IMPERAS_PERSONALITY=CPUMAN_DV_ASYNC
# setup QUESTA (Imperas only command, YMMV)
svsetup -questa
pushd pipelined/regression
# With IDV
IMPERAS_TOOLS=$(pwd)/imperas.ic \
OTHERFLAGS="+TRACE2LOG_ENABLE=1 VERBOSE=1" \
TESTDIR=${WALLY}/external/ImperasDV-HMC/tests/riscof/work/riscv-arch-test/rv64i_m/F/src/fadd_b1-01.S \
vsim -c -do "do wally-pipelined-imperas.do rv64gc"
popd
# notes
# run the pushd external code
#source external/ImperasDV-HMC/Imperas/bin/setup.sh
# setupImperas /home/ross/repos/active-wally/riscv-wally/external/ImperasDV-HMC/Imperas
# env | grep IMPERAS
# export IMPERAS_PERSONALITY=CPUMAN_DV_ASYNC
IMPERAS_TOOLS=$(pwd)/imperas.ic \
OTHERFLAGS="+TRACE2LOG_ENABLE=1 VERBOSE=1" \
TESTDIR=../../tests/riscof_lee/work/riscv-arch-test/rv64i_m/F/src/fadd_b1-01.S \
vsim -c -do "do wally-pipelined-imperas.do rv64gc"
# getting library issue.
# try switching to modelsim 2022.01