mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
merged script install file
This commit is contained in:
commit
ea8f424b78
2
.gitignore
vendored
2
.gitignore
vendored
@ -190,3 +190,5 @@ benchmarks/embench/run*
|
||||
sim/cfi.log
|
||||
sim/cfi/*
|
||||
sim/branch/*
|
||||
sim/obj_dir
|
||||
examples/verilog/fulladder/obj_dir
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit eb0a3892215ad2384702db02da1551a59701ec67
|
||||
Subproject commit c955abf757df98cf38809e40a62d2a6b448ea507
|
@ -167,7 +167,7 @@ sudo ln -sf $RISCV/sail-riscv/c_emulator/riscv_sim_RV32 /usr/bin/riscv_sim_RV32
|
||||
|
||||
# riscof
|
||||
sudo pip3 install -U testresources riscv_config
|
||||
pip3 install git+https://github.com/riscv/riscof.git
|
||||
sudo pip3 install git+https://github.com/riscv/riscof.git
|
||||
|
||||
# Download OSU Skywater 130 cell library
|
||||
sudo mkdir -p $RISCV/cad/lib
|
||||
|
@ -35,7 +35,7 @@ localparam XLEN = 32'd32;
|
||||
// IEEE 754 compliance
|
||||
localparam IEEE754 = 0;
|
||||
|
||||
localparam MISA = (32'h00000104 | 1 << 1 | 1 << 20 | 1 << 18 | 1 << 12 | 1 << 0 | 1 <<3 | 1 << 5);
|
||||
localparam MISA = (32'h00000104 | 1 << 20 | 1 << 18 | 1 << 12 | 1 << 0 | 1 <<3 | 1 << 5);
|
||||
localparam ZICSR_SUPPORTED = 1;
|
||||
localparam ZIFENCEI_SUPPORTED = 1;
|
||||
localparam COUNTERS = 12'd32;
|
||||
|
@ -34,7 +34,7 @@ localparam XLEN = 32'd64;
|
||||
localparam IEEE754 = 0;
|
||||
|
||||
// MISA RISC-V configuration per specification
|
||||
localparam MISA = (32'h00000104 | 1 << 1 | 1 << 5 | 1 << 3 | 1 << 18 | 1 << 20 | 1 << 12 | 1 << 0);
|
||||
localparam MISA = (32'h00000104 | 1 << 5 | 1 << 3 | 1 << 18 | 1 << 20 | 1 << 12 | 1 << 0);
|
||||
localparam ZICSR_SUPPORTED = 1;
|
||||
localparam ZIFENCEI_SUPPORTED = 1;
|
||||
localparam COUNTERS = 12'd32;
|
||||
|
@ -3,6 +3,7 @@ module testbench();
|
||||
logic a, b, c, s, cout, sexpected, coutexpected;
|
||||
logic [31:0] vectornum, errors;
|
||||
logic [4:0] testvectors[10000:0];
|
||||
integer cycle;
|
||||
|
||||
// instantiate device under test
|
||||
fulladder dut(a, b, c, s, cout);
|
||||
@ -11,12 +12,15 @@ module testbench();
|
||||
always
|
||||
begin
|
||||
clk = 1; #5; clk = 0; #5;
|
||||
cycle = cycle + 1;
|
||||
$display("cycle: %x vectornum %x testvectors[vectornum]: %b", cycle, vectornum, testvectors[vectornum]);
|
||||
end
|
||||
|
||||
// at start of test, load vectors and pulse reset
|
||||
initial
|
||||
begin
|
||||
$readmemb("fulladder.tv", testvectors);
|
||||
cycle = 0;
|
||||
vectornum = 0; errors = 0;
|
||||
reset = 1; #22; reset = 0;
|
||||
end
|
||||
@ -36,10 +40,11 @@ module testbench();
|
||||
errors = errors + 1;
|
||||
end
|
||||
vectornum = vectornum + 1;
|
||||
if (testvectors[vectornum] === 5'bx) begin
|
||||
//if (testvectors[vectornum] === 5'bx) begin
|
||||
if (vectornum === 10) begin
|
||||
$display("%d tests completed with %d errors",
|
||||
vectornum, errors);
|
||||
$stop;
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
5
examples/verilog/fulladder/verilate
Executable file
5
examples/verilog/fulladder/verilate
Executable file
@ -0,0 +1,5 @@
|
||||
#verilator --timescale "1ns/1ns" --timing -cc --exe --build --top-module testbench fulladder.sv
|
||||
#verilator --timescale "1ns/1ns" --timing -cc --exe --top-module testbench fulladder.sv
|
||||
#verilator --binary --top-module testbench fulladder.sv
|
||||
verilator --timescale "1ns/1ns" --timing --binary --top-module testbench fulladder.sv
|
||||
|
@ -17,8 +17,7 @@ all: riscoftests memfiles coveragetests
|
||||
|
||||
wally-riscv-arch-test: wallyriscoftests memfiles
|
||||
|
||||
coverage:
|
||||
#make -C ../tests/coverage --jobs
|
||||
coverage: cov/rv64gc_arch64i.ucdb
|
||||
#iter-elf.bash --cover --search ../tests/coverage
|
||||
vcover merge -out cov/cov.ucdb cov/rv64gc_arch64i.ucdb cov/rv64gc*.ucdb -logfile cov/log
|
||||
# vcover merge -out cov/cov.ucdb cov/rv64gc_arch64i.ucdb cov/rv64gc*.ucdb cov/buildroot_buildroot.ucdb riscv.ucdb -logfile cov/log
|
||||
@ -60,4 +59,4 @@ memfiles:
|
||||
make -f makefile-memfile wally-sim-files --jobs
|
||||
|
||||
coveragetests:
|
||||
make -C ../tests/coverage/
|
||||
make -C ../tests/coverage/ --jobs
|
||||
|
@ -68,8 +68,9 @@ coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange $sta
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheBusW"]
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache SelAdrCauses"] -item e 1 -fecexprrow 4 10
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/cachefsm -linerange [GetLineNum ../src/cache/cachefsm.sv "exclusion-tag: icache CacheBusRCauses"] -item e 1 -fecexprrow 1-2 12
|
||||
# cache.sv AdrSelMux and CacheBusAdrMux, excluding unhit Flush branch
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/AdrSelMux -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1
|
||||
# cache.sv AdrSelMuxData and AdrSelMuxTag and CacheBusAdrMux, excluding unhit Flush branch
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/AdrSelMuxData -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/AdrSelMuxTag -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1
|
||||
coverage exclude -scope /dut/core/ifu/bus/icache/icache/CacheBusAdrMux -linerange [GetLineNum ../src/generic/mux.sv "exclusion-tag: mux3"] -item b 1 3
|
||||
# CacheWay Dirty logic. -scope does not accept wildcards.
|
||||
set numcacheways 4
|
||||
@ -106,6 +107,10 @@ coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/clintdec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/gpiodec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/uartdec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/plicdec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/dtimdec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/iromdec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/ddr4dec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/sdcdec
|
||||
|
||||
# PMA Regions 8, 9, and 10 (dtim, irom, ddr4) are never used in the rv64gc configuration, so exclude coverage
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "exclusion-tag: unused-cachable"]
|
||||
@ -114,19 +119,13 @@ coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$lin
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "exclusion-tag: unused-idempotent"]
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2,4,6
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2,4,6,8
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "exclusion-tag: unused-atomic"]
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2,4
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2,4
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "exclusion-tag: unused-tim"]
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2,4
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2,4
|
||||
|
||||
# Excluding so far un-used instruction sources for the ifu
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/bootromdec
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/uncoreramdec
|
||||
# coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/bootromdec
|
||||
# coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/uncoreramdec
|
||||
|
||||
#Excluding the bootrom, uncoreran, and clint as sources for the lsu
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/bootromdec
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/bootromdec
|
||||
|
||||
#Excluding signals in lsu: clintdec and uncoreram accept all sizes so 'SizeValid' will never be 0
|
||||
set line [GetLineNum ../src/mmu/adrdec.sv "& SizeValid"]
|
||||
@ -134,25 +133,29 @@ coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/clintdec -lin
|
||||
set line [GetLineNum ../src/mmu/adrdec.sv "& SizeValid"]
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/uncoreramdec -linerange $line-$line -item e 1 -fecexprrow 5
|
||||
|
||||
set line [GetLineNum ../src/mmu/adrdec.sv "& Supported"]
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/dtimdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/iromdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/ddr4dec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/gpiodec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/uartdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/plicdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/sdcdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/dtimdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/iromdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/ddr4dec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/sdcdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# set line [GetLineNum ../src/mmu/adrdec.sv "& Supported"]
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/dtimdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/iromdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/ddr4dec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/gpiodec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/uartdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/plicdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/sdcdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/dtimdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/iromdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/ddr4dec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
# coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker/adrdecs/sdcdec -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/dtimdec
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/iromdec
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/ddr4dec
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker/adrdecs/sdcdec
|
||||
|
||||
####################
|
||||
# Unused access types due to sharing IFU and LSU logic
|
||||
####################
|
||||
|
||||
## The lsu never executes instructions so 'ExecuteAccessF' will never be 1
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "AccessRWX ="]
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "AccessRWXC ="]
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 6
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "ReadAccessM \\| ExecuteAccessF"]
|
||||
coverage exclude -scope /dut/core/lsu/dmmu/dmmu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 4
|
||||
@ -181,9 +184,9 @@ set line [GetLineNum ../src/mmu/pmachecker.sv "ExecuteAccessF & PMAAccessFault"]
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 1
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "ReadAccessM & PMAAccessFault"]
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2-4
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "WriteAccessM & PMAAccessFault"]
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 2-4
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "AccessRWX \\| AtomicAccessM"]
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "PMAStoreAmoAccessFaultM ="]
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line
|
||||
set line [GetLineNum ../src/mmu/pmachecker.sv "AccessRWXC \\| AtomicAccessM"]
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu/pmachecker -linerange $line-$line -item e 1 -fecexprrow 3
|
||||
set line [GetLineNum ../src/mmu/mmu.sv "ExecuteAccessF \\| ReadAccessM"]
|
||||
coverage exclude -scope /dut/core/ifu/immu/immu -linerange $line-$line -item e 1 -fecexprrow 1,3,4
|
||||
@ -231,6 +234,12 @@ coverage exclude -scope /dut/core/ifu -linerange $line-$line -item c 1 -feccondr
|
||||
set line [GetLineNum ../src/generic/flop/floprc.sv "reset \\| clear"]
|
||||
coverage exclude -scope /dut/core/priv/priv/pmd/wfi/wficountreg -linerange $line-$line -item c 1 -feccondrow 2
|
||||
|
||||
# Exclude system reset case in ebu
|
||||
set line [GetLineNum ../src/ebu/ebufsmarb.sv "BeatCounter\\("]
|
||||
coverage exclude -scope /dut/core/ebu/ebu/ebufsmarb -linerange $line-$line -item e 1 -fecexprrow 1
|
||||
set line [GetLineNum ../src/ebu/ebufsmarb.sv "FinalBeatReg\\("]
|
||||
coverage exclude -scope /dut/core/ebu/ebu/ebufsmarb -linerange $line-$line -item e 1 -fecexprrow 1
|
||||
|
||||
# TLB not recently used never has all RU bits = 1 because it will then clear all to 0
|
||||
# This is a blunt instrument; perhaps there is a more graceful exclusion
|
||||
coverage exclude -srcfile priorityonehot.sv
|
||||
|
@ -51,9 +51,13 @@
|
||||
--override cpu/unaligned=T # Zicclsm (should be true)
|
||||
--override cpu/ignore_non_leaf_DAU=1
|
||||
--override cpu/wfi_is_nop=T
|
||||
--override cpu/misa_Extensions_mask=0x0
|
||||
--override cpu/misa_Extensions_mask=0x0 # MISA not writable
|
||||
--override cpu/Sstc=T
|
||||
|
||||
# unsuccessfully attempt to add B extension (DH 12/21/23)
|
||||
#--override cpu/add_Extensions="B"
|
||||
#--override cpu/misa_Extensions=0x0014112F
|
||||
|
||||
# Enable SVADU hardware update of A/D bits when menvcfg.ADUE=1
|
||||
--override cpu/Svadu=T
|
||||
#--override cpu/updatePTEA=F
|
||||
|
@ -78,7 +78,8 @@ for test in tests64i:
|
||||
configs.append(tc)
|
||||
|
||||
tests32gcimperas = ["imperas32i", "imperas32f", "imperas32m", "imperas32c"] # unused
|
||||
tests32gc = ["arch32f", "arch32d", "arch32f_fma", "arch32d_fma", "arch32i", "arch32priv", "arch32c", "arch32m", "arch32a", "arch32zi", "arch32zba", "arch32zbb", "arch32zbc", "arch32zbs", "wally32a", "wally32priv", "wally32periph"]
|
||||
tests32gc = ["arch32f", "arch32d", "arch32f_fma", "arch32d_fma", "arch32i", "arch32priv", "arch32c", "arch32m", "arch32a", "arch32zifencei", "arch32zba", "arch32zbb", "arch32zbc", "arch32zbs", "wally32a", "wally32priv", "wally32periph"]
|
||||
#tests32gc = ["arch32f", "arch32d", "arch32f_fma", "arch32d_fma", "arch32i", "arch32priv", "arch32c", "arch32m", "arch32a", "arch32zifencei", "arch32zba", "arch32zbb", "arch32zbc", "arch32zbs", "arch32zicboz", "arch32zcb", "wally32a", "wally32priv", "wally32periph"]
|
||||
for test in tests32gc:
|
||||
tc = TestCase(
|
||||
name=test,
|
||||
@ -126,15 +127,19 @@ for test in ahbTests:
|
||||
configs.append(tc)
|
||||
|
||||
tests64gc = ["arch64f", "arch64d", "arch64f_fma", "arch64d_fma", "arch64i", "arch64zba", "arch64zbb", "arch64zbc", "arch64zbs",
|
||||
"arch64priv", "arch64c", "arch64m", "arch64a", "arch64zi", "wally64a", "wally64periph", "wally64priv"]
|
||||
"arch64priv", "arch64c", "arch64m", "arch64a", "arch64zifencei", "wally64a", "wally64periph", "wally64priv"]
|
||||
#tests64gc = ["arch64f", "arch64d", "arch64f_fma", "arch64d_fma", "arch64i", "arch64zba", "arch64zbb", "arch64zbc", "arch64zbs",
|
||||
# "arch64priv", "arch64c", "arch64m", "arch64a", "arch64zifencei", "wally64a", "wally64periph", "wally64priv", "arch64zicboz", "arch64zcb"]
|
||||
if (coverage): # delete all but 64gc tests when running coverage
|
||||
configs = []
|
||||
tests64gc = ["coverage64gc", "arch64i", "arch64priv", "arch64c", "arch64m",
|
||||
"arch64zi", "wally64a", "wally64periph", "wally64priv",
|
||||
"arch64zba", "arch64zbb", "arch64zbc", "arch64zbs"]
|
||||
"arch64zifencei", "wally64a", "wally64periph", "wally64priv",
|
||||
"arch64zba", "arch64zbb", "arch64zbc", "arch64zbs"] # add when working: "arch64zicboz", "arch64zcb",
|
||||
if (fp):
|
||||
tests64gc.append("arch64f")
|
||||
tests64gc.append("arch64d")
|
||||
tests64gc.append("arch64f_fma")
|
||||
tests64gc.append("arch64d_fma")
|
||||
coverStr = '-coverage'
|
||||
else:
|
||||
coverStr = ''
|
||||
|
@ -8,9 +8,11 @@ basepath=$(dirname $0)/..
|
||||
#for config in rv32e rv64gc rv32gc rv32imc rv32i rv64i rv64fpquad; do
|
||||
for config in rv64gc; do
|
||||
echo "$config simulating..."
|
||||
if !($verilator --timescale "1ns/1ns" --timing --exe --cc "$@" --top-module testbench "-I$basepath/config/shared" "-I$basepath/config/$config" $basepath/src/cvw.sv $basepath/testbench/testbench.sv $basepath/testbench/common/*.sv $basepath/src/*/*.sv $basepath/src/*/*/*.sv --relative-includes ); then
|
||||
# not working: -GTEST="arch64i"
|
||||
if !($verilator --timescale "1ns/1ns" --timing --binary "$@" --top-module testbench "-I$basepath/config/shared" "-I$basepath/config/$config" $basepath/src/cvw.sv $basepath/testbench/testbench.sv $basepath/testbench/common/*.sv $basepath/src/*/*.sv $basepath/src/*/*/*.sv --relative-includes ); then
|
||||
echo "Exiting after $config lint due to errors or warnings"
|
||||
exit 1
|
||||
fi
|
||||
./obj_dir/Vtestbench
|
||||
done
|
||||
echo "Verilation complete"
|
||||
|
53
sim/wave.do
53
sim/wave.do
@ -8,11 +8,11 @@ add wave -noupdate /testbench/dut/core/SATP_REGW
|
||||
add wave -noupdate /testbench/dut/core/InstrValidM
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/hzu/RetM
|
||||
add wave -noupdate -expand -group HDU -group hazards -color Pink /testbench/dut/core/hzu/TrapM
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/hzu/LoadStallD
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/ieu/c/LoadStallD
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/ifu/IFUStallF
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/hzu/BPWrongE
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/hzu/LSUStallM
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/MDUStallD
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/ieu/c/MDUStallD
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/hzu/DivBusyE
|
||||
add wave -noupdate -expand -group HDU -group hazards /testbench/dut/core/hzu/FDivBusyE
|
||||
add wave -noupdate -expand -group HDU -group traps /testbench/dut/core/priv/priv/trap/InstrMisalignedFaultM
|
||||
@ -59,14 +59,13 @@ add wave -noupdate -group {PCNext Generation} /testbench/dut/core/ifu/PCSrcE
|
||||
add wave -noupdate -group {PCNext Generation} /testbench/dut/core/ifu/PC1NextF
|
||||
add wave -noupdate -group {PCNext Generation} -label {NextValidPCE (from bpred)} /testbench/dut/core/ifu/NextValidPCE
|
||||
add wave -noupdate -group {PCNext Generation} /testbench/dut/core/ifu/CSRWriteFenceM
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 /testbench/dut/core/priv/priv/csr/PC2NextF
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 -group xepc /testbench/dut/core/priv/priv/csr/MEPC_REGW
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 -group xepc /testbench/dut/core/priv/priv/csr/SEPC_REGW
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 -group xepc /testbench/dut/core/priv/priv/csr/mretM
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 -group xepc /testbench/dut/core/priv/priv/csr/EPC
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 -group xepc /testbench/dut/core/priv/priv/EPCM
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 /testbench/dut/core/priv/priv/csr/TrapVectorM
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 /testbench/dut/core/priv/priv/csr/TrapM
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 /testbench/dut/core/priv/priv/csr/RetM
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 /testbench/dut/core/priv/priv/RetM
|
||||
add wave -noupdate -group {PCNext Generation} -expand -group pcmux3 /testbench/dut/core/ifu/UnalignedPCNextF
|
||||
add wave -noupdate -group {PCNext Generation} /testbench/dut/core/ifu/PCNextF
|
||||
add wave -noupdate -group {PCNext Generation} /testbench/dut/core/ifu/PCF
|
||||
@ -195,9 +194,9 @@ add wave -noupdate -group {Decode Stage} /testbench/dut/core/ifu/InstrD
|
||||
add wave -noupdate -group {Decode Stage} /testbench/InstrDName
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/c/InstrValidD
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/c/RegWriteD
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/dp/RdD
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/dp/Rs1D
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/dp/Rs2D
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/c/RdD
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/c/Rs1D
|
||||
add wave -noupdate -group {Decode Stage} /testbench/dut/core/ieu/c/Rs2D
|
||||
add wave -noupdate -group {Execution Stage} /testbench/dut/core/ifu/PCE
|
||||
add wave -noupdate -group {Execution Stage} /testbench/dut/core/ifu/InstrE
|
||||
add wave -noupdate -group {Execution Stage} /testbench/InstrEName
|
||||
@ -251,13 +250,12 @@ add wave -noupdate -group lsu /testbench/dut/core/lsu/IEUAdrExtE
|
||||
add wave -noupdate -group lsu /testbench/dut/core/lsu/IEUAdrExtM
|
||||
add wave -noupdate -group lsu /testbench/dut/core/lsu/bus/dcache/dcache/NextSet
|
||||
add wave -noupdate -group lsu -expand -group dcache /testbench/dut/core/lsu/bus/dcache/dcache/CacheRW
|
||||
add wave -noupdate -group lsu -expand -group dcache /testbench/dut/core/lsu/bus/dcache/dcache/CMOp
|
||||
add wave -noupdate -group lsu -expand -group dcache /testbench/dut/core/lsu/bus/dcache/dcache/CMOpM
|
||||
add wave -noupdate -group lsu -expand -group dcache -color Gold /testbench/dut/core/lsu/bus/dcache/dcache/cachefsm/CurrState
|
||||
add wave -noupdate -group lsu -expand -group dcache -group SRAM-update-control /testbench/dut/core/lsu/bus/dcache/dcache/SetValid
|
||||
add wave -noupdate -group lsu -expand -group dcache -group SRAM-update-control /testbench/dut/core/lsu/bus/dcache/dcache/ClearValid
|
||||
add wave -noupdate -group lsu -expand -group dcache -group SRAM-update-control /testbench/dut/core/lsu/bus/dcache/dcache/SetDirty
|
||||
add wave -noupdate -group lsu -expand -group dcache -group SRAM-update-control /testbench/dut/core/lsu/bus/dcache/dcache/ClearDirty
|
||||
add wave -noupdate -group lsu -expand -group dcache -group SRAM-update-control /testbench/dut/core/lsu/bus/dcache/dcache/SelFlush
|
||||
add wave -noupdate -group lsu -expand -group dcache -group SRAM-update-control /testbench/dut/core/lsu/bus/dcache/dcache/SelWay
|
||||
add wave -noupdate -group lsu -expand -group dcache -group {requesting address} /testbench/dut/core/lsu/IEUAdrE
|
||||
add wave -noupdate -group lsu -expand -group dcache -group {requesting address} /testbench/dut/core/lsu/bus/dcache/dcache/PAdr
|
||||
@ -291,7 +289,6 @@ add wave -noupdate -group lsu -expand -group dcache -group flush /testbench/dut/
|
||||
add wave -noupdate -group lsu -expand -group dcache -group flush /testbench/dut/core/lsu/bus/dcache/dcache/FlushWayCntEn
|
||||
add wave -noupdate -group lsu -expand -group dcache -group flush /testbench/dut/core/lsu/bus/dcache/dcache/cachefsm/FlushAdrCntEn
|
||||
add wave -noupdate -group lsu -expand -group dcache -group flush /testbench/dut/core/lsu/bus/dcache/dcache/FlushAdrFlag
|
||||
add wave -noupdate -group lsu -expand -group dcache -group flush /testbench/dut/core/lsu/bus/dcache/dcache/cachefsm/SelFlush
|
||||
add wave -noupdate -group lsu -expand -group dcache -group {Cache SRAM writes} /testbench/dut/core/lsu/bus/dcache/dcache/SetValid
|
||||
add wave -noupdate -group lsu -expand -group dcache -group {Cache SRAM writes} /testbench/dut/core/lsu/bus/dcache/dcache/ClearValid
|
||||
add wave -noupdate -group lsu -expand -group dcache -group {Cache SRAM writes} /testbench/dut/core/lsu/bus/dcache/dcache/SetDirty
|
||||
@ -626,24 +623,24 @@ add wave -noupdate -group alu /testbench/dut/core/ieu/dp/alu/B
|
||||
add wave -noupdate -group alu /testbench/dut/core/ieu/dp/alu/ALUResult
|
||||
add wave -noupdate -group alu /testbench/dut/core/ieu/dp/alu/BALUControl
|
||||
add wave -noupdate -group alu -divider internals
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/Rs1D
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/Rs2D
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/Rs1E
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/Rs2E
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/RdE
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/RdM
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/RdW
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/MemReadE
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/RegWriteM
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/RegWriteW
|
||||
add wave -noupdate -group Forward -color Thistle /testbench/dut/core/ieu/fw/ForwardAE
|
||||
add wave -noupdate -group Forward -color Thistle /testbench/dut/core/ieu/fw/ForwardBE
|
||||
add wave -noupdate -group Forward -color Thistle /testbench/dut/core/ieu/fw/LoadStallD
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/Rs1D
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/Rs2D
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/Rs1E
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/Rs2E
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/RdE
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/RdM
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/RdW
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/MemReadE
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/RegWriteM
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/RegWriteW
|
||||
add wave -noupdate -group Forward -color Thistle /testbench/dut/core/ieu/c/ForwardAE
|
||||
add wave -noupdate -group Forward -color Thistle /testbench/dut/core/ieu/c/ForwardBE
|
||||
add wave -noupdate -group Forward -color Thistle /testbench/dut/core/ieu/c/LoadStallD
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/dp/IFResultM
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/ForwardAE
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/Rs1E
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/RdM
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/fw/RdW
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/ForwardAE
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/Rs1E
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/RdM
|
||||
add wave -noupdate -group Forward /testbench/dut/core/ieu/c/RdW
|
||||
add wave -noupdate -group {alu execution stage} /testbench/dut/core/ieu/dp/ALUResultE
|
||||
add wave -noupdate -group {alu execution stage} /testbench/dut/core/ieu/dp/SrcAE
|
||||
add wave -noupdate -group {alu execution stage} /testbench/dut/core/ieu/dp/SrcBE
|
||||
|
20
src/cache/cache.sv
vendored
20
src/cache/cache.sv
vendored
@ -34,11 +34,10 @@ module cache import cvw::*; #(parameter cvw_t P,
|
||||
input logic Stall, // Stall the cache, preventing new accesses. In-flight access finished but does not return to READY
|
||||
input logic FlushStage, // Pipeline flush of second stage (prevent writes and bus operations)
|
||||
// cpu side
|
||||
input logic [1:0] CacheRWNext, // [1] Read, [0] Write
|
||||
input logic [1:0] CacheRW, // [1] Read, [0] Write
|
||||
input logic FlushCache, // Flush all dirty lines back to memory
|
||||
input logic InvalidateCache, // Clear all valid bits
|
||||
input logic [3:0] CMOp, // 1: cbo.inval; 2: cbo.flush; 4: cbo.clean; 8: cbo.zero
|
||||
input logic [3:0] CMOpM, // 1: cbo.inval; 2: cbo.flush; 4: cbo.clean; 8: cbo.zero
|
||||
input logic [11:0] NextSet, // Virtual address, but we only use the lower 12 bits.
|
||||
input logic [PA_BITS-1:0] PAdr, // Physical address
|
||||
input logic [(WORDLEN-1)/8:0] ByteMask, // Which bytes to write (D$ only)
|
||||
@ -94,7 +93,6 @@ module cache import cvw::*; #(parameter cvw_t P,
|
||||
logic FlushWayCntEn;
|
||||
logic SelWriteback;
|
||||
logic LRUWriteEn;
|
||||
logic SelFlush;
|
||||
logic ResetOrFlushCntRst;
|
||||
logic [LINELEN-1:0] ReadDataLine, ReadDataLineCache;
|
||||
logic SelFetchBuffer;
|
||||
@ -112,10 +110,10 @@ module cache import cvw::*; #(parameter cvw_t P,
|
||||
// and FlushAdr when handling D$ flushes
|
||||
// The icache must update to the newest PCNextF on flush as it is probably a trap. Trap
|
||||
// sets PCNextF to XTVEC and the icache must start reading the instruction.
|
||||
assign AdrSelMuxSelData = {SelFlush, ((SelAdrData | SelHPTW) & ~((READ_ONLY_CACHE == 1) & FlushStage))};
|
||||
assign AdrSelMuxSelData = {FlushCache, ((SelAdrData | SelHPTW) & ~((READ_ONLY_CACHE == 1) & FlushStage))};
|
||||
mux3 #(SETLEN) AdrSelMuxData(NextSet[SETTOP-1:OFFSETLEN], PAdr[SETTOP-1:OFFSETLEN], FlushAdr,
|
||||
AdrSelMuxSelData, CacheSetData);
|
||||
assign AdrSelMuxSelTag = {SelFlush, ((SelAdrTag | SelHPTW) & ~((READ_ONLY_CACHE == 1) & FlushStage))};
|
||||
assign AdrSelMuxSelTag = {FlushCache, ((SelAdrTag | SelHPTW) & ~((READ_ONLY_CACHE == 1) & FlushStage))};
|
||||
mux3 #(SETLEN) AdrSelMuxTag(NextSet[SETTOP-1:OFFSETLEN], PAdr[SETTOP-1:OFFSETLEN], FlushAdr,
|
||||
AdrSelMuxSelTag, CacheSetTag);
|
||||
|
||||
@ -123,7 +121,7 @@ module cache import cvw::*; #(parameter cvw_t P,
|
||||
cacheway #(P, PA_BITS, XLEN, NUMLINES, LINELEN, TAGLEN, OFFSETLEN, SETLEN, READ_ONLY_CACHE) CacheWays[NUMWAYS-1:0](
|
||||
.clk, .reset, .CacheEn, .CacheSetData, .CacheSetTag, .PAdr, .LineWriteData, .LineByteMask, .SelWay,
|
||||
.SetValid, .ClearValid, .SetDirty, .ClearDirty, .VictimWay,
|
||||
.FlushWay, .SelFlush, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .HitDirtyWay, .TagWay, .FlushStage, .InvalidateCache);
|
||||
.FlushWay, .FlushCache, .ReadDataLineWay, .HitWay, .ValidWay, .DirtyWay, .HitDirtyWay, .TagWay, .FlushStage, .InvalidateCache);
|
||||
|
||||
// Select victim way for associative caches
|
||||
if(NUMWAYS > 1) begin:vict
|
||||
@ -162,7 +160,7 @@ module cache import cvw::*; #(parameter cvw_t P,
|
||||
mux3 #(PA_BITS) CacheBusAdrMux(.d0({PAdr[PA_BITS-1:OFFSETLEN], {OFFSETLEN{1'b0}}}),
|
||||
.d1({Tag, PAdr[SETTOP-1:OFFSETLEN], {OFFSETLEN{1'b0}}}),
|
||||
.d2({Tag, FlushAdr, {OFFSETLEN{1'b0}}}),
|
||||
.s({SelFlush, SelWriteback}), .y(CacheBusAdr));
|
||||
.s({FlushCache, SelWriteback}), .y(CacheBusAdr));
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Write Path
|
||||
@ -186,7 +184,7 @@ module cache import cvw::*; #(parameter cvw_t P,
|
||||
// Merge write data into fetched cache line for store miss
|
||||
for(index = 0; index < LINELEN/8; index++) begin
|
||||
mux2 #(8) WriteDataMux(.d0(CacheWriteData[(8*index)%WORDLEN+7:(8*index)%WORDLEN]),
|
||||
.d1(FetchBuffer[8*index+7:8*index]), .s(FetchBufferByteSel[index] & ~CMOp[3]), .y(LineWriteData[8*index+7:8*index]));
|
||||
.d1(FetchBuffer[8*index+7:8*index]), .s(FetchBufferByteSel[index] & ~CMOpM[3]), .y(LineWriteData[8*index+7:8*index]));
|
||||
end
|
||||
assign LineByteMask = SetValid ? '1 : SetDirty ? DemuxedByteMask : '0;
|
||||
end
|
||||
@ -225,11 +223,11 @@ module cache import cvw::*; #(parameter cvw_t P,
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
cachefsm #(P, READ_ONLY_CACHE) cachefsm(.clk, .reset, .CacheBusRW, .CacheBusAck,
|
||||
.FlushStage, .CacheRW, .CacheRWNext, .Stall,
|
||||
.FlushStage, .CacheRW, .Stall,
|
||||
.CacheHit, .LineDirty, .HitLineDirty, .CacheStall, .CacheCommitted,
|
||||
.CacheMiss, .CacheAccess, .SelAdrData, .SelAdrTag, .SelWay,
|
||||
.ClearDirty, .SetDirty, .SetValid, .ClearValid, .SelWriteback, .SelFlush,
|
||||
.ClearDirty, .SetDirty, .SetValid, .ClearValid, .SelWriteback,
|
||||
.FlushAdrCntEn, .FlushWayCntEn, .FlushCntRst,
|
||||
.FlushAdrFlag, .FlushWayFlag, .FlushCache, .SelFetchBuffer,
|
||||
.InvalidateCache, .CMOp, .CacheEn, .LRUWriteEn);
|
||||
.InvalidateCache, .CMOpM, .CacheEn, .LRUWriteEn);
|
||||
endmodule
|
||||
|
46
src/cache/cachefsm.sv
vendored
46
src/cache/cachefsm.sv
vendored
@ -38,10 +38,9 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
output logic CacheStall, // Cache stalls pipeline during multicycle operation
|
||||
// inputs from IEU
|
||||
input logic [1:0] CacheRW, // [1] Read, [0] Write
|
||||
input logic [1:0] CacheRWNext, // [1] Read, [0] Write
|
||||
input logic FlushCache, // Flush all dirty lines back to memory
|
||||
input logic InvalidateCache, // Clear all valid bits
|
||||
input logic [3:0] CMOp, // 1: cbo.inval; 2: cbo.flush; 4: cbo.clean; 8: cbo.zero
|
||||
input logic [3:0] CMOpM, // 0001: cbo.inval; 0010: cbo.flush; 0100: cbo.clean; 1000: cbo.zero
|
||||
// Bus controls
|
||||
input logic CacheBusAck, // Bus operation completed
|
||||
output logic [1:0] CacheBusRW, // [1] Read (cache line fetch) or [0] write bus (cache line writeback)
|
||||
@ -63,7 +62,6 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
output logic ClearDirty, // Clear the dirty bit in the selected way and set
|
||||
output logic SelWriteback, // Overrides cached tag check to select a specific way and set for writeback
|
||||
output logic LRUWriteEn, // Update the LRU state
|
||||
output logic SelFlush, // [0] Use SelAdr, [1] SRAM reads/writes from FlushAdr
|
||||
output logic SelWay, // Controls which way to select a way data and tag, 00 = hitway, 10 = victimway, 11 = flushway
|
||||
output logic FlushAdrCntEn, // Enable the counter for Flush Adr
|
||||
output logic FlushWayCntEn, // Enable the way counter during a flush
|
||||
@ -79,7 +77,6 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
logic CMOWriteback;
|
||||
logic CMOZeroNoEviction;
|
||||
logic StallConditions;
|
||||
logic StoreHazard;
|
||||
|
||||
typedef enum logic [3:0]{STATE_READY, // hit states
|
||||
// miss states
|
||||
@ -97,8 +94,8 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
assign AnyMiss = (CacheRW[0] | CacheRW[1]) & ~CacheHit & ~InvalidateCache; // exclusion-tag: cache AnyMiss
|
||||
assign AnyUpdateHit = (CacheRW[0]) & CacheHit; // exclusion-tag: icache storeAMO1
|
||||
assign AnyHit = AnyUpdateHit | (CacheRW[1] & CacheHit); // exclusion-tag: icache AnyUpdateHit
|
||||
assign CMOZeroNoEviction = CMOp[3] & ~LineDirty; // (hit or miss) with no writeback store zeros now
|
||||
assign CMOWriteback = ((CMOp[1] | CMOp[2]) & CacheHit & HitLineDirty) | CMOp[3] & LineDirty;
|
||||
assign CMOZeroNoEviction = CMOpM[3] & ~LineDirty; // (hit or miss) with no writeback store zeros now
|
||||
assign CMOWriteback = ((CMOpM[1] | CMOpM[2]) & CacheHit & HitLineDirty) | CMOpM[3] & LineDirty;
|
||||
|
||||
assign FlushFlag = FlushAdrFlag & FlushWayFlag;
|
||||
|
||||
@ -106,8 +103,6 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
assign CacheAccess = (|CacheRW) & ((CurrState == STATE_READY & ~Stall & ~FlushStage) | (CurrState == STATE_READ_HOLD & ~Stall & ~FlushStage)); // exclusion-tag: icache CacheW
|
||||
assign CacheMiss = CacheAccess & ~CacheHit;
|
||||
|
||||
assign StoreHazard = CacheRWNext[1] & CacheRW[0] & ~CacheRW[1];
|
||||
|
||||
// special case on reset. When the fsm first exists reset the
|
||||
// PCNextF will no longer be pointing to the correct address.
|
||||
// But PCF will be the reset vector.
|
||||
@ -124,7 +119,6 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
else if(FlushCache & ~READ_ONLY_CACHE) NextState = STATE_FLUSH;
|
||||
else if(AnyMiss & (READ_ONLY_CACHE | ~LineDirty)) NextState = STATE_FETCH; // exclusion-tag: icache FETCHStatement
|
||||
else if(AnyMiss | CMOWriteback) NextState = STATE_WRITEBACK; // exclusion-tag: icache WRITEBACKStatement
|
||||
else if(StoreHazard) NextState = STATE_READ_HOLD;
|
||||
else NextState = STATE_READY;
|
||||
STATE_FETCH: if(CacheBusAck) NextState = STATE_WRITE_LINE;
|
||||
else if(CacheBusAck) NextState = STATE_READY;
|
||||
@ -133,7 +127,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
STATE_READ_HOLD: if(Stall) NextState = STATE_READ_HOLD;
|
||||
else NextState = STATE_READY;
|
||||
// exclusion-tag-start: icache case
|
||||
STATE_WRITEBACK: if(CacheBusAck & ~(|CMOp[3:1])) NextState = STATE_FETCH;
|
||||
STATE_WRITEBACK: if(CacheBusAck & ~(|CMOpM[3:1])) NextState = STATE_FETCH;
|
||||
else if(CacheBusAck) NextState = STATE_READ_HOLD; // Read_hold lowers CacheStall
|
||||
else NextState = STATE_WRITEBACK;
|
||||
// eviction needs a delay as the bus fsm does not correctly handle sending the write command at the same time as getting back the bus ack.
|
||||
@ -150,7 +144,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
|
||||
// com back to CPU
|
||||
assign CacheCommitted = (CurrState != STATE_READY) & ~(READ_ONLY_CACHE & (CurrState == STATE_READ_HOLD));
|
||||
assign StallConditions = FlushCache | AnyMiss | CMOWriteback | (StoreHazard);
|
||||
assign StallConditions = FlushCache | AnyMiss | CMOWriteback;
|
||||
assign CacheStall = (CurrState == STATE_READY & StallConditions) | // exclusion-tag: icache StallStates
|
||||
(CurrState == STATE_FETCH) |
|
||||
(CurrState == STATE_WRITEBACK) |
|
||||
@ -160,32 +154,26 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
// write enables internal to cache
|
||||
assign SetValid = CurrState == STATE_WRITE_LINE |
|
||||
(CurrState == STATE_READY & CMOZeroNoEviction) |
|
||||
(CurrState == STATE_WRITEBACK & CacheBusAck & CMOp[3]);
|
||||
assign ClearValid = (CurrState == STATE_READY & CMOp[0]) |
|
||||
(CurrState == STATE_WRITEBACK & CMOp[2] & CacheBusAck);
|
||||
(CurrState == STATE_WRITEBACK & CacheBusAck & CMOpM[3]);
|
||||
assign ClearValid = (CurrState == STATE_READY & CMOpM[0]) |
|
||||
(CurrState == STATE_WRITEBACK & CMOpM[2] & CacheBusAck);
|
||||
// coverage off -item e 1 -fecexprrow 8
|
||||
assign LRUWriteEn = (((CurrState == STATE_READY & (AnyHit | CMOZeroNoEviction)) |
|
||||
(CurrState == STATE_WRITE_LINE)) & ~FlushStage) |
|
||||
(CurrState == STATE_WRITEBACK & CMOp[3] & CacheBusAck);
|
||||
(CurrState == STATE_WRITEBACK & CMOpM[3] & CacheBusAck);
|
||||
// exclusion-tag-start: icache flushdirtycontrols
|
||||
assign SetDirty = (CurrState == STATE_READY & (AnyUpdateHit | CMOZeroNoEviction)) | // exclusion-tag: icache SetDirty
|
||||
(CurrState == STATE_WRITE_LINE & (CacheRW[0])) |
|
||||
(CurrState == STATE_WRITEBACK & (CMOp[3] & CacheBusAck));
|
||||
(CurrState == STATE_WRITEBACK & (CMOpM[3] & CacheBusAck));
|
||||
assign ClearDirty = (CurrState == STATE_WRITE_LINE & ~(CacheRW[0])) | // exclusion-tag: icache ClearDirty
|
||||
(CurrState == STATE_FLUSH & LineDirty) | // This is wrong in a multicore snoop cache protocal. Dirty must be cleared concurrently and atomically with writeback. For single core cannot clear after writeback on bus ack and change flushadr. Clears the wrong set.
|
||||
// Flush and eviction controls
|
||||
CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2]) & CacheBusAck;
|
||||
assign SelWay = (CurrState == STATE_WRITEBACK & ((~CacheBusAck & ~(CMOp[1] | CMOp[2])) | (CacheBusAck & CMOp[3]))) |
|
||||
CurrState == STATE_WRITEBACK & (CMOpM[1] | CMOpM[2]) & CacheBusAck;
|
||||
assign SelWay = (CurrState == STATE_WRITEBACK & ((~CacheBusAck & ~(CMOpM[1] | CMOpM[2])) | (CacheBusAck & CMOpM[3]))) |
|
||||
(CurrState == STATE_READY & ((AnyMiss & LineDirty) | (CMOZeroNoEviction & ~CacheHit))) |
|
||||
(CurrState == STATE_WRITE_LINE);
|
||||
assign SelWriteback = (CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2] | ~CacheBusAck)) |
|
||||
assign SelWriteback = (CurrState == STATE_WRITEBACK & (CMOpM[1] | CMOpM[2] | ~CacheBusAck)) |
|
||||
(CurrState == STATE_READY & AnyMiss & LineDirty);
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
assign SelFlush = (CurrState == STATE_READY & FlushCache) |
|
||||
(CurrState == STATE_FLUSH) |
|
||||
(CurrState == STATE_FLUSH_WRITEBACK);
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
assign SelFlush = FlushCache;
|
||||
// coverage off -item e 1 -fecexprrow 1
|
||||
// (state is always FLUSH_WRITEBACK when FlushWayFlag & CacheBusAck)
|
||||
assign FlushAdrCntEn = (CurrState == STATE_FLUSH_WRITEBACK & FlushWayFlag & CacheBusAck) |
|
||||
@ -198,7 +186,7 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
// Bus interface controls
|
||||
assign CacheBusRW[1] = (CurrState == STATE_READY & AnyMiss & ~LineDirty) | // exclusion-tag: icache CacheBusRCauses
|
||||
(CurrState == STATE_FETCH & ~CacheBusAck) |
|
||||
(CurrState == STATE_WRITEBACK & CacheBusAck & ~(|CMOp));
|
||||
(CurrState == STATE_WRITEBACK & CacheBusAck & ~(|CMOpM));
|
||||
|
||||
logic LoadMiss;
|
||||
|
||||
@ -208,14 +196,14 @@ module cachefsm import cvw::*; #(parameter cvw_t P,
|
||||
assign CacheBusRW[0] = (CurrState == STATE_READY & LoadMiss & LineDirty) | // exclusion-tag: icache CacheBusW
|
||||
(CurrState == STATE_WRITEBACK & ~CacheBusAck) |
|
||||
(CurrState == STATE_FLUSH_WRITEBACK & ~CacheBusAck) |
|
||||
(CurrState == STATE_WRITEBACK & (CMOp[1] | CMOp[2]) & ~CacheBusAck);
|
||||
(CurrState == STATE_WRITEBACK & (CMOpM[1] | CMOpM[2]) & ~CacheBusAck);
|
||||
|
||||
assign SelAdrData = (CurrState == STATE_READY & (CacheRW[0] | AnyMiss | (|CMOp))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed
|
||||
assign SelAdrData = (CurrState == STATE_READY & (CacheRW[0] | AnyMiss | (|CMOpM))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed
|
||||
(CurrState == STATE_FETCH) |
|
||||
(CurrState == STATE_WRITEBACK) |
|
||||
(CurrState == STATE_WRITE_LINE) |
|
||||
resetDelay;
|
||||
assign SelAdrTag = (CurrState == STATE_READY & (AnyMiss | (|CMOp))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed
|
||||
assign SelAdrTag = (CurrState == STATE_READY & (AnyMiss | (|CMOpM))) | // exclusion-tag: icache SelAdrCauses // changes if store delay hazard removed
|
||||
(CurrState == STATE_FETCH) |
|
||||
(CurrState == STATE_WRITEBACK) |
|
||||
(CurrState == STATE_WRITE_LINE) |
|
||||
|
8
src/cache/cacheway.sv
vendored
8
src/cache/cacheway.sv
vendored
@ -43,7 +43,7 @@ module cacheway import cvw::*; #(parameter cvw_t P,
|
||||
input logic SetDirty, // Set the dirty bit in the selected way and set
|
||||
input logic SelWay, // Controls which way to select a way data and tag, 00 = hitway, 10 = victimway, 11 = flushway
|
||||
input logic ClearDirty, // Clear the dirty bit in the selected way and set
|
||||
input logic SelFlush, // [0] Use SelAdr, [1] SRAM reads/writes from FlushAdr
|
||||
input logic FlushCache, // [0] Use SelAdr, [1] SRAM reads/writes from FlushAdr
|
||||
input logic VictimWay, // LRU selected this way as victim to evict
|
||||
input logic FlushWay, // This way is selected for flush and possible writeback if dirty
|
||||
input logic InvalidateCache,// Clear all valid bits
|
||||
@ -80,12 +80,12 @@ module cacheway import cvw::*; #(parameter cvw_t P,
|
||||
|
||||
if (!READ_ONLY_CACHE) begin:flushlogic
|
||||
logic FlushWayEn;
|
||||
mux2 #(1) seltagmux(VictimWay, FlushWay, SelFlush, SelDirty);
|
||||
mux2 #(1) seltagmux(VictimWay, FlushWay, FlushCache, SelDirty);
|
||||
|
||||
// FlushWay is part of a one hot way selection. Must clear it if FlushWay not selected.
|
||||
// coverage off -item e 1 -fecexprrow 3
|
||||
// nonzero ways will never see SelFlush=0 while FlushWay=1 since FlushWay only advances on a subset of SelFlush assertion cases.
|
||||
assign FlushWayEn = FlushWay & SelFlush;
|
||||
// nonzero ways will never see FlushCache=0 while FlushWay=1 since FlushWay only advances on a subset of FlushCache assertion cases.
|
||||
assign FlushWayEn = FlushWay & FlushCache;
|
||||
assign SelNonHit = FlushWayEn | SelWay;
|
||||
end else begin:flushlogic // no flush operation for read-only caches.
|
||||
assign SelDirty = VictimWay;
|
||||
|
@ -65,6 +65,7 @@ module ahbcacheinterface #(
|
||||
input logic [PA_BITS-1:0] PAdr, // Physical address of uncached memory operation
|
||||
input logic [LLEN-1:0] WriteDataM, // IEU write data for uncached store
|
||||
input logic [1:0] BusRW, // Uncached memory operation read/write control: 10: read, 01: write
|
||||
input logic BusAtomic, // Uncache atomic memory operation
|
||||
input logic [2:0] Funct3, // Size of uncached memory operation
|
||||
input logic BusCMOZero, // Uncached cbo.zero must write zero to full sized cacheline without going through the cache
|
||||
|
||||
@ -121,7 +122,7 @@ module ahbcacheinterface #(
|
||||
flopen #(AHBW/8) HWSTRBReg(HCLK, HREADY, BusByteMaskM[AHBW/8-1:0], HWSTRB);
|
||||
|
||||
buscachefsm #(BeatCountThreshold, AHBWLOGBWPL, READ_ONLY_CACHE) AHBBuscachefsm(
|
||||
.HCLK, .HRESETn, .Flush, .BusRW, .Stall, .BusCommitted, .BusStall, .CaptureEn, .SelBusBeat,
|
||||
.HCLK, .HRESETn, .Flush, .BusRW, .BusAtomic, .Stall, .BusCommitted, .BusStall, .CaptureEn, .SelBusBeat,
|
||||
.CacheBusRW, .BusCMOZero, .CacheBusAck, .BeatCount, .BeatCountDelayed,
|
||||
.HREADY, .HTRANS, .HWRITE, .HBURST);
|
||||
endmodule
|
||||
|
@ -42,6 +42,7 @@ module buscachefsm #(
|
||||
input logic Stall, // Core pipeline is stalled
|
||||
input logic Flush, // Pipeline stage flush. Prevents bus transaction from starting
|
||||
input logic [1:0] BusRW, // Uncached memory operation read/write control: 10: read, 01: write
|
||||
input logic BusAtomic, // Uncache atomic memory operation
|
||||
input logic BusCMOZero, // Uncached cbo.zero must write zero to full sized cacheline without going through the cache
|
||||
output logic BusStall, // Bus is busy with an in flight memory operation
|
||||
output logic BusCommitted, // Bus is busy with an in flight memory operation and it is not safe to take an interrupt
|
||||
@ -65,7 +66,7 @@ module buscachefsm #(
|
||||
output logic [2:0] HBURST // AHB burst length
|
||||
);
|
||||
|
||||
typedef enum logic [2:0] {ADR_PHASE, DATA_PHASE, MEM3, CACHE_FETCH, CACHE_WRITEBACK} busstatetype;
|
||||
typedef enum logic [2:0] {ADR_PHASE, DATA_PHASE, ATOMIC_PHASE, MEM3, CACHE_FETCH, CACHE_WRITEBACK} busstatetype;
|
||||
typedef enum logic [1:0] {AHB_IDLE = 2'b00, AHB_BUSY = 2'b01, AHB_NONSEQ = 2'b10, AHB_SEQ = 2'b11} ahbtranstype;
|
||||
|
||||
busstatetype CurrState, NextState;
|
||||
@ -90,16 +91,20 @@ module buscachefsm #(
|
||||
else if (HREADY & BusWrite) NextState = CACHE_WRITEBACK;
|
||||
else if (HREADY & CacheBusRW[1]) NextState = CACHE_FETCH;
|
||||
else NextState = ADR_PHASE;
|
||||
DATA_PHASE: if(HREADY) NextState = MEM3;
|
||||
DATA_PHASE: if(HREADY & BusAtomic) NextState = ATOMIC_PHASE;
|
||||
else if(HREADY & ~BusAtomic) NextState = MEM3;
|
||||
else NextState = DATA_PHASE;
|
||||
ATOMIC_PHASE: if(HREADY) NextState = MEM3;
|
||||
else NextState = ATOMIC_PHASE;
|
||||
MEM3: if(Stall) NextState = MEM3;
|
||||
else NextState = ADR_PHASE;
|
||||
CACHE_FETCH: if(HREADY & FinalBeatCount & BusWrite) NextState = CACHE_WRITEBACK;
|
||||
CACHE_FETCH: if(HREADY & FinalBeatCount & CacheBusRW[0]) NextState = CACHE_WRITEBACK;
|
||||
else if(HREADY & FinalBeatCount & CacheBusRW[1]) NextState = CACHE_FETCH;
|
||||
else if(HREADY & FinalBeatCount & ~|CacheBusRW) NextState = ADR_PHASE;
|
||||
else NextState = CACHE_FETCH;
|
||||
CACHE_WRITEBACK: if(HREADY & FinalBeatCount & BusWrite) NextState = CACHE_WRITEBACK;
|
||||
CACHE_WRITEBACK: if(HREADY & FinalBeatCount & CacheBusRW[0]) NextState = CACHE_WRITEBACK;
|
||||
else if(HREADY & FinalBeatCount & CacheBusRW[1]) NextState = CACHE_FETCH;
|
||||
else if(HREADY & FinalBeatCount & BusCMOZero) NextState = MEM3;
|
||||
else if(HREADY & FinalBeatCount & ~|CacheBusRW) NextState = ADR_PHASE;
|
||||
else NextState = CACHE_WRITEBACK;
|
||||
default: NextState = ADR_PHASE;
|
||||
@ -120,19 +125,23 @@ module buscachefsm #(
|
||||
assign CaptureEn = (CurrState == DATA_PHASE & BusRW[1] & ~Flush) | (CurrState == CACHE_FETCH & HREADY);
|
||||
assign CacheAccess = CurrState == CACHE_FETCH | CurrState == CACHE_WRITEBACK;
|
||||
|
||||
assign BusStall = (CurrState == ADR_PHASE & ((|BusRW) | (|CacheBusRW))) |
|
||||
assign BusStall = (CurrState == ADR_PHASE & ((|BusRW) | (|CacheBusRW) | BusCMOZero)) |
|
||||
//(CurrState == DATA_PHASE & ~BusRW[0]) | // *** replace the next line with this. Fails uart test but i think it's a test problem not a hardware problem.
|
||||
(CurrState == DATA_PHASE) |
|
||||
(CurrState == CACHE_FETCH & ~HREADY) |
|
||||
(CurrState == CACHE_WRITEBACK & ~HREADY);
|
||||
(CurrState == ATOMIC_PHASE) |
|
||||
(CurrState == CACHE_FETCH & ~FinalBeatCount) |
|
||||
(CurrState == CACHE_WRITEBACK & ~FinalBeatCount);
|
||||
|
||||
assign BusCommitted = (CurrState != ADR_PHASE) & ~(READ_ONLY_CACHE & CurrState == MEM3);
|
||||
|
||||
// AHB bus interface
|
||||
assign HTRANS = (CurrState == ADR_PHASE & HREADY & ((|BusRW) | (|CacheBusRW)) & ~Flush) |
|
||||
assign HTRANS = (CurrState == ADR_PHASE & HREADY & ((|BusRW) | (|CacheBusRW) | BusCMOZero) & ~Flush) |
|
||||
(CurrState == DATA_PHASE & BusAtomic) |
|
||||
(CacheAccess & FinalBeatCount & |CacheBusRW & HREADY & ~Flush) ? AHB_NONSEQ : // if we have a pipelined request
|
||||
(CacheAccess & |BeatCount) ? (`BURST_EN ? AHB_SEQ : AHB_NONSEQ) : AHB_IDLE;
|
||||
|
||||
assign HWRITE = (BusRW[0] | BusWrite & ~Flush) | (CurrState == CACHE_WRITEBACK & |BeatCount);
|
||||
assign HWRITE = ((BusRW[0] & ~BusAtomic) | BusWrite & ~Flush) | (CurrState == DATA_PHASE & BusAtomic) |
|
||||
(CurrState == CACHE_WRITEBACK & |BeatCount);
|
||||
assign HBURST = `BURST_EN & ((|CacheBusRW & ~Flush) | (CacheAccess & |BeatCount)) ? LocalBurstType : 3'b0;
|
||||
|
||||
always_comb begin
|
||||
@ -149,6 +158,7 @@ module buscachefsm #(
|
||||
assign CacheBusAck = (CacheAccess & HREADY & FinalBeatCount & ~BusCMOZero);
|
||||
assign SelBusBeat = (CurrState == ADR_PHASE & (BusRW[0] | BusWrite)) |
|
||||
(CurrState == DATA_PHASE & BusRW[0]) |
|
||||
(CurrState == ATOMIC_PHASE & BusRW[0]) |
|
||||
(CurrState == CACHE_WRITEBACK) |
|
||||
(CurrState == CACHE_FETCH);
|
||||
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
module hazard import cvw::*; #(parameter cvw_t P) (
|
||||
input logic BPWrongE, CSRWriteFenceM, RetM, TrapM,
|
||||
input logic LoadStallD, StoreStallD, MDUStallD, CSRRdStallD,
|
||||
input logic StructuralStallD,
|
||||
input logic LSUStallM, IFUStallF,
|
||||
input logic FCvtIntStallD, FPUStallD,
|
||||
input logic FPUStallD,
|
||||
input logic DivBusyE, FDivBusyE,
|
||||
input logic wfiM, IntPendingM,
|
||||
// Stall & flush outputs
|
||||
@ -82,7 +82,7 @@ module hazard import cvw::*; #(parameter cvw_t P) (
|
||||
// The IFU stalls the entire pipeline rather than just Fetch to avoid complications with instructions later in the pipeline causing Exceptions
|
||||
// A trap could be asserted at the start of a IFU/LSU stall, and should flush the memory operation
|
||||
assign StallFCause = '0;
|
||||
assign StallDCause = (LoadStallD | StoreStallD | MDUStallD | CSRRdStallD | FCvtIntStallD | FPUStallD) & ~FlushDCause;
|
||||
assign StallDCause = (StructuralStallD | FPUStallD) & ~FlushDCause;
|
||||
assign StallECause = (DivBusyE | FDivBusyE) & ~FlushECause;
|
||||
assign StallMCause = WFIStallM & ~FlushMCause;
|
||||
// Need to gate IFUStallF when the equivalent FlushFCause = FlushDCause = 1.
|
||||
|
@ -27,8 +27,8 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module alu import cvw::*; #(parameter cvw_t P, parameter WIDTH) (
|
||||
input logic [WIDTH-1:0] A, B, // Operands
|
||||
module alu import cvw::*; #(parameter cvw_t P) (
|
||||
input logic [P.XLEN-1:0] A, B, // Operands
|
||||
input logic W64, // W64-type instruction
|
||||
input logic SubArith, // Subtraction or arithmetic shift
|
||||
input logic [2:0] ALUSelect, // ALU mux select signal
|
||||
@ -37,14 +37,14 @@ module alu import cvw::*; #(parameter cvw_t P, parameter WIDTH) (
|
||||
input logic [2:0] Funct3, // For BMU decoding
|
||||
input logic [2:0] BALUControl, // ALU Control signals for B instructions in Execute Stage
|
||||
input logic BMUActiveE, // Bit manipulation instruction being executed
|
||||
output logic [WIDTH-1:0] ALUResult, // ALU result
|
||||
output logic [WIDTH-1:0] Sum); // Sum of operands
|
||||
output logic [P.XLEN-1:0] ALUResult, // ALU result
|
||||
output logic [P.XLEN-1:0] Sum); // Sum of operands
|
||||
|
||||
// CondInvB = ~B when subtracting, B otherwise. Shift = shift result. SLT/U = result of a slt/u instruction.
|
||||
// FullResult = ALU result before adjusting for a RV64 w-suffix instruction.
|
||||
logic [WIDTH-1:0] CondMaskInvB, Shift, FullResult, PreALUResult; // Intermediate Signals
|
||||
logic [WIDTH-1:0] CondMaskB; // Result of B mask select mux
|
||||
logic [WIDTH-1:0] CondShiftA; // Result of A shifted select mux
|
||||
logic [P.XLEN-1:0] CondMaskInvB, Shift, FullResult, PreALUResult; // Intermediate Signals
|
||||
logic [P.XLEN-1:0] CondMaskB; // Result of B mask select mux
|
||||
logic [P.XLEN-1:0] CondShiftA; // Result of A shifted select mux
|
||||
logic Carry, Neg; // Flags: carry out, negative
|
||||
logic LT, LTU; // Less than, Less than unsigned
|
||||
logic Asign, Bsign; // Sign bits of A, B
|
||||
@ -53,7 +53,7 @@ module alu import cvw::*; #(parameter cvw_t P, parameter WIDTH) (
|
||||
// CondMaskB is B for add/sub, or a masked version of B for certain bit manipulation instructions
|
||||
// CondShiftA is A for add/sub or a shifted version of A for shift-and-add BMU instructions
|
||||
assign CondMaskInvB = SubArith ? ~CondMaskB : CondMaskB;
|
||||
assign {Carry, Sum} = CondShiftA + CondMaskInvB + {{(WIDTH-1){1'b0}}, SubArith};
|
||||
assign {Carry, Sum} = CondShiftA + CondMaskInvB + {{(P.XLEN-1){1'b0}}, SubArith};
|
||||
|
||||
// Shifts (configurable for rotation)
|
||||
shifter #(P) sh(.A, .Amt(B[P.LOG_XLEN-1:0]), .Right(Funct3[2]), .W64, .SubArith, .Y(Shift), .Rotate(BALUControl[2]));
|
||||
@ -62,9 +62,9 @@ module alu import cvw::*; #(parameter cvw_t P, parameter WIDTH) (
|
||||
// Overflow occurs when the numbers being subtracted have the opposite sign
|
||||
// and the result has the opposite sign of A.
|
||||
// LT is simplified from Overflow = Asign & Bsign & Asign & Neg; LT = Neg ^ Overflow
|
||||
assign Neg = Sum[WIDTH-1];
|
||||
assign Asign = A[WIDTH-1];
|
||||
assign Bsign = B[WIDTH-1];
|
||||
assign Neg = Sum[P.XLEN-1];
|
||||
assign Asign = A[P.XLEN-1];
|
||||
assign Bsign = B[P.XLEN-1];
|
||||
assign LT = Asign & ~Bsign | Asign & Neg | ~Bsign & Neg;
|
||||
assign LTU = ~Carry;
|
||||
|
||||
@ -73,21 +73,22 @@ module alu import cvw::*; #(parameter cvw_t P, parameter WIDTH) (
|
||||
case (ALUSelect)
|
||||
3'b000: FullResult = Sum; // add or sub (including address generation)
|
||||
3'b001: FullResult = Shift; // sll, sra, or srl
|
||||
3'b010: FullResult = {{(WIDTH-1){1'b0}}, LT}; // slt
|
||||
3'b011: FullResult = {{(WIDTH-1){1'b0}}, LTU}; // sltu
|
||||
3'b010: FullResult = {{(P.XLEN-1){1'b0}}, LT}; // slt
|
||||
3'b011: FullResult = {{(P.XLEN-1){1'b0}}, LTU}; // sltu
|
||||
3'b100: FullResult = A ^ CondMaskInvB; // xor, xnor, binv
|
||||
3'b101: FullResult = (P.ZBS_SUPPORTED | P.ZBB_SUPPORTED) ? {{(WIDTH-1){1'b0}},{|(A & CondMaskB)}} : Shift; // bext (or IEU shift when BMU not supported)
|
||||
3'b101: FullResult = (P.ZBS_SUPPORTED | P.ZBB_SUPPORTED) ? {{(P.XLEN-1){1'b0}},{|(A & CondMaskB)}} : Shift; // bext (or IEU shift when BMU not supported)
|
||||
3'b110: FullResult = A | CondMaskInvB; // or, orn, bset
|
||||
3'b111: FullResult = A & CondMaskInvB; // and, bclr
|
||||
endcase
|
||||
|
||||
// Support RV64I W-type addw/subw/addiw/shifts that discard upper 32 bits and sign-extend 32-bit result to 64 bits
|
||||
if (WIDTH == 64) assign PreALUResult = W64 ? {{32{FullResult[31]}}, FullResult[31:0]} : FullResult;
|
||||
if (P.XLEN == 64) assign PreALUResult = W64 ? {{32{FullResult[31]}}, FullResult[31:0]} : FullResult;
|
||||
else assign PreALUResult = FullResult;
|
||||
|
||||
// Final Result B instruction select mux
|
||||
if (P.ZBC_SUPPORTED | P.ZBS_SUPPORTED | P.ZBA_SUPPORTED | P.ZBB_SUPPORTED) begin : bitmanipalu
|
||||
bitmanipalu #(P, WIDTH) balu(.A, .B, .W64, .BSelect, .ZBBSelect, .BMUActiveE,
|
||||
bitmanipalu #(P) balu(
|
||||
.A, .B, .W64, .BSelect, .ZBBSelect, .BMUActiveE,
|
||||
.Funct3, .LT,.LTU, .BALUControl, .PreALUResult, .FullResult,
|
||||
.CondMaskB, .CondShiftA, .ALUResult);
|
||||
end else begin
|
||||
|
@ -27,9 +27,8 @@
|
||||
// and limitations under the License.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module bitmanipalu import cvw::*; #(parameter cvw_t P,
|
||||
parameter WIDTH=32) (
|
||||
input logic [WIDTH-1:0] A, B, // Operands
|
||||
module bitmanipalu import cvw::*; #(parameter cvw_t P) (
|
||||
input logic [P.XLEN-1:0] A, B, // Operands
|
||||
input logic W64, // W64-type instruction
|
||||
input logic [1:0] BSelect, // Binary encoding of if it's a ZBA_ZBB_ZBC_ZBS instruction
|
||||
input logic [2:0] ZBBSelect, // ZBB mux select signal
|
||||
@ -38,37 +37,37 @@ module bitmanipalu import cvw::*; #(parameter cvw_t P,
|
||||
input logic LTU, // less than unsigned flag
|
||||
input logic [2:0] BALUControl, // ALU Control signals for B instructions in Execute Stage
|
||||
input logic BMUActiveE, // Bit manipulation instruction being executed
|
||||
input logic [WIDTH-1:0] PreALUResult, FullResult,// PreALUResult, FullResult signals
|
||||
output logic [WIDTH-1:0] CondMaskB, // B is conditionally masked for ZBS instructions
|
||||
output logic [WIDTH-1:0] CondShiftA, // A is conditionally shifted for ShAdd instructions
|
||||
output logic [WIDTH-1:0] ALUResult); // Result
|
||||
input logic [P.XLEN-1:0] PreALUResult, FullResult,// PreALUResult, FullResult signals
|
||||
output logic [P.XLEN-1:0] CondMaskB, // B is conditionally masked for ZBS instructions
|
||||
output logic [P.XLEN-1:0] CondShiftA, // A is conditionally shifted for ShAdd instructions
|
||||
output logic [P.XLEN-1:0] ALUResult); // Result
|
||||
|
||||
logic [WIDTH-1:0] ZBBResult, ZBCResult; // ZBB, ZBC Result
|
||||
logic [WIDTH-1:0] MaskB; // BitMask of B
|
||||
logic [WIDTH-1:0] RevA; // Bit-reversed A
|
||||
logic [P.XLEN-1:0] ZBBResult, ZBCResult; // ZBB, ZBC Result
|
||||
logic [P.XLEN-1:0] MaskB; // BitMask of B
|
||||
logic [P.XLEN-1:0] RevA; // Bit-reversed A
|
||||
logic Rotate; // Indicates if it is Rotate instruction
|
||||
logic Mask; // Indicates if it is ZBS instruction
|
||||
logic PreShift; // Inidicates if it is sh1add, sh2add, sh3add instruction
|
||||
logic [1:0] PreShiftAmt; // Amount to Pre-Shift A
|
||||
logic [WIDTH-1:0] CondZextA; // A Conditional Extend Intermediary Signal
|
||||
logic [WIDTH-1:0] ABMU, BBMU; // Gated data inputs to reduce BMU activity
|
||||
logic [P.XLEN-1:0] CondZextA; // A Conditional Extend Intermediary Signal
|
||||
logic [P.XLEN-1:0] ABMU, BBMU; // Gated data inputs to reduce BMU activity
|
||||
|
||||
// gate data inputs to BMU to only operate when BMU is active
|
||||
assign ABMU = A & {WIDTH{BMUActiveE}};
|
||||
assign BBMU = B & {WIDTH{BMUActiveE}};
|
||||
assign ABMU = A & {P.XLEN{BMUActiveE}};
|
||||
assign BBMU = B & {P.XLEN{BMUActiveE}};
|
||||
|
||||
// Extract control signals from bitmanip ALUControl.
|
||||
assign {Mask, PreShift} = BALUControl[1:0];
|
||||
|
||||
// Mask Generation Mux
|
||||
if (P.ZBS_SUPPORTED) begin: zbsdec
|
||||
decoder #($clog2(WIDTH)) maskgen(BBMU[$clog2(WIDTH)-1:0], MaskB);
|
||||
mux2 #(WIDTH) maskmux(B, MaskB, Mask, CondMaskB);
|
||||
decoder #($clog2(P.XLEN)) maskgen(BBMU[$clog2(P.XLEN)-1:0], MaskB);
|
||||
mux2 #(P.XLEN) maskmux(B, MaskB, Mask, CondMaskB);
|
||||
end else assign CondMaskB = B;
|
||||
|
||||
// 0-3 bit Pre-Shift Mux
|
||||
if (P.ZBA_SUPPORTED) begin: zbapreshift
|
||||
if (WIDTH == 64) begin
|
||||
if (P.XLEN == 64) begin
|
||||
mux2 #(64) zextmux(A, {{32{1'b0}}, A[31:0]}, W64, CondZextA);
|
||||
end else assign CondZextA = A;
|
||||
assign PreShiftAmt = Funct3[2:1] & {2{PreShift}};
|
||||
@ -80,17 +79,17 @@ module bitmanipalu import cvw::*; #(parameter cvw_t P,
|
||||
|
||||
// Bit reverse needed for some ZBB, ZBC instructions
|
||||
if (P.ZBC_SUPPORTED | P.ZBB_SUPPORTED) begin: bitreverse
|
||||
bitreverse #(WIDTH) brA(.A(ABMU), .RevA);
|
||||
bitreverse #(P.XLEN) brA(.A(ABMU), .RevA);
|
||||
end
|
||||
|
||||
// ZBC Unit
|
||||
if (P.ZBC_SUPPORTED) begin: zbc
|
||||
zbc #(WIDTH) ZBC(.A(ABMU), .RevA, .B(BBMU), .Funct3, .ZBCResult);
|
||||
zbc #(P.XLEN) ZBC(.A(ABMU), .RevA, .B(BBMU), .Funct3, .ZBCResult);
|
||||
end else assign ZBCResult = 0;
|
||||
|
||||
// ZBB Unit
|
||||
if (P.ZBB_SUPPORTED) begin: zbb
|
||||
zbb #(WIDTH) ZBB(.A(ABMU), .RevA, .B(BBMU), .W64, .LT, .LTU, .BUnsigned(Funct3[0]), .ZBBSelect, .ZBBResult);
|
||||
zbb #(P.XLEN) ZBB(.A(ABMU), .RevA, .B(BBMU), .W64, .LT, .LTU, .BUnsigned(Funct3[0]), .ZBBSelect, .ZBBResult);
|
||||
end else assign ZBBResult = 0;
|
||||
|
||||
// Result Select Mux
|
||||
|
@ -39,10 +39,14 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
||||
output logic IllegalBaseInstrD, // Illegal I-type instruction, or illegal RV32 access to upper 16 registers
|
||||
output logic JumpD, // Jump instruction
|
||||
output logic BranchD, // Branch instruction
|
||||
output logic StructuralStallD, // Structural stalls detected by controller
|
||||
output logic LoadStallD, // Structural stalls for load, sent to performance counters
|
||||
output logic [4:0] Rs1D, Rs2D, // Register sources to read in Decode or Execute stage
|
||||
// Execute stage control signals
|
||||
input logic StallE, FlushE, // Stall, flush Execute stage
|
||||
input logic [1:0] FlagsE, // Comparison flags ({eq, lt})
|
||||
input logic FWriteIntE, // Write integer register, coming from FPU controller
|
||||
input logic FCvtIntE, // FPU convert float to int
|
||||
output logic PCSrcE, // Select signal to choose next PC (for datapath and Hazard unit)
|
||||
output logic ALUSrcAE, ALUSrcBE, // ALU operands
|
||||
output logic ALUResultSrcE, // Selects result to pass on to Memory stage
|
||||
@ -65,7 +69,7 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
||||
output logic [3:0] CMOpM, // 1: cbo.inval; 2: cbo.flush; 4: cbo.clean; 8: cbo.zero
|
||||
output logic IFUPrefetchE, // instruction prefetch
|
||||
output logic LSUPrefetchM, // data prefetch
|
||||
|
||||
output logic [1:0] ForwardAE, ForwardBE, // Select signals for forwarding multiplexers
|
||||
// Memory stage control signals
|
||||
input logic StallM, FlushM, // Stall, flush Memory stage
|
||||
output logic [1:0] MemRWE, // Mem read/write: MemRWM[1] = 1 for read, MemRWM[0] = 1 for write
|
||||
@ -83,14 +87,16 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
||||
output logic [2:0] ResultSrcW, // Select source of result to write back to register file
|
||||
// Stall during CSRs
|
||||
output logic CSRWriteFenceM, // CSR write or fence instruction; needs to flush the following instructions
|
||||
output logic StoreStallD // Store (memory write) causes stall
|
||||
output logic [4:0] RdE, RdM, // Pipelined destination registers
|
||||
// Forwarding controls
|
||||
output logic [4:0] RdW // Register destinations in Execute, Memory, or Writeback stage
|
||||
);
|
||||
|
||||
|
||||
logic [4:0] Rs1E, Rs2E; // pipelined register sources
|
||||
logic [6:0] OpD; // Opcode in Decode stage
|
||||
logic [2:0] Funct3D; // Funct3 field in Decode stage
|
||||
logic [6:0] Funct7D; // Funct7 field in Decode stage
|
||||
logic [4:0] Rs1D, Rs2D, RdD; // Rs1/2 source register / dest reg in Decode stage
|
||||
logic [4:0] RdD; // Rs1/2 source register / dest reg in Decode stage
|
||||
|
||||
`define CTRLW 24
|
||||
|
||||
@ -146,6 +152,11 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
||||
logic [3:0] CMOpD, CMOpE; // which CMO instruction 1: cbo.inval; 2: cbo.flush; 4: cbo.clean; 8: cbo.zero
|
||||
logic IFUPrefetchD; // instruction prefetch
|
||||
logic LSUPrefetchD, LSUPrefetchE; // data prefetch
|
||||
logic CMOStallD; // Structural hazards from cache management ops
|
||||
logic MatchDE; // Match between a source register in Decode stage and destination register in Execute stage
|
||||
logic FCvtIntStallD, MDUStallD, CSRRdStallD; // Stall due to conversion, load, multiply/divide, CSR read
|
||||
logic StoreStallD; // load after store hazard
|
||||
|
||||
|
||||
// Extract fields
|
||||
assign OpD = InstrD[6:0];
|
||||
@ -394,6 +405,9 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
||||
flopenrc #(35) controlregE(clk, reset, FlushE, ~StallE,
|
||||
{ALUSelectD, RegWriteD, ResultSrcD, MemRWD, JumpD, BranchD, ALUSrcAD, ALUSrcBD, ALUResultSrcD, CSRReadD, CSRWriteD, PrivilegedD, Funct3D, W64D, SubArithD, MDUD, AtomicD, InvalidateICacheD, FlushDCacheD, FenceD, CMOpD, IFUPrefetchD, LSUPrefetchD, InstrValidD},
|
||||
{ALUSelectE, IEURegWriteE, ResultSrcE, MemRWE, JumpE, BranchE, ALUSrcAE, ALUSrcBE, ALUResultSrcE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, W64E, SubArithE, MDUE, AtomicE, InvalidateICacheE, FlushDCacheE, FenceE, CMOpE, IFUPrefetchE, LSUPrefetchE, InstrValidE});
|
||||
flopenrc #(5) Rs1EReg(clk, reset, FlushE, ~StallE, Rs1D, Rs1E);
|
||||
flopenrc #(5) Rs2EReg(clk, reset, FlushE, ~StallE, Rs2D, Rs2E);
|
||||
flopenrc #(5) RdEReg(clk, reset, FlushE, ~StallE, RdD, RdE);
|
||||
|
||||
// Branch Logic
|
||||
// The comparator handles both signed and unsigned branches using BranchSignedE
|
||||
@ -415,22 +429,37 @@ module controller import cvw::*; #(parameter cvw_t P) (
|
||||
flopenrc #(25) controlregM(clk, reset, FlushM, ~StallM,
|
||||
{RegWriteE, ResultSrcE, MemRWE, CSRReadE, CSRWriteE, PrivilegedE, Funct3E, FWriteIntE, AtomicE, InvalidateICacheE, FlushDCacheE, FenceE, InstrValidE, IntDivE, CMOpE, LSUPrefetchE},
|
||||
{RegWriteM, ResultSrcM, MemRWM, CSRReadM, CSRWriteM, PrivilegedM, Funct3M, FWriteIntM, AtomicM, InvalidateICacheM, FlushDCacheM, FenceM, InstrValidM, IntDivM, CMOpM, LSUPrefetchM});
|
||||
flopenrc #(5) RdMReg(clk, reset, FlushM, ~StallM, RdE, RdM);
|
||||
|
||||
// Writeback stage pipeline control register
|
||||
flopenrc #(5) controlregW(clk, reset, FlushW, ~StallW,
|
||||
{RegWriteM, ResultSrcM, IntDivM},
|
||||
{RegWriteW, ResultSrcW, IntDivW});
|
||||
flopenrc #(5) RdWReg(clk, reset, FlushW, ~StallW, RdM, RdW);
|
||||
|
||||
// Flush F, D, and E stages on a CSR write or Fence.I or SFence.VMA
|
||||
assign CSRWriteFenceM = CSRWriteM | FenceM;
|
||||
|
||||
// the synchronous DTIM cannot read immediately after write
|
||||
// a cache cannot read or write immediately after a write
|
||||
// atomic operations are also detected as MemRWD[1]
|
||||
// *** RT: Remove this after updating the cache.
|
||||
// *** RT: Check that atomic after atomic works correctly.
|
||||
//assign StoreStallD = ((|CMOpE)) & ((|CMOpD));
|
||||
logic AMOHazard;
|
||||
assign AMOHazard = &MemRWE & MemRWD[1];
|
||||
assign StoreStallD = ((|CMOpE) & (|CMOpD)) | AMOHazard;
|
||||
// Forwarding logic
|
||||
always_comb begin
|
||||
ForwardAE = 2'b00;
|
||||
ForwardBE = 2'b00;
|
||||
if (Rs1E != 5'b0)
|
||||
if ((Rs1E == RdM) & RegWriteM) ForwardAE = 2'b10;
|
||||
else if ((Rs1E == RdW) & RegWriteW) ForwardAE = 2'b01;
|
||||
|
||||
if (Rs2E != 5'b0)
|
||||
if ((Rs2E == RdM) & RegWriteM) ForwardBE = 2'b10;
|
||||
else if ((Rs2E == RdW) & RegWriteW) ForwardBE = 2'b01;
|
||||
end
|
||||
|
||||
// Stall on dependent operations that finish in Mem Stage and can't bypass in time
|
||||
// Structural hazard causes stall if any of these events occur
|
||||
assign MatchDE = ((Rs1D == RdE) | (Rs2D == RdE)) & (RdE != 5'b0); // Decode-stage instruction source depends on result from execute stage instruction
|
||||
assign LoadStallD = (MemReadE|SCE) & MatchDE;
|
||||
assign StoreStallD = MemRWD[1] & MemRWE[0]; // Store or AMO followed by load or AMO
|
||||
assign CSRRdStallD = CSRReadE & MatchDE;
|
||||
assign MDUStallD = MDUE & MatchDE; // Int mult/div is at least two cycle latency, even when coming from the FDIV
|
||||
assign FCvtIntStallD = FCvtIntE & MatchDE; // FPU to Integer transfers have single-cycle latency except fcvt
|
||||
assign StructuralStallD = LoadStallD | StoreStallD | CSRRdStallD | MDUStallD | FCvtIntStallD;
|
||||
endmodule
|
||||
|
@ -32,6 +32,7 @@ module datapath import cvw::*; #(parameter cvw_t P) (
|
||||
// Decode stage signals
|
||||
input logic [2:0] ImmSrcD, // Selects type of immediate extension
|
||||
input logic [31:0] InstrD, // Instruction in Decode stage
|
||||
input logic [4:0] Rs1D, Rs2D, // Source registers
|
||||
// Execute stage signals
|
||||
input logic [P.XLEN-1:0] PCE, // PC in Execute stage
|
||||
input logic [P.XLEN-1:0] PCLinkE, // PC + 4 (of instruction in Execute stage)
|
||||
@ -68,9 +69,8 @@ module datapath import cvw::*; #(parameter cvw_t P) (
|
||||
input logic [P.XLEN-1:0] CSRReadValW, // CSR read result
|
||||
input logic [P.XLEN-1:0] MDUResultW, // MDU (Multiply/divide unit) result
|
||||
input logic [P.XLEN-1:0] FIntDivResultW, // FPU's integer divide result
|
||||
input logic [4:0] RdW // Destination register
|
||||
// Hazard Unit signals
|
||||
output logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, // Register sources to read in Decode or Execute stage
|
||||
output logic [4:0] RdE, RdM, RdW // Register destinations in Execute, Memory, or Writeback stage
|
||||
);
|
||||
|
||||
// Fetch stage signals
|
||||
@ -94,9 +94,6 @@ module datapath import cvw::*; #(parameter cvw_t P) (
|
||||
logic [P.XLEN-1:0] MulDivResultW; // Multiply always comes from MDU. Divide could come from MDU or FPU (when using fdivsqrt for integer division)
|
||||
|
||||
// Decode stage
|
||||
assign Rs1D = InstrD[19:15];
|
||||
assign Rs2D = InstrD[24:20];
|
||||
assign RdD = InstrD[11:7];
|
||||
regfile #(P.XLEN, P.E_SUPPORTED) regf(clk, reset, RegWriteW, Rs1D, Rs2D, RdW, ResultW, R1D, R2D);
|
||||
extend #(P) ext(.InstrD(InstrD[31:7]), .ImmSrcD, .ImmExtD);
|
||||
|
||||
@ -104,28 +101,23 @@ module datapath import cvw::*; #(parameter cvw_t P) (
|
||||
flopenrc #(P.XLEN) RD1EReg(clk, reset, FlushE, ~StallE, R1D, R1E);
|
||||
flopenrc #(P.XLEN) RD2EReg(clk, reset, FlushE, ~StallE, R2D, R2E);
|
||||
flopenrc #(P.XLEN) ImmExtEReg(clk, reset, FlushE, ~StallE, ImmExtD, ImmExtE);
|
||||
flopenrc #(5) Rs1EReg(clk, reset, FlushE, ~StallE, Rs1D, Rs1E);
|
||||
flopenrc #(5) Rs2EReg(clk, reset, FlushE, ~StallE, Rs2D, Rs2E);
|
||||
flopenrc #(5) RdEReg(clk, reset, FlushE, ~StallE, RdD, RdE);
|
||||
|
||||
mux3 #(P.XLEN) faemux(R1E, ResultW, IFResultM, ForwardAE, ForwardedSrcAE);
|
||||
mux3 #(P.XLEN) fbemux(R2E, ResultW, IFResultM, ForwardBE, ForwardedSrcBE);
|
||||
comparator #(P.XLEN) comp(ForwardedSrcAE, ForwardedSrcBE, BranchSignedE, FlagsE);
|
||||
mux2 #(P.XLEN) srcamux(ForwardedSrcAE, PCE, ALUSrcAE, SrcAE);
|
||||
mux2 #(P.XLEN) srcbmux(ForwardedSrcBE, ImmExtE, ALUSrcBE, SrcBE);
|
||||
alu #(P, P.XLEN) alu(SrcAE, SrcBE, W64E, SubArithE, ALUSelectE, BSelectE, ZBBSelectE, Funct3E, BALUControlE, BMUActiveE, ALUResultE, IEUAdrE);
|
||||
alu #(P) alu(SrcAE, SrcBE, W64E, SubArithE, ALUSelectE, BSelectE, ZBBSelectE, Funct3E, BALUControlE, BMUActiveE, ALUResultE, IEUAdrE);
|
||||
mux2 #(P.XLEN) altresultmux(ImmExtE, PCLinkE, JumpE, AltResultE);
|
||||
mux2 #(P.XLEN) ieuresultmux(ALUResultE, AltResultE, ALUResultSrcE, IEUResultE);
|
||||
|
||||
// Memory stage pipeline register
|
||||
flopenrc #(P.XLEN) SrcAMReg(clk, reset, FlushM, ~StallM, SrcAE, SrcAM);
|
||||
flopenrc #(P.XLEN) IEUResultMReg(clk, reset, FlushM, ~StallM, IEUResultE, IEUResultM);
|
||||
flopenrc #(5) RdMReg(clk, reset, FlushM, ~StallM, RdE, RdM);
|
||||
flopenrc #(P.XLEN) WriteDataMReg(clk, reset, FlushM, ~StallM, ForwardedSrcBE, WriteDataM);
|
||||
|
||||
// Writeback stage pipeline register and logic
|
||||
flopenrc #(P.XLEN) IFResultWReg(clk, reset, FlushW, ~StallW, IFResultM, IFResultW);
|
||||
flopenrc #(5) RdWReg(clk, reset, FlushW, ~StallW, RdM, RdW);
|
||||
|
||||
// floating point inputs: FIntResM comes from fclass, fcmp, fmv; FCvtIntResW comes from fcvt
|
||||
if (P.F_SUPPORTED) begin:fpmux
|
||||
|
@ -1,62 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// forward.sv
|
||||
//
|
||||
// Written: David_Harris@hmc.edu, Sarah.Harris@unlv.edu
|
||||
// Created: 9 January 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: Determine datapath forwarding
|
||||
//
|
||||
// Documentation: RISC-V System on Chip Design Chapter 4 (Section 4.2.2.3)
|
||||
//
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module forward(
|
||||
// Detect hazards
|
||||
input logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E, RdE, RdM, RdW, // Source and destination registers
|
||||
input logic MemReadE, MDUE, CSRReadE, // Execute stage instruction is a load (MemReadE), divide (MDUE), or CSR read (CSRReadE)
|
||||
input logic RegWriteM, RegWriteW, // Instruction in Memory or Writeback stage writes register file
|
||||
input logic FCvtIntE, // FPU convert float to int
|
||||
input logic SCE, // Store Conditional instruction
|
||||
// Forwarding controls
|
||||
output logic [1:0] ForwardAE, ForwardBE, // Select signals for forwarding multiplexers
|
||||
output logic FCvtIntStallD, LoadStallD, MDUStallD, CSRRdStallD // Stall due to conversion, load, multiply/divide, CSR read
|
||||
);
|
||||
|
||||
logic MatchDE; // Match between a source register in Decode stage and destination register in Execute stage
|
||||
|
||||
always_comb begin
|
||||
ForwardAE = 2'b00;
|
||||
ForwardBE = 2'b00;
|
||||
if (Rs1E != 5'b0)
|
||||
if ((Rs1E == RdM) & RegWriteM) ForwardAE = 2'b10;
|
||||
else if ((Rs1E == RdW) & RegWriteW) ForwardAE = 2'b01;
|
||||
|
||||
if (Rs2E != 5'b0)
|
||||
if ((Rs2E == RdM) & RegWriteM) ForwardBE = 2'b10;
|
||||
else if ((Rs2E == RdW) & RegWriteW) ForwardBE = 2'b01;
|
||||
end
|
||||
|
||||
// Stall on dependent operations that finish in Mem Stage and can't bypass in time
|
||||
assign MatchDE = ((Rs1D == RdE) | (Rs2D == RdE)) & (RdE != 5'b0); // Decode-stage instruction source depends on result from execute stage instruction
|
||||
assign FCvtIntStallD = FCvtIntE & MatchDE; // FPU to Integer transfers have single-cycle latency except fcvt
|
||||
assign LoadStallD = (MemReadE|SCE) & MatchDE;
|
||||
assign MDUStallD = MDUE & MatchDE; // Int mult/div is at least two cycle latency, even when coming from the FDIV
|
||||
assign CSRRdStallD = CSRReadE & MatchDE;
|
||||
endmodule
|
@ -73,8 +73,8 @@ module ieu import cvw::*; #(parameter cvw_t P) (
|
||||
// Hazard unit signals
|
||||
input logic StallD, StallE, StallM, StallW, // Stall signals from hazard unit
|
||||
input logic FlushD, FlushE, FlushM, FlushW, // Flush signals
|
||||
output logic FCvtIntStallD, LoadStallD, // Stall causes from IEU to hazard unit
|
||||
output logic MDUStallD, CSRRdStallD, StoreStallD,
|
||||
output logic StructuralStallD, // IEU detects structural hazard in Decode stage
|
||||
output logic LoadStallD, // Structural stalls for load, sent to performance counters
|
||||
output logic CSRReadM, CSRWriteM, PrivilegedM,// CSR read, CSR write, is privileged instruction
|
||||
output logic CSRWriteFenceM // CSR write or fence instruction needs to flush subsequent instructions
|
||||
);
|
||||
@ -94,7 +94,7 @@ module ieu import cvw::*; #(parameter cvw_t P) (
|
||||
logic SubArithE; // Subtraction or arithmetic shift
|
||||
|
||||
// Forwarding signals
|
||||
logic [4:0] Rs1D, Rs2D, Rs1E, Rs2E; // Source and destination registers
|
||||
logic [4:0] Rs1D, Rs2D; // Source registers
|
||||
logic [1:0] ForwardAE, ForwardBE; // Select signals for forwarding multiplexers
|
||||
logic RegWriteM, RegWriteW; // Register will be written in Memory, Writeback stages
|
||||
logic MemReadE, CSRReadE; // Load, CSRRead instruction
|
||||
@ -104,25 +104,23 @@ module ieu import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
controller #(P) c(
|
||||
.clk, .reset, .StallD, .FlushD, .InstrD, .STATUS_FS, .ENVCFG_CBE, .ImmSrcD,
|
||||
.IllegalIEUFPUInstrD, .IllegalBaseInstrD, .StallE, .FlushE, .FlagsE, .FWriteIntE,
|
||||
.IllegalIEUFPUInstrD, .IllegalBaseInstrD,
|
||||
.StructuralStallD, .LoadStallD, .Rs1D, .Rs2D,
|
||||
.StallE, .FlushE, .FlagsE, .FWriteIntE,
|
||||
.PCSrcE, .ALUSrcAE, .ALUSrcBE, .ALUResultSrcE, .ALUSelectE, .MemReadE, .CSRReadE,
|
||||
.Funct3E, .IntDivE, .MDUE, .W64E, .SubArithE, .BranchD, .BranchE, .JumpD, .JumpE, .SCE,
|
||||
.BranchSignedE, .BSelectE, .ZBBSelectE, .BALUControlE, .BMUActiveE, .MDUActiveE, .CMOpM, .IFUPrefetchE, .LSUPrefetchM,
|
||||
.BranchSignedE, .BSelectE, .ZBBSelectE, .BALUControlE, .BMUActiveE, .MDUActiveE,
|
||||
.FCvtIntE, .ForwardAE, .ForwardBE, .CMOpM, .IFUPrefetchE, .LSUPrefetchM,
|
||||
.StallM, .FlushM, .MemRWE, .MemRWM, .CSRReadM, .CSRWriteM, .PrivilegedM, .AtomicM, .Funct3M,
|
||||
.RegWriteM, .FlushDCacheM, .InstrValidM, .InstrValidE, .InstrValidD, .FWriteIntM,
|
||||
.StallW, .FlushW, .RegWriteW, .IntDivW, .ResultSrcW, .CSRWriteFenceM, .InvalidateICacheM, .StoreStallD);
|
||||
.StallW, .FlushW, .RegWriteW, .IntDivW, .ResultSrcW, .CSRWriteFenceM, .InvalidateICacheM,
|
||||
.RdW, .RdE, .RdM);
|
||||
|
||||
datapath #(P) dp(
|
||||
.clk, .reset, .ImmSrcD, .InstrD, .StallE, .FlushE, .ForwardAE, .ForwardBE, .W64E, .SubArithE,
|
||||
.clk, .reset, .ImmSrcD, .InstrD, .Rs1D, .Rs2D, .StallE, .FlushE, .ForwardAE, .ForwardBE, .W64E, .SubArithE,
|
||||
.Funct3E, .ALUSrcAE, .ALUSrcBE, .ALUResultSrcE, .ALUSelectE, .JumpE, .BranchSignedE,
|
||||
.PCE, .PCLinkE, .FlagsE, .IEUAdrE, .ForwardedSrcAE, .ForwardedSrcBE, .BSelectE, .ZBBSelectE, .BALUControlE, .BMUActiveE,
|
||||
.StallM, .FlushM, .FWriteIntM, .FIntResM, .SrcAM, .WriteDataM, .FCvtIntW,
|
||||
.StallW, .FlushW, .RegWriteW, .IntDivW, .SquashSCW, .ResultSrcW, .ReadDataW, .FCvtIntResW,
|
||||
.CSRReadValW, .MDUResultW, .FIntDivResultW, .Rs1D, .Rs2D, .Rs1E, .Rs2E, .RdE, .RdM, .RdW);
|
||||
|
||||
forward fw(
|
||||
.Rs1D, .Rs2D, .Rs1E, .Rs2E, .RdE, .RdM, .RdW,
|
||||
.MemReadE, .MDUE, .CSRReadE, .RegWriteM, .RegWriteW,
|
||||
.FCvtIntE, .SCE, .ForwardAE, .ForwardBE,
|
||||
.FCvtIntStallD, .LoadStallD, .MDUStallD, .CSRRdStallD);
|
||||
.CSRReadValW, .MDUResultW, .FIntDivResultW, .RdW);
|
||||
endmodule
|
||||
|
@ -185,7 +185,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
|
||||
.InstrAccessFaultF, .LoadAccessFaultM(), .StoreAmoAccessFaultM(),
|
||||
.InstrPageFaultF, .LoadPageFaultM(), .StoreAmoPageFaultM(),
|
||||
.LoadMisalignedFaultM(), .StoreAmoMisalignedFaultM(),
|
||||
.UpdateDA(InstrUpdateDAF), .CMOp(4'b0),
|
||||
.UpdateDA(InstrUpdateDAF), .CMOpM(4'b0),
|
||||
.AtomicAccessM(1'b0),.ExecuteAccessF(1'b1), .WriteAccessM(1'b0), .ReadAccessM(1'b0),
|
||||
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW);
|
||||
|
||||
@ -223,6 +223,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
|
||||
// **** must fix words per line vs beats per line as in lsu.
|
||||
localparam WORDSPERLINE = P.ICACHE_SUPPORTED ? P.ICACHE_LINELENINBITS/P.XLEN : 1;
|
||||
localparam LOGBWPL = P.ICACHE_SUPPORTED ? $clog2(WORDSPERLINE) : 1;
|
||||
|
||||
if(P.ICACHE_SUPPORTED) begin : icache
|
||||
localparam LINELEN = P.ICACHE_SUPPORTED ? P.ICACHE_LINELENINBITS : P.XLEN;
|
||||
localparam LLENPOVERAHBW = P.LLEN / P.AHBW; // Number of AHB beats in a LLEN word. AHBW cannot be larger than LLEN. (implementation limitation)
|
||||
@ -233,7 +234,7 @@ module ifu import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
assign BusRW = ~ITLBMissF & ~CacheableF & ~SelIROM ? IFURWF : '0;
|
||||
assign CacheRWF = ~ITLBMissF & CacheableF & ~SelIROM ? IFURWF : '0;
|
||||
// *** RT: Fix CMOp. Should be CMOpM. Also PAdr and NextSet are replaced with mux between PCPF/IEUAdrM and PCSpillNextF/IEUAdrE.
|
||||
// *** RT: PAdr and NextSet are replaced with mux between PCPF/IEUAdrM and PCSpillNextF/IEUAdrE.
|
||||
cache #(.P(P), .PA_BITS(P.PA_BITS), .XLEN(P.XLEN), .LINELEN(P.ICACHE_LINELENINBITS),
|
||||
.NUMLINES(P.ICACHE_WAYSIZEINBYTES*8/P.ICACHE_LINELENINBITS),
|
||||
.NUMWAYS(P.ICACHE_NUMWAYS), .LOGBWPL(LOGBWPL), .WORDLEN(32), .MUXINTERVAL(16), .READ_ONLY_CACHE(1))
|
||||
@ -246,24 +247,29 @@ module ifu import cvw::*; #(parameter cvw_t P) (
|
||||
.CacheMiss(ICacheMiss), .CacheAccess(ICacheAccess),
|
||||
.ByteMask('0), .BeatCount('0), .SelBusBeat('0),
|
||||
.CacheWriteData('0),
|
||||
.CacheRW(CacheRWF), .CacheRWNext('0), // CacheRWNext is only used to detect hazards. Not possible with icache
|
||||
.CacheRW(CacheRWF),
|
||||
.FlushCache('0),
|
||||
.NextSet(PCSpillNextF[11:0]),
|
||||
.PAdr(PCPF),
|
||||
.CacheCommitted(CacheCommittedF), .InvalidateCache(InvalidateICacheM), .CMOp('0));
|
||||
.CacheCommitted(CacheCommittedF), .InvalidateCache(InvalidateICacheM), .CMOpM('0));
|
||||
|
||||
ahbcacheinterface #(P.AHBW, P.LLEN, P.PA_BITS, WORDSPERLINE, LOGBWPL, LINELEN, LLENPOVERAHBW, 1)
|
||||
ahbcacheinterface(.HCLK(clk), .HRESETn(~reset),
|
||||
.HRDATA,
|
||||
.Flush(FlushD), .CacheBusRW, .BusCMOZero(1'b0), .HSIZE(IFUHSIZE), .HBURST(IFUHBURST), .HTRANS(IFUHTRANS), .HWSTRB(),
|
||||
.Funct3(3'b010), .HADDR(IFUHADDR), .HREADY(IFUHREADY), .HWRITE(IFUHWRITE), .CacheBusAdr(ICacheBusAdr),
|
||||
.BeatCount(), .Cacheable(CacheableF), .SelBusBeat(), .WriteDataM('0),
|
||||
.BeatCount(), .Cacheable(CacheableF), .SelBusBeat(), .WriteDataM('0), .BusAtomic('0),
|
||||
.CacheBusAck(ICacheBusAck), .HWDATA(), .CacheableOrFlushCacheM(1'b0), .CacheReadDataWordM('0),
|
||||
.FetchBuffer, .PAdr(PCPF),
|
||||
.BusRW, .Stall(GatedStallD),
|
||||
.BusStall, .BusCommitted(BusCommittedF));
|
||||
|
||||
mux3 #(32) UnCachedDataMux(.d0(ICacheInstrF), .d1(FetchBuffer[32-1:0]), .d2(IROMInstrF),
|
||||
logic [31:0] ShiftUncachedInstr;
|
||||
|
||||
if(P.XLEN == 64) mux4 #(32) UncachedShiftInstrMux(FetchBuffer[32-1:0], FetchBuffer[48-1:16], FetchBuffer[64-1:32], {16'b0, FetchBuffer[64-1:48]},
|
||||
PCSpillF[2:1], ShiftUncachedInstr);
|
||||
else mux2 #(32) UncachedShiftInstrMux(FetchBuffer[32-1:0], {16'b0, FetchBuffer[32-1:16]}, PCSpillF[1], ShiftUncachedInstr);
|
||||
mux3 #(32) UnCachedDataMux(.d0(ICacheInstrF), .d1(ShiftUncachedInstr), .d2(IROMInstrF),
|
||||
.s({SelIROM, ~CacheableF}), .y(InstrRawF[31:0]));
|
||||
end else begin : passthrough
|
||||
assign IFUHADDR = PCPF;
|
||||
@ -363,11 +369,11 @@ module ifu import cvw::*; #(parameter cvw_t P) (
|
||||
flopenrc #(P.XLEN) PCDReg(clk, reset, FlushD, ~StallD, PCF, PCD);
|
||||
|
||||
// expand 16-bit compressed instructions to 32 bits
|
||||
if (P.COMPRESSED_SUPPORTED) begin
|
||||
if (P.COMPRESSED_SUPPORTED) begin: decomp
|
||||
logic IllegalCompInstrD;
|
||||
decompress #(P) decomp(.InstrRawD, .InstrD, .IllegalCompInstrD);
|
||||
assign IllegalIEUInstrD = IllegalBaseInstrD | IllegalCompInstrD; // illegal if bad 32 or 16-bit instr
|
||||
end else begin
|
||||
end else begin: decomp
|
||||
assign InstrD = InstrRawD;
|
||||
assign IllegalIEUInstrD = IllegalBaseInstrD;
|
||||
end
|
||||
|
@ -117,9 +117,9 @@ module align import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
always_comb begin
|
||||
case (CurrState)
|
||||
STATE_READY: if (ValidSpillM & ~MemRWM[0]) NextState = STATE_SPILL;
|
||||
else if(ValidSpillM & MemRWM[0])NextState = STATE_STORE_DELAY;
|
||||
else NextState = STATE_READY;
|
||||
STATE_READY: if (ValidSpillM & ~MemRWM[0]) NextState = STATE_SPILL; // load spill
|
||||
else if(ValidSpillM) NextState = STATE_STORE_DELAY; // store spill
|
||||
else NextState = STATE_READY; // no spill
|
||||
STATE_SPILL: if(StallM) NextState = STATE_SPILL;
|
||||
else NextState = STATE_READY;
|
||||
STATE_STORE_DELAY: NextState = STATE_SPILL;
|
||||
@ -131,7 +131,7 @@ module align import cvw::*; #(parameter cvw_t P) (
|
||||
assign SelSpillE = (CurrState == STATE_READY & ValidSpillM) | (CurrState == STATE_SPILL & CacheBusHPWTStall) | (CurrState == STATE_STORE_DELAY);
|
||||
assign SpillSaveM = (CurrState == STATE_READY) & ValidSpillM & ~FlushM;
|
||||
assign SelStoreDelay = (CurrState == STATE_STORE_DELAY); // *** Can this be merged into the PreLSURWM logic?
|
||||
assign SpillStallM = SelSpillE | CurrState == STATE_STORE_DELAY;
|
||||
assign SpillStallM = SelSpillE;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Merge spilled data
|
||||
|
@ -36,9 +36,7 @@ module dtim import cvw::*; #(parameter cvw_t P) (
|
||||
input logic [P.PA_BITS-1:0] DTIMAdr, // No stall: Execution stage memory address. Stall: Memory stage memory address
|
||||
input logic [P.LLEN-1:0] WriteDataM, // Write data from IEU
|
||||
input logic [P.LLEN/8-1:0] ByteMaskM, // Selects which bytes within a word to write
|
||||
output logic [P.LLEN-1:0] ReadDataWordM, // Read data before subword selection
|
||||
output logic DTIMStall,
|
||||
output logic DTIMSelWrite
|
||||
output logic [P.LLEN-1:0] ReadDataWordM // Read data before subword selection
|
||||
);
|
||||
|
||||
logic we;
|
||||
@ -50,16 +48,8 @@ module dtim import cvw::*; #(parameter cvw_t P) (
|
||||
localparam ADDR_WDITH = $clog2(DEPTH);
|
||||
localparam OFFSET = $clog2(LLENBYTES);
|
||||
|
||||
logic DTIMStallHazard, DTIMStallHazardD;
|
||||
|
||||
assign DTIMStallHazard = MemRWM[0] & MemRWE[1];
|
||||
flopr #(1) DTIMStallReg(clk, reset, DTIMStallHazard, DTIMStallHazardD);
|
||||
assign DTIMStall = DTIMStallHazard & ~DTIMStallHazardD;
|
||||
|
||||
assign DTIMSelWrite = MemRWM[0] & ~(DTIMStallHazard & ~DTIMStall);
|
||||
|
||||
assign we = DTIMSelWrite & ~FlushW; // have to ignore write if Trap.
|
||||
assign we = MemRWM[0] & ~FlushW; // have to ignore write if Trap.
|
||||
|
||||
ram1p1rwbe #(.USE_SRAM(P.USE_SRAM), .DEPTH(DEPTH), .WIDTH(P.LLEN))
|
||||
ram(.clk, .ce(ce | DTIMSelWrite), .we, .bwe(ByteMaskM), .addr(DTIMAdr[ADDR_WDITH+OFFSET-1:OFFSET]), .dout(ReadDataWordM), .din(WriteDataM));
|
||||
ram(.clk, .ce, .we, .bwe(ByteMaskM), .addr(DTIMAdr[ADDR_WDITH+OFFSET-1:OFFSET]), .dout(ReadDataWordM), .din(WriteDataM));
|
||||
endmodule
|
||||
|
@ -150,7 +150,6 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
logic IgnoreRequest; // On FlushM or TLB miss ignore memory operation
|
||||
logic SelDTIM; // Select DTIM rather than bus or D$
|
||||
logic [P.XLEN-1:0] WriteDataZM;
|
||||
logic DTIMStall;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Pipeline for IEUAdr E to M
|
||||
@ -220,7 +219,7 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
// the trap module.
|
||||
assign CommittedM = SelHPTW | DCacheCommittedM | BusCommittedM;
|
||||
assign GatedStallW = StallW & ~SelHPTW;
|
||||
assign CacheBusHPWTStall = DCacheStallM | HPTWStall | BusStall | DTIMStall;
|
||||
assign CacheBusHPWTStall = DCacheStallM | HPTWStall | BusStall;
|
||||
assign LSUStallM = CacheBusHPWTStall | SpillStallM;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -240,7 +239,7 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
.StoreAmoAccessFaultM(LSUStoreAmoAccessFaultM), .InstrPageFaultF(), .LoadPageFaultM,
|
||||
.StoreAmoPageFaultM,
|
||||
.LoadMisalignedFaultM, .StoreAmoMisalignedFaultM, // *** these faults need to be supressed during hptw.
|
||||
.UpdateDA(DataUpdateDAM), .CMOp(CMOpM),
|
||||
.UpdateDA(DataUpdateDAM), .CMOpM(CMOpM),
|
||||
.AtomicAccessM(|LSUAtomicM), .ExecuteAccessF(1'b0),
|
||||
.WriteAccessM, .ReadAccessM(PreLSURWM[1]),
|
||||
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW);
|
||||
@ -269,10 +268,9 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
if (P.DTIM_SUPPORTED) begin : dtim
|
||||
logic [P.PA_BITS-1:0] DTIMAdr;
|
||||
logic [1:0] DTIMMemRWM;
|
||||
logic DTIMSelWrite;
|
||||
|
||||
// The DTIM uses untranslated addresses, so it is not compatible with virtual memory.
|
||||
mux2 #(P.PA_BITS) DTIMAdrMux(IEUAdrExtE[P.PA_BITS-1:0], IEUAdrExtM[P.PA_BITS-1:0], DTIMSelWrite, DTIMAdr);
|
||||
mux2 #(P.PA_BITS) DTIMAdrMux(IEUAdrExtE[P.PA_BITS-1:0], IEUAdrExtM[P.PA_BITS-1:0], MemRWM[0], DTIMAdr);
|
||||
assign DTIMMemRWM = SelDTIM & ~IgnoreRequestTLB ? LSURWM : '0;
|
||||
// **** fix ReadDataWordM to be LLEN. ByteMask is wrong length.
|
||||
// **** create config to support DTIM with floating point.
|
||||
@ -280,9 +278,7 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
dtim #(P) dtim(.clk, .reset, .ce(~GatedStallW), .MemRWE(MemRWE), // *** update when you update the cache RWE
|
||||
.MemRWM(DTIMMemRWM),
|
||||
.DTIMAdr, .FlushW, .WriteDataM(LSUWriteDataM),
|
||||
.ReadDataWordM(DTIMReadDataWordM[P.LLEN-1:0]), .ByteMaskM(ByteMaskM), .DTIMStall, .DTIMSelWrite);
|
||||
end else begin
|
||||
assign DTIMStall = '0;
|
||||
.ReadDataWordM(DTIMReadDataWordM[P.LLEN-1:0]), .ByteMaskM(ByteMaskM));
|
||||
end
|
||||
if (P.BUS_SUPPORTED) begin : bus
|
||||
if(P.DCACHE_SUPPORTED) begin : dcache
|
||||
@ -307,11 +303,17 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
logic CacheStall;
|
||||
logic [1:0] CacheBusRWTemp;
|
||||
logic BusCMOZero;
|
||||
logic [3:0] CacheCMOpM;
|
||||
logic BusAtomic;
|
||||
|
||||
if(P.ZICBOZ_SUPPORTED) begin
|
||||
assign BusCMOZero = CMOpM[3] & ~CacheableM;
|
||||
assign CacheCMOpM = (CacheableM & ~SelHPTW) ? CMOpM : '0;
|
||||
assign BusAtomic = AtomicM[1] & ~CacheableM;
|
||||
end else begin
|
||||
assign BusCMOZero = '0;
|
||||
assign CacheCMOpM = '0;
|
||||
assign BusAtomic = '0;
|
||||
end
|
||||
assign BusRW = ~CacheableM & ~SelDTIM ? LSURWM : '0;
|
||||
assign CacheableOrFlushCacheM = CacheableM | FlushDCacheM;
|
||||
@ -320,7 +322,7 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
cache #(.P(P), .PA_BITS(P.PA_BITS), .XLEN(P.XLEN), .LINELEN(P.DCACHE_LINELENINBITS), .NUMLINES(P.DCACHE_WAYSIZEINBYTES*8/LINELEN),
|
||||
.NUMWAYS(P.DCACHE_NUMWAYS), .LOGBWPL(LLENLOGBWPL), .WORDLEN(CACHEWORDLEN), .MUXINTERVAL(P.LLEN), .READ_ONLY_CACHE(0)) dcache(
|
||||
.clk, .reset, .Stall(GatedStallW & ~SelSpillE), .SelBusBeat, .FlushStage(FlushW | IgnoreRequestTLB), .CacheRWNext(MemRWE), // *** change to LSURWE after updating hptw and atomic
|
||||
.clk, .reset, .Stall(GatedStallW & ~SelSpillE), .SelBusBeat, .FlushStage(FlushW | IgnoreRequestTLB),
|
||||
.CacheRW(SelStoreDelay ? 2'b00 : CacheRWM),
|
||||
.FlushCache(FlushDCache), .NextSet(IEUAdrExtE[11:0]), .PAdr(PAdrM),
|
||||
.ByteMask(ByteMaskSpillM), .BeatCount(BeatCount[AHBWLOGBWPL-1:AHBWLOGBWPL-LLENLOGBWPL]),
|
||||
@ -329,7 +331,7 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
.CacheCommitted(DCacheCommittedM),
|
||||
.CacheBusAdr(DCacheBusAdr), .ReadDataWord(DCacheReadDataWordM),
|
||||
.FetchBuffer, .CacheBusRW(CacheBusRWTemp),
|
||||
.CacheBusAck(DCacheBusAck), .InvalidateCache(1'b0), .CMOp(CMOpM));
|
||||
.CacheBusAck(DCacheBusAck), .InvalidateCache(1'b0), .CMOpM(CacheCMOpM));
|
||||
|
||||
assign DCacheStallM = CacheStall & ~IgnoreRequestTLB;
|
||||
assign CacheBusRW = CacheBusRWTemp;
|
||||
@ -340,7 +342,7 @@ module lsu import cvw::*; #(parameter cvw_t P) (
|
||||
.HRDATA, .HWDATA(LSUHWDATA), .HWSTRB(LSUHWSTRB),
|
||||
.HSIZE(LSUHSIZE), .HBURST(LSUHBURST), .HTRANS(LSUHTRANS), .HWRITE(LSUHWRITE), .HREADY(LSUHREADY),
|
||||
.BeatCount, .SelBusBeat, .CacheReadDataWordM(DCacheReadDataWordM[P.LLEN-1:0]), .WriteDataM(LSUWriteDataM),
|
||||
.Funct3(LSUFunct3M), .HADDR(LSUHADDR), .CacheBusAdr(DCacheBusAdr), .CacheBusRW, .BusCMOZero, .CacheableOrFlushCacheM,
|
||||
.Funct3(LSUFunct3M), .HADDR(LSUHADDR), .CacheBusAdr(DCacheBusAdr), .CacheBusRW, .BusAtomic, .BusCMOZero, .CacheableOrFlushCacheM,
|
||||
.CacheBusAck(DCacheBusAck), .FetchBuffer, .PAdr(PAdrM),
|
||||
.Cacheable(CacheableOrFlushCacheM), .BusRW, .Stall(GatedStallW),
|
||||
.BusStall, .BusCommitted(BusCommittedM));
|
||||
|
@ -37,17 +37,17 @@ module adrdecs import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
localparam logic [3:0] SUPPORTED_SIZE = (P.LLEN == 32 ? 4'b0111 : 4'b1111);
|
||||
// Determine which region of physical memory (if any) is being accessed
|
||||
adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[11]);
|
||||
adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[10]);
|
||||
adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[9]);
|
||||
adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[8]);
|
||||
adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[7]);
|
||||
adrdec #(P.PA_BITS) dtimdec(PhysicalAddress, P.DTIM_BASE[P.PA_BITS-1:0], P.DTIM_RANGE[P.PA_BITS-1:0], P.DTIM_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[1]);
|
||||
adrdec #(P.PA_BITS) iromdec(PhysicalAddress, P.IROM_BASE[P.PA_BITS-1:0], P.IROM_RANGE[P.PA_BITS-1:0], P.IROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[2]);
|
||||
adrdec #(P.PA_BITS) ddr4dec(PhysicalAddress, P.EXT_MEM_BASE[P.PA_BITS-1:0], P.EXT_MEM_RANGE[P.PA_BITS-1:0], P.EXT_MEM_SUPPORTED, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[3]);
|
||||
adrdec #(P.PA_BITS) bootromdec(PhysicalAddress, P.BOOTROM_BASE[P.PA_BITS-1:0], P.BOOTROM_RANGE[P.PA_BITS-1:0], P.BOOTROM_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[4]);
|
||||
adrdec #(P.PA_BITS) uncoreramdec(PhysicalAddress, P.UNCORE_RAM_BASE[P.PA_BITS-1:0], P.UNCORE_RAM_RANGE[P.PA_BITS-1:0], P.UNCORE_RAM_SUPPORTED, AccessRWXC, Size, SUPPORTED_SIZE, SelRegions[5]);
|
||||
adrdec #(P.PA_BITS) clintdec(PhysicalAddress, P.CLINT_BASE[P.PA_BITS-1:0], P.CLINT_RANGE[P.PA_BITS-1:0], P.CLINT_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE, SelRegions[6]);
|
||||
adrdec #(P.PA_BITS) gpiodec(PhysicalAddress, P.GPIO_BASE[P.PA_BITS-1:0], P.GPIO_RANGE[P.PA_BITS-1:0], P.GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[5]);
|
||||
adrdec #(P.PA_BITS) uartdec(PhysicalAddress, P.UART_BASE[P.PA_BITS-1:0], P.UART_RANGE[P.PA_BITS-1:0], P.UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[4]);
|
||||
adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[3]);
|
||||
adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE & 4'b1100, SelRegions[2]);
|
||||
adrdec #(P.PA_BITS) spidec(PhysicalAddress, P.SPI_BASE[P.PA_BITS-1:0], P.SPI_RANGE[P.PA_BITS-1:0], P.SPI_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[1]);
|
||||
adrdec #(P.PA_BITS) gpiodec(PhysicalAddress, P.GPIO_BASE[P.PA_BITS-1:0], P.GPIO_RANGE[P.PA_BITS-1:0], P.GPIO_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[7]);
|
||||
adrdec #(P.PA_BITS) uartdec(PhysicalAddress, P.UART_BASE[P.PA_BITS-1:0], P.UART_RANGE[P.PA_BITS-1:0], P.UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[8]);
|
||||
adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[9]);
|
||||
adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE & 4'b1100, SelRegions[10]);
|
||||
adrdec #(P.PA_BITS) spidec(PhysicalAddress, P.SPI_BASE[P.PA_BITS-1:0], P.SPI_RANGE[P.PA_BITS-1:0], P.SPI_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[11]);
|
||||
|
||||
assign SelRegions[0] = ~|(SelRegions[11:1]); // none of the regions are selected
|
||||
endmodule
|
||||
|
@ -139,7 +139,7 @@ module hptw import cvw::*; #(parameter cvw_t P) (
|
||||
assign LeafPTE = Executable | Writable | Readable;
|
||||
assign ValidPTE = Valid & ~(Writable & ~Readable);
|
||||
assign ValidLeafPTE = ValidPTE & LeafPTE;
|
||||
assign ValidNonLeafPTE = ValidPTE & ~LeafPTE;
|
||||
assign ValidNonLeafPTE = Valid & ~LeafPTE;
|
||||
|
||||
if(P.SVADU_SUPPORTED) begin : hptwwrites
|
||||
logic ReadAccess, WriteAccess;
|
||||
@ -255,13 +255,14 @@ module hptw import cvw::*; #(parameter cvw_t P) (
|
||||
end
|
||||
|
||||
// Page Table Walker FSM
|
||||
// there is a bug here. Each memory access needs to be potentially flushed if the PMA/P checkers
|
||||
// *** there is a bug here (RT). Each memory access needs to be potentially flushed if the PMA/P checkers
|
||||
// generate an access fault. Specially the store on UDPATE_PTE needs to check for access violation.
|
||||
// I think the solution is to do 1 of the following
|
||||
// 1. Allow the HPTW to generate exceptions and stop walking immediately.
|
||||
// 2. If the store would generate an exception don't store to dcache but still write the TLB. When we go back
|
||||
// to LEAF then the PMA/P. Wait this does not work. The PMA/P won't be looking a the address in the table, but
|
||||
// rather than physical address of the translated instruction/data. So we must generate the exception.
|
||||
// *** DH 1/1/24 another bug: when the NAPOT bits (PTE[62:61]) are nonzero on a nonleaf PTE, the walker should make a page fault (Issue 546)
|
||||
flopenl #(.TYPE(statetype)) WalkerStateReg(clk, reset | FlushW, 1'b1, NextWalkerState, IDLE, WalkerState);
|
||||
always_comb
|
||||
case (WalkerState)
|
||||
|
@ -55,7 +55,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
|
||||
output logic UpdateDA, // page fault due to setting dirty or access bit
|
||||
output logic LoadMisalignedFaultM, StoreAmoMisalignedFaultM, // misaligned fault sources
|
||||
// PMA checker signals
|
||||
input logic [3:0] CMOp, // Cache management instructions
|
||||
input logic [3:0] CMOpM, // Cache management instructions
|
||||
input logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM, // access type
|
||||
input var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0], // PMP configuration
|
||||
input var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW[P.PMP_ENTRIES-1:0] // PMP addresses
|
||||
@ -85,7 +85,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
|
||||
.SATP_MODE(SATP_REGW[P.XLEN-1:P.XLEN-P.SVMODE_BITS]),
|
||||
.SATP_ASID(SATP_REGW[P.ASID_BASE+P.ASID_BITS-1:P.ASID_BASE]),
|
||||
.VAdr(VAdr[P.XLEN-1:0]), .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_ADUE,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess, .CMOp,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess, .CMOpM,
|
||||
.DisableTranslation, .PTE, .PageTypeWriteVal,
|
||||
.TLBWrite, .TLBFlush, .TLBPAdr, .TLBMiss, .TLBHit,
|
||||
.Translate, .TLBPageFault, .UpdateDA, .PBMemoryType);
|
||||
@ -107,7 +107,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
|
||||
// Check physical memory accesses
|
||||
///////////////////////////////////////////
|
||||
|
||||
pmachecker #(P) pmachecker(.PhysicalAddress, .Size, .CMOp,
|
||||
pmachecker #(P) pmachecker(.PhysicalAddress, .Size, .CMOpM,
|
||||
.AtomicAccessM, .ExecuteAccessF, .WriteAccessM, .ReadAccessM, .PBMemoryType,
|
||||
.Cacheable, .Idempotent, .SelTIM,
|
||||
.PMAInstrAccessFaultF, .PMALoadAccessFaultM, .PMAStoreAmoAccessFaultM);
|
||||
@ -115,7 +115,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
|
||||
if (P.PMP_ENTRIES > 0) begin : pmp
|
||||
pmpchecker #(P) pmpchecker(.PhysicalAddress, .PrivilegeModeW,
|
||||
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,
|
||||
.ExecuteAccessF, .WriteAccessM, .ReadAccessM, .CMOp,
|
||||
.ExecuteAccessF, .WriteAccessM, .ReadAccessM, .CMOpM,
|
||||
.PMPInstrAccessFaultF, .PMPLoadAccessFaultM, .PMPStoreAmoAccessFaultM);
|
||||
end else begin
|
||||
assign PMPInstrAccessFaultF = 0;
|
||||
|
@ -31,7 +31,7 @@
|
||||
module pmachecker import cvw::*; #(parameter cvw_t P) (
|
||||
input logic [P.PA_BITS-1:0] PhysicalAddress,
|
||||
input logic [1:0] Size,
|
||||
input logic [3:0] CMOp,
|
||||
input logic [3:0] CMOpM,
|
||||
input logic AtomicAccessM, // Atomic access
|
||||
input logic ExecuteAccessF, // Execute access
|
||||
input logic WriteAccessM, // Write access
|
||||
@ -51,29 +51,29 @@ module pmachecker import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
// Determine what type of access is being made
|
||||
assign AccessRW = ReadAccessM | WriteAccessM;
|
||||
assign AccessRWXC = ReadAccessM | WriteAccessM | ExecuteAccessF | (|CMOp);
|
||||
assign AccessRWXC = ReadAccessM | WriteAccessM | ExecuteAccessF | (|CMOpM);
|
||||
assign AccessRX = ReadAccessM | ExecuteAccessF;
|
||||
|
||||
// Determine which region of physical memory (if any) is being accessed
|
||||
adrdecs #(P) adrdecs(PhysicalAddress, AccessRW, AccessRX, AccessRWXC, Size, SelRegions);
|
||||
|
||||
// Only non-core RAM/ROM memory regions are cacheable. PBMT can override cachable; NC and IO are uncachable
|
||||
assign CacheableRegion = SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-cachable
|
||||
assign CacheableRegion = SelRegions[3] | SelRegions[4] | SelRegions[5]; // exclusion-tag: unused-cachable
|
||||
assign Cacheable = (PBMemoryType == 2'b00) ? CacheableRegion : 0;
|
||||
|
||||
// Nonidemdempotent means access could have side effect and must not be done speculatively or redundantly
|
||||
// I/O is nonidempotent. PBMT can override PMA; NC is idempotent and IO is non-idempotent
|
||||
assign IdempotentRegion = SelRegions[11] | SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7]; // exclusion-tag: unused-idempotent
|
||||
assign IdempotentRegion = SelRegions[1] | SelRegions[2] | SelRegions[3] | SelRegions[4] | SelRegions[5]; // exclusion-tag: unused-idempotent
|
||||
assign Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01);
|
||||
|
||||
// Atomic operations are only allowed on RAM
|
||||
assign AtomicAllowed = SelRegions[11] | SelRegions[9] | SelRegions[7]; // exclusion-tag: unused-idempotent
|
||||
assign AtomicAllowed = SelRegions[1] | SelRegions[3] | SelRegions[5]; // exclusion-tag: unused-atomic
|
||||
// Check if tightly integrated memories are selected
|
||||
assign SelTIM = SelRegions[11] | SelRegions[10]; // exclusion-tag: unused-idempotent
|
||||
assign SelTIM = SelRegions[1] | SelRegions[2]; // exclusion-tag: unused-tim
|
||||
|
||||
// Detect access faults
|
||||
assign PMAAccessFault = (SelRegions[0]) & AccessRWXC | AtomicAccessM & ~AtomicAllowed;
|
||||
assign PMAAccessFault = SelRegions[0] & AccessRWXC | AtomicAccessM & ~AtomicAllowed;
|
||||
assign PMAInstrAccessFaultF = ExecuteAccessF & PMAAccessFault;
|
||||
assign PMALoadAccessFaultM = ReadAccessM & PMAAccessFault;
|
||||
assign PMAStoreAmoAccessFaultM = (WriteAccessM | (|CMOp)) & PMAAccessFault;
|
||||
assign PMAStoreAmoAccessFaultM = (WriteAccessM | (|CMOpM)) & PMAAccessFault;
|
||||
endmodule
|
||||
|
@ -42,7 +42,7 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) (
|
||||
input var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0],
|
||||
input var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW [P.PMP_ENTRIES-1:0],
|
||||
input logic ExecuteAccessF, WriteAccessM, ReadAccessM,
|
||||
input logic [3:0] CMOp,
|
||||
input logic [3:0] CMOpM,
|
||||
output logic PMPInstrAccessFaultF,
|
||||
output logic PMPLoadAccessFaultM,
|
||||
output logic PMPStoreAmoAccessFaultM
|
||||
@ -72,8 +72,8 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) (
|
||||
// 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 PMPCBOMAccessFault = EnforcePMP & (|CMOp[2:0]) & ~|((R|W) & FirstMatch) ;
|
||||
assign PMPCBOZAccessFault = EnforcePMP & CMOp[3] & ~|(W & FirstMatch) ;
|
||||
assign PMPCBOMAccessFault = EnforcePMP & (|CMOpM[2:0]) & ~|((R|W) & FirstMatch) ;
|
||||
assign PMPCBOZAccessFault = EnforcePMP & CMOpM[3] & ~|(W & FirstMatch) ;
|
||||
assign PMPCMOAccessFault = PMPCBOZAccessFault | PMPCBOMAccessFault;
|
||||
|
||||
assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|(X & FirstMatch) ;
|
||||
|
@ -62,7 +62,7 @@ module tlb import cvw::*; #(parameter cvw_t P,
|
||||
input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor
|
||||
input logic ReadAccess,
|
||||
input logic WriteAccess,
|
||||
input logic [3:0] CMOp,
|
||||
input logic [3:0] CMOpM,
|
||||
input logic DisableTranslation,
|
||||
input logic [P.XLEN-1:0] VAdr, // address input before translation (could be physical or virtual)
|
||||
input logic [P.XLEN-1:0] PTE, // page table entry to write
|
||||
@ -109,7 +109,7 @@ module tlb import cvw::*; #(parameter cvw_t P,
|
||||
assign NAPOT4 = (PPN[3:0] == 4'b1000); // 64 KiB contiguous region with pte.napot_bits = 4
|
||||
|
||||
tlbcontrol #(P, ITLB) tlbcontrol(.SATP_MODE, .VAdr, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_ADUE,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess, .CMOp, .DisableTranslation, .TLBFlush,
|
||||
.PrivilegeModeW, .ReadAccess, .WriteAccess, .CMOpM, .DisableTranslation, .TLBFlush,
|
||||
.PTEAccessBits, .CAMHit, .Misaligned, .NAPOT4,
|
||||
.TLBMiss, .TLBHit, .TLBPageFault,
|
||||
.UpdateDA, .SV39Mode, .Translate, .PTE_N, .PBMemoryType);
|
||||
|
@ -35,7 +35,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
||||
input logic ENVCFG_ADUE, // HPTW A/D Update enable
|
||||
input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor
|
||||
input logic ReadAccess, WriteAccess,
|
||||
input logic [3:0] CMOp,
|
||||
input logic [3:0] CMOpM,
|
||||
input logic DisableTranslation,
|
||||
input logic TLBFlush, // Invalidate all TLB entries
|
||||
input logic [11:0] PTEAccessBits,
|
||||
@ -69,7 +69,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
||||
assign Translate = (SATP_MODE != P.NO_TRANSLATE[P.SVMODE_BITS-1:0]) & (EffectivePrivilegeMode != P.M_MODE) & ~DisableTranslation;
|
||||
|
||||
// Determine whether TLB is being used
|
||||
assign TLBAccess = ReadAccess | WriteAccess | (|CMOp);
|
||||
assign TLBAccess = ReadAccess | WriteAccess | (|CMOpM);
|
||||
|
||||
// Check that upper bits are legal (all 0s or all 1s)
|
||||
vm64check #(P) vm64check(.SATP_MODE, .VAdr, .SV39Mode, .UpperBitsUnequal);
|
||||
@ -85,8 +85,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
||||
assign PBMemoryType = PTE_PBMT & {2{Translate & TLBHit & P.SVPBMT_SUPPORTED}};
|
||||
|
||||
// check if reserved, N, or PBMT bits are malformed w in RV64
|
||||
assign BadPBMT = PTE_PBMT != 0 & (~(P.SVPBMT_SUPPORTED & ENVCFG_PBMTE) |
|
||||
{PTE_X, PTE_W, PTE_R} == 3'b000) | PTE_PBMT == 3; // PBMT must be zero if not supported or for non-leaf PTEs;
|
||||
assign BadPBMT = ((PTE_PBMT != 0) & ~(P.SVPBMT_SUPPORTED & ENVCFG_PBMTE)) | PTE_PBMT == 3; // PBMT must be zero if not supported; value of 3 is reserved
|
||||
assign BadNAPOT = PTE_N & (~P.SVNAPOT_SUPPORTED | ~NAPOT4); // N must be be 0 if CVNAPOT is not supported or not 64 KiB contiguous region
|
||||
assign BadReserved = PTE_RESERVED; // Reserved bits must be zero
|
||||
|
||||
@ -94,8 +93,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
||||
if (ITLB == 1) begin:itlb // Instruction TLB fault checking
|
||||
// User mode may only execute user mode pages, and supervisor mode may
|
||||
// only execute non-user mode pages.
|
||||
assign ImproperPrivilege = ((EffectivePrivilegeMode == P.U_MODE) & ~PTE_U) |
|
||||
((EffectivePrivilegeMode == P.S_MODE) & PTE_U);
|
||||
assign ImproperPrivilege = ((PrivilegeModeW == P.U_MODE) & ~PTE_U) | ((PrivilegeModeW == P.S_MODE) & PTE_U);
|
||||
assign PreUpdateDA = ~PTE_A;
|
||||
assign InvalidAccess = ~PTE_X;
|
||||
end else begin:dtlb // Data TLB fault checking
|
||||
@ -113,8 +111,8 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) (
|
||||
// Check for write error. Writes are invalid when the page's write bit is
|
||||
// low.
|
||||
assign InvalidWrite = WriteAccess & ~PTE_W;
|
||||
assign InvalidCBOM = (|CMOp[2:0]) & (~PTE_W | (~PTE_R & (~STATUS_MXR | ~PTE_X)));
|
||||
assign InvalidCBOZ = CMOp[3] & ~PTE_W;
|
||||
assign InvalidCBOM = (|CMOpM[2:0]) & (~PTE_W | (~PTE_R & (~STATUS_MXR | ~PTE_X)));
|
||||
assign InvalidCBOZ = CMOpM[3] & ~PTE_W;
|
||||
assign InvalidAccess = InvalidRead | InvalidWrite | InvalidCBOM | InvalidCBOZ;
|
||||
assign PreUpdateDA = ~PTE_A | WriteAccess & ~PTE_D;
|
||||
end
|
||||
|
@ -54,7 +54,6 @@ module csr import cvw::*; #(parameter cvw_t P) (
|
||||
input logic SelHPTW, // hardware page table walker active, so base endianness on supervisor mode
|
||||
// inputs for performance counters
|
||||
input logic LoadStallD,
|
||||
input logic StoreStallD,
|
||||
input logic ICacheStallF,
|
||||
input logic DCacheStallM,
|
||||
input logic BPDirPredWrongM,
|
||||
@ -275,7 +274,7 @@ module csr import cvw::*; #(parameter cvw_t P) (
|
||||
|
||||
if (P.ZICNTR_SUPPORTED) begin:counters
|
||||
csrc #(P) counters(.clk, .reset, .StallE, .StallM, .FlushM,
|
||||
.InstrValidNotFlushedM, .LoadStallD, .StoreStallD, .CSRWriteM, .CSRMWriteM,
|
||||
.InstrValidNotFlushedM, .LoadStallD, .CSRWriteM, .CSRMWriteM,
|
||||
.BPDirPredWrongM, .BTAWrongM, .RASPredPCWrongM, .IClassWrongM, .BPWrongM,
|
||||
.InstrClassM, .DCacheMiss, .DCacheAccess, .ICacheMiss, .ICacheAccess, .sfencevmaM,
|
||||
.InterruptM, .ExceptionM, .InvalidateICacheM, .ICacheStallF, .DCacheStallM, .DivBusyE, .FDivBusyE,
|
||||
|
@ -32,7 +32,7 @@ module csrc import cvw::*; #(parameter cvw_t P) (
|
||||
input logic clk, reset,
|
||||
input logic StallE, StallM,
|
||||
input logic FlushM,
|
||||
input logic InstrValidNotFlushedM, LoadStallD, StoreStallD,
|
||||
input logic InstrValidNotFlushedM, LoadStallD,
|
||||
input logic CSRMWriteM, CSRWriteM,
|
||||
input logic BPDirPredWrongM,
|
||||
input logic BTAWrongM,
|
||||
@ -75,7 +75,6 @@ module csrc import cvw::*; #(parameter cvw_t P) (
|
||||
logic [P.XLEN-1:0] HPMCOUNTER_REGW[P.COUNTERS-1:0];
|
||||
logic [P.XLEN-1:0] HPMCOUNTERH_REGW[P.COUNTERS-1:0];
|
||||
logic LoadStallE, LoadStallM;
|
||||
logic StoreStallE, StoreStallM;
|
||||
logic [P.COUNTERS-1:0] WriteHPMCOUNTERM;
|
||||
logic [P.COUNTERS-1:0] CounterEvent;
|
||||
logic [63:0] HPMCOUNTERPlusM[P.COUNTERS-1:0];
|
||||
@ -83,8 +82,8 @@ module csrc import cvw::*; #(parameter cvw_t P) (
|
||||
genvar i;
|
||||
|
||||
// Interface signals
|
||||
flopenrc #(2) LoadStallEReg(.clk, .reset, .clear(1'b0), .en(~StallE), .d({StoreStallD, LoadStallD}), .q({StoreStallE, LoadStallE})); // don't flush the load stall during a load stall.
|
||||
flopenrc #(2) LoadStallMReg(.clk, .reset, .clear(FlushM), .en(~StallM), .d({StoreStallE, LoadStallE}), .q({StoreStallM, LoadStallM}));
|
||||
flopenrc #(1) LoadStallEReg(.clk, .reset, .clear(1'b0), .en(~StallE), .d(LoadStallD), .q(LoadStallE)); // don't flush the load stall during a load stall.
|
||||
flopenrc #(1) LoadStallMReg(.clk, .reset, .clear(FlushM), .en(~StallM), .d(LoadStallE), .q(LoadStallM));
|
||||
|
||||
// Determine when to increment each counter
|
||||
assign CounterEvent[0] = 1'b1; // MCYCLE always increments
|
||||
@ -100,7 +99,7 @@ module csrc import cvw::*; #(parameter cvw_t P) (
|
||||
assign CounterEvent[9] = RASPredPCWrongM & InstrValidNotFlushedM; // return address stack wrong address
|
||||
assign CounterEvent[10] = IClassWrongM & InstrValidNotFlushedM; // instruction class predictor wrong
|
||||
assign CounterEvent[11] = LoadStallM; // Load Stalls. don't want to suppress on flush as this only happens if flushed.
|
||||
assign CounterEvent[12] = StoreStallM; // Store Stall
|
||||
assign CounterEvent[12] = 0; // depricated Store Stall
|
||||
assign CounterEvent[13] = DCacheAccess; // data cache access
|
||||
assign CounterEvent[14] = DCacheMiss; // data cache miss. Miss asserted 1 cycle at start of cache miss
|
||||
assign CounterEvent[15] = DCacheStallM; // d cache miss cycles
|
||||
|
@ -45,7 +45,6 @@ module privileged import cvw::*; #(parameter cvw_t P) (
|
||||
// processor events for performance counter logging
|
||||
input logic FRegWriteM, // instruction will write floating-point registers
|
||||
input logic LoadStallD, // load instruction is stalling
|
||||
input logic StoreStallD, // store instruction is stalling
|
||||
input logic ICacheStallF, // I cache stalled
|
||||
input logic DCacheStallM, // D cache stalled
|
||||
input logic BPDirPredWrongM, // branch predictor guessed wrong direction
|
||||
@ -133,7 +132,7 @@ module privileged import cvw::*; #(parameter cvw_t P) (
|
||||
.InstrM, .InstrOrigM, .PCM, .SrcAM, .IEUAdrM,
|
||||
.CSRReadM, .CSRWriteM, .TrapM, .mretM, .sretM, .InterruptM,
|
||||
.MTimerInt, .MExtInt, .SExtInt, .MSwInt,
|
||||
.MTIME_CLINT, .InstrValidM, .FRegWriteM, .LoadStallD, .StoreStallD,
|
||||
.MTIME_CLINT, .InstrValidM, .FRegWriteM, .LoadStallD,
|
||||
.BPDirPredWrongM, .BTAWrongM, .RASPredPCWrongM, .BPWrongM,
|
||||
.sfencevmaM, .ExceptionM, .InvalidateICacheM, .ICacheStallF, .DCacheStallM, .DivBusyE, .FDivBusyE,
|
||||
.IClassWrongM, .InstrClassM, .DCacheMiss, .DCacheAccess, .ICacheMiss, .ICacheAccess,
|
||||
|
@ -91,7 +91,7 @@ module uncore import cvw::*; #(parameter cvw_t P)(
|
||||
adrdecs #(P) adrdecs(HADDR, 1'b1, 1'b1, 1'b1, HSIZE[1:0], HSELRegions);
|
||||
|
||||
// unswizzle HSEL signals
|
||||
assign {HSELDTIM, HSELIROM, HSELEXT, HSELBootRom, HSELRam, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC, HSELEXTSDC, HSELSPI} = HSELRegions[11:1];
|
||||
assign {HSELSPI, HSELEXTSDC, HSELPLIC, HSELUART, HSELGPIO, HSELCLINT, HSELRam, HSELBootRom, HSELEXT, HSELIROM, HSELDTIM} = HSELRegions[11:1];
|
||||
|
||||
// AHB -> APB bridge
|
||||
ahbapbbridge #(P, 5) ahbapbbridge (
|
||||
@ -180,7 +180,7 @@ module uncore import cvw::*; #(parameter cvw_t P)(
|
||||
// device is ready. Hense this register must be selectively enabled by HREADY.
|
||||
// However on reset None must be seleted.
|
||||
flopenl #(12) hseldelayreg(HCLK, ~HRESETn, HREADY, HSELRegions, 12'b1,
|
||||
{HSELDTIMD, HSELIROMD, HSELEXTD, HSELBootRomD, HSELRamD,
|
||||
HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD, HSELEXTSDCD, HSELSPID, HSELNoneD});
|
||||
{HSELSPID, HSELEXTSDCD, HSELPLICD, HSELUARTD, HSELGPIOD, HSELCLINTD,
|
||||
HSELRamD, HSELBootRomD, HSELEXTD, HSELIROMD, HSELDTIMD, HSELNoneD});
|
||||
flopenr #(1) hselbridgedelayreg(HCLK, ~HRESETn, HREADY, HSELBRIDGE, HSELBRIDGED);
|
||||
endmodule
|
||||
|
@ -75,7 +75,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
|
||||
logic PCSrcE;
|
||||
logic CSRWriteFenceM;
|
||||
logic DivBusyE;
|
||||
logic LoadStallD, StoreStallD, MDUStallD, CSRRdStallD;
|
||||
logic StructuralStallD;
|
||||
logic LoadStallD;
|
||||
logic SquashSCW;
|
||||
logic MDUActiveE; // Mul/Div instruction being executed
|
||||
logic ENVCFG_ADUE; // HPTW A/D Update enable
|
||||
@ -95,7 +96,6 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
|
||||
logic FCvtIntW;
|
||||
logic FDivBusyE;
|
||||
logic FRegWriteM;
|
||||
logic FCvtIntStallD;
|
||||
logic FpLoadStoreM;
|
||||
logic [4:0] SetFflagsM;
|
||||
logic [P.XLEN-1:0] FIntDivResultW;
|
||||
@ -211,8 +211,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
|
||||
.InstrValidM, .InstrValidE, .InstrValidD, .FCvtIntResW, .FCvtIntW,
|
||||
// hazards
|
||||
.StallD, .StallE, .StallM, .StallW, .FlushD, .FlushE, .FlushM, .FlushW,
|
||||
.FCvtIntStallD, .LoadStallD, .MDUStallD, .CSRRdStallD, .PCSrcE,
|
||||
.CSRReadM, .CSRWriteM, .PrivilegedM, .CSRWriteFenceM, .InvalidateICacheM, .StoreStallD);
|
||||
.StructuralStallD, .LoadStallD, .PCSrcE,
|
||||
.CSRReadM, .CSRWriteM, .PrivilegedM, .CSRWriteFenceM, .InvalidateICacheM);
|
||||
|
||||
lsu #(P) lsu(
|
||||
.clk, .reset, .StallM, .FlushM, .StallW, .FlushW,
|
||||
@ -266,9 +266,9 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
|
||||
// global stall and flush control
|
||||
hazard #(P) hzu(
|
||||
.BPWrongE, .CSRWriteFenceM, .RetM, .TrapM,
|
||||
.LoadStallD, .StoreStallD, .MDUStallD, .CSRRdStallD,
|
||||
.StructuralStallD,
|
||||
.LSUStallM, .IFUStallF,
|
||||
.FCvtIntStallD, .FPUStallD,
|
||||
.FPUStallD,
|
||||
.DivBusyE, .FDivBusyE,
|
||||
.wfiM, .IntPendingM,
|
||||
// Stall & flush outputs
|
||||
@ -284,7 +284,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) (
|
||||
.InstrM, .InstrOrigM, .CSRReadValW, .EPCM, .TrapVectorM,
|
||||
.RetM, .TrapM, .sfencevmaM, .InvalidateICacheM, .DCacheStallM, .ICacheStallF,
|
||||
.InstrValidM, .CommittedM, .CommittedF,
|
||||
.FRegWriteM, .LoadStallD, .StoreStallD,
|
||||
.FRegWriteM, .LoadStallD,
|
||||
.BPDirPredWrongM, .BTAWrongM, .BPWrongM,
|
||||
.RASPredPCWrongM, .IClassWrongM, .DivBusyE, .FDivBusyE,
|
||||
.InstrClassM, .DCacheMiss, .DCacheAccess, .ICacheMiss, .ICacheAccess, .PrivilegedM,
|
||||
|
@ -205,12 +205,12 @@ module testbench;
|
||||
|
||||
end
|
||||
|
||||
always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt));
|
||||
always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt));
|
||||
always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt));
|
||||
always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt));
|
||||
always @(dut.core.priv.priv.csr.csrs.csrs.STimerInt) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csrs.csrs.STimerInt));
|
||||
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[7]) void'(rvvi.net_push("MTimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[7]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[11]) void'(rvvi.net_push("MExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[11]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[9]) void'(rvvi.net_push("SExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[9]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[3]) void'(rvvi.net_push("MSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[3]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[1]) void'(rvvi.net_push("SSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[1]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[5]) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[5]));
|
||||
|
||||
final begin
|
||||
void'(rvviRefShutdown());
|
||||
|
@ -432,11 +432,12 @@ module testbench;
|
||||
end
|
||||
end
|
||||
|
||||
always @(dut.core.MTimerInt) void'(rvvi.net_push("MTimerInterrupt", dut.core.MTimerInt));
|
||||
always @(dut.core.MExtInt) void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt));
|
||||
always @(dut.core.SExtInt) void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt));
|
||||
always @(dut.core.MSwInt) void'(rvvi.net_push("MSWInterrupt", dut.core.MSwInt));
|
||||
always @(dut.core.priv.priv.csr.csrs.csrs.STimerInt) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csrs.csrs.STimerInt));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[7]) void'(rvvi.net_push("MTimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[7]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[11]) void'(rvvi.net_push("MExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[11]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[9]) void'(rvvi.net_push("SExternalInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[9]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[3]) void'(rvvi.net_push("MSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[3]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[1]) void'(rvvi.net_push("SSWInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[1]));
|
||||
always @(dut.core.priv.priv.csr.csri.MIP_REGW[5]) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csri.MIP_REGW[5]));
|
||||
|
||||
final begin
|
||||
void'(rvviRefShutdown());
|
||||
|
@ -44,8 +44,9 @@ string tvpaths[] = '{
|
||||
|
||||
string coverage64gc[] = '{
|
||||
`COVERAGE,
|
||||
"tlbmisc",
|
||||
"tlbNAPOT",
|
||||
"ieu",
|
||||
// "tlbNAPOT",
|
||||
"priv",
|
||||
"ebu",
|
||||
"csrwrites",
|
||||
@ -2114,7 +2115,7 @@ string arch64zbs[] = '{
|
||||
`WALLYTEST,
|
||||
"rv32i_m/privilege/src/WALLY-csr-permission-s-01.S",
|
||||
"rv32i_m/privilege/src/WALLY-csr-permission-u-01.S",
|
||||
"rv32i_m/privilege/src/WALLY-cbom-01.S",
|
||||
// "rv32i_m/privilege/src/WALLY-cbom-01.S",
|
||||
"rv32i_m/privilege/src/WALLY-cboz-01.S",
|
||||
"rv32i_m/privilege/src/WALLY-mie-01.S",
|
||||
"rv32i_m/privilege/src/WALLY-minfo-01.S",
|
||||
|
@ -51,9 +51,11 @@ main:
|
||||
jal a1, looptest
|
||||
li a2, 0x40215240 # Test properly formed pages with 1 in PPN[3] that are not NAPOT
|
||||
jal a1, looptest
|
||||
# li t4, 0x1000 # address step size
|
||||
# li a2, 0x80216000 # Test NAPOT pages
|
||||
# jal a1, looptest
|
||||
li t4, 0x1000 # address step size
|
||||
li a2, 0x80216000 # Test NAPOT pages
|
||||
jal a1, looptest
|
||||
li a0, 3 # switch back to machine mode because code at 0x80000000 may not have clean page table entry
|
||||
ecall
|
||||
j done
|
||||
|
||||
looptest:
|
||||
@ -62,30 +64,64 @@ looptest:
|
||||
li t3, 35 # Max amount of Loops = 34
|
||||
li t5, 0x8082 # return instruction opcode
|
||||
|
||||
loop: bge t2, t3, looptesti # exit loop if i >= loops
|
||||
loop: bge t2, t3, finished # exit loop if i >= loops
|
||||
sw t5, 0(t0) # store a return at this address to exercise DTLB
|
||||
lw t1, 0(t0) # read it back
|
||||
fence.i # synchronize with I$
|
||||
jal changetoipfhandler # set up trap handler to return from instruction page fault if necessary
|
||||
jalr ra, t0 # jump to the return statement to exercise the ITLB
|
||||
jal changetodefaulthandler
|
||||
add t0, t0, t4
|
||||
addi t2, t2, 1
|
||||
j loop
|
||||
|
||||
looptesti:
|
||||
mv t0, a2 # base address
|
||||
li t2, 0 # i = 0
|
||||
fence.i # synchronize with I$
|
||||
|
||||
# Exercise itlb by jumping to each of the return statements
|
||||
loopi: bge t2, t3, finished # exit loop if i >= loops
|
||||
jalr ra, t0 # jump to the return statement to exercise the ITLB
|
||||
add t0, t0, t4
|
||||
addi t2, t2, 1
|
||||
j loopi
|
||||
|
||||
finished:
|
||||
jr a1
|
||||
|
||||
changetoipfhandler:
|
||||
li a0, 3
|
||||
ecall # switch to machine mode
|
||||
la a0, ipf_handler
|
||||
csrw mtvec, a0 # point to new handler
|
||||
li a0, 1
|
||||
ecall # switch back to supervisor mode
|
||||
ret
|
||||
|
||||
changetodefaulthandler:
|
||||
li a0, 3
|
||||
ecall # switch to machine mode
|
||||
la a0, trap_handler
|
||||
csrw mtvec, a0 # point to new handler
|
||||
li a0, 1
|
||||
ecall # switch back to supervisor mode
|
||||
ret
|
||||
|
||||
instructionpagefaulthandler:
|
||||
csrw mepc, ra # go back to calling function
|
||||
mret
|
||||
|
||||
.align 4 # trap handlers must be aligned to multiple of 4
|
||||
ipf_handler:
|
||||
# Load trap handler stack pointer tp
|
||||
csrrw tp, mscratch, tp # swap MSCRATCH and tp
|
||||
sd t0, 0(tp) # Save t0 and t1 on the stack
|
||||
sd t1, -8(tp)
|
||||
csrr t0, mcause # Check the cause
|
||||
li t1, 8 # is it an ecall trap?
|
||||
andi t0, t0, 0xFC # if CAUSE = 8, 9, or 11
|
||||
beq t0, t1, ecall # yes, take ecall
|
||||
csrr t0, mcause
|
||||
li t1, 12 # is it an instruction page fault
|
||||
beq t0, t1, ipf # yes, return to calling function
|
||||
j trap_return
|
||||
|
||||
ipf:
|
||||
csrw mepc, ra # return to calling function
|
||||
ld t1, -8(tp) # restore t1 and t0
|
||||
ld t0, 0(tp)
|
||||
csrrw tp, mscratch, tp # restore tp
|
||||
mret # return from trap
|
||||
|
||||
.data
|
||||
|
||||
.align 16
|
||||
|
333
tests/coverage/tlbmisc.S
Normal file
333
tests/coverage/tlbmisc.S
Normal file
@ -0,0 +1,333 @@
|
||||
///////////////////////////////////////////
|
||||
// tlbmisc.S
|
||||
//
|
||||
// Written David_Harris@hmc.edu 1/1/24
|
||||
//
|
||||
// Purpose: Test coverage for other TLB issues
|
||||
//
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// load code to initalize stack, handle interrupts, terminate
|
||||
|
||||
#include "WALLY-init-lib.h"
|
||||
|
||||
# run-elf.bash find this in project description
|
||||
main:
|
||||
li t5, 0x1
|
||||
slli t5, t5, 62
|
||||
ori t5, t5, 0xF0
|
||||
csrs menvcfg, t5 # menvcfg.PBMTE = 1, CBZE, CBCFE, CBIE all 1
|
||||
|
||||
# store ret instruction in case we jump to an address mapping to 80000000
|
||||
li t0, 0x80000000
|
||||
li t5, 0x8082 # return instruction opcode
|
||||
sw t5, 0(t0)
|
||||
fence.i
|
||||
|
||||
# Page table root address at 0x80010000; SV48
|
||||
li t5, 0x9000000000080010
|
||||
csrw satp, t5
|
||||
|
||||
# sfence.vma x0, x0
|
||||
|
||||
# switch to supervisor mode
|
||||
li a0, 1
|
||||
ecall
|
||||
|
||||
# Instruction fetch from misaligned pages
|
||||
jal changetoipfhandler # set up trap handler to return from instruction page fault if necessary
|
||||
li t0, 0x8000000000
|
||||
jalr ra, t0 # jump misaligned terapage
|
||||
li t0, 0x00000000
|
||||
jalr ra, t0 # jump to misaligned gigapage
|
||||
li t0, 0x80200000
|
||||
jalr ra, t0 # jump to misaligned megapage
|
||||
|
||||
# exercise ebufsmarb
|
||||
li t0, 0x80000000
|
||||
lw t1, 0(t0) # fetch from an address to warm up tlb entries
|
||||
li t0, 0x80A00000
|
||||
lw t1, 0(t0) # trigger TLB miss on a non-first entry
|
||||
jal backandforth
|
||||
|
||||
# exercise malformed PBMT pages
|
||||
|
||||
# page has PBMT = 3 (reserved)
|
||||
li t0, 0x80400000
|
||||
lw t1, 0(t0) # read from page
|
||||
sw t1, 0(t0) # write to page
|
||||
jalr ra, t0 # jump to page
|
||||
|
||||
# Nonleaf PTE has PBMT != 0 # this should cause a page fault during page walking. However, as of issue 546 1/1/24, both ImperasDV and Wally don't detect this
|
||||
li t0, 0x80600000
|
||||
lw t1, 0(t0) # read from page
|
||||
sw t1, 0(t0) # write to page
|
||||
jalr ra, t0 # jump to page
|
||||
|
||||
|
||||
# change back to default trap handler after checking everything that might cause an instruction page fault
|
||||
jal changetodefaulthandler
|
||||
|
||||
# exercise CBOM instructions with various permissions
|
||||
li t0, 0x80800000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80801000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80802000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80803000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80804000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
|
||||
# set mstatus.MXR
|
||||
li a0, 3
|
||||
ecall
|
||||
li t0, 1
|
||||
slli t0, t0, 19
|
||||
csrs mstatus, t0 # mstatus.mxr = 1
|
||||
li a0, 1
|
||||
ecall
|
||||
|
||||
# exercise CBOM again now that MXR is set
|
||||
li t0, 0x80800000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80801000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80802000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80803000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
li t0, 0x80804000
|
||||
cbo.zero (t0)
|
||||
cbo.clean (t0)
|
||||
|
||||
# clear mstatus.MXR
|
||||
li a0, 3
|
||||
ecall
|
||||
li t0, 1
|
||||
slli t0, t0, 19
|
||||
csrc mstatus, t0 # mstatus.mxr = 1
|
||||
li a0, 1
|
||||
ecall
|
||||
|
||||
|
||||
# wrap up
|
||||
li a0, 3 # switch back to machine mode because code at 0x80000000 may not have clean page table entry
|
||||
ecall
|
||||
j done
|
||||
|
||||
backandforth:
|
||||
ret
|
||||
|
||||
changetoipfhandler:
|
||||
li a0, 3
|
||||
ecall # switch to machine mode
|
||||
la a0, ipf_handler
|
||||
csrw mtvec, a0 # point to new handler
|
||||
li a0, 1
|
||||
ecall # switch back to supervisor mode
|
||||
ret
|
||||
|
||||
changetodefaulthandler:
|
||||
li a0, 3
|
||||
ecall # switch to machine mode
|
||||
la a0, trap_handler
|
||||
csrw mtvec, a0 # point to new handler
|
||||
li a0, 1
|
||||
ecall # switch back to supervisor mode
|
||||
ret
|
||||
|
||||
instructionpagefaulthandler:
|
||||
csrw mepc, ra # go back to calling function
|
||||
mret
|
||||
|
||||
.align 4 # trap handlers must be aligned to multiple of 4
|
||||
ipf_handler:
|
||||
# Load trap handler stack pointer tp
|
||||
csrrw tp, mscratch, tp # swap MSCRATCH and tp
|
||||
sd t0, 0(tp) # Save t0 and t1 on the stack
|
||||
sd t1, -8(tp)
|
||||
csrr t0, mcause # Check the cause
|
||||
li t1, 8 # is it an ecall trap?
|
||||
andi t0, t0, 0xFC # if CAUSE = 8, 9, or 11
|
||||
beq t0, t1, ecall # yes, take ecall
|
||||
csrr t0, mcause
|
||||
li t1, 12 # is it an instruction page fault
|
||||
beq t0, t1, ipf # yes, return to calling function
|
||||
j trap_return
|
||||
|
||||
ipf:
|
||||
csrw mepc, ra # return to calling function
|
||||
ld t1, -8(tp) # restore t1 and t0
|
||||
ld t0, 0(tp)
|
||||
csrrw tp, mscratch, tp # restore tp
|
||||
mret # return from trap
|
||||
|
||||
.data
|
||||
|
||||
.align 16
|
||||
# root Page table situated at 0x80010000
|
||||
pagetable:
|
||||
.8byte 0x200044C1 # 0x00000000-0x80_00000000: PTE at 0x80011000 C1 dirty, accessed, valid
|
||||
.8byte 0x00000000000010CF # misaligned terapage at 0x80_00000000
|
||||
|
||||
# next page table at 0x80011000
|
||||
.align 12
|
||||
.8byte 0x00000000000010CF # misaligned gigapage at 0x00000000
|
||||
.8byte 0x00000000200058C1 # PTE for pages at 0x40000000
|
||||
.8byte 0x00000000200048C1 # gigapage at 0x80000000 pointing to 0x80120000
|
||||
|
||||
|
||||
# Next page table at 0x80012000 for gigapage at 0x80000000
|
||||
.align 12
|
||||
.8byte 0x0000000020004CC1 # for VA starting at 80000000 (pointer to NAPOT 64 KiB pages)
|
||||
.8byte 0x0000000020014CCF # for VA starting at 80200000 (misaligned megapage)
|
||||
.8byte 0x00000000200050C1 # for VA starting at 80400000 (bad PBMT pages)
|
||||
.8byte 0x4000000020004CC1 # for VA starting at 80600000 (bad entry: nonleaf PTE can't have PBMT != 0)
|
||||
.8byte 0x00000000200054C1 # for VA starting at 80800000 (testing rwx permissiosn with cbom/cboz)
|
||||
.8byte 0x0000000020004CC1 # for VA starting at 80A00000 (pointer to NAPOT 64 KiB pages like at 80000000)
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
.8byte 0x0000000020004CC1
|
||||
|
||||
# Leaf page table at 0x80013000 with NAPOT pages
|
||||
.align 12
|
||||
#80000000
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
.8byte 0xA0000000200020CF
|
||||
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
.8byte 0x80000000200060CF
|
||||
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
.8byte 0x800000002000A0CF
|
||||
|
||||
.8byte 0x800000002000E0CF
|
||||
.8byte 0x800000002000E0CF
|
||||
.8byte 0x800000002000E0CF
|
||||
.8byte 0x800000002000E0CF
|
||||
|
||||
.8byte 0x800000002000E0CF
|
||||
.8byte 0x800000002000E0CF
|
||||
|
||||
# Leaf page table at 0x80014000 with PBMT pages
|
||||
.align 12
|
||||
#80400000
|
||||
.8byte 0x60000000200020CF # reserved entry
|
||||
|
||||
# Leaf page table at 0x80015000 with various permissions for testing CBOM and CBOZ
|
||||
.align 12
|
||||
#80800000
|
||||
.8byte 0x00000000200000CF # valid rwx for VA 80800000
|
||||
.8byte 0x00000000200000CB # valid r x for VA 80801000
|
||||
.8byte 0x00000000200000C3 # valid r for VA 80802000
|
||||
.8byte 0x00000000200000C5 # valid x for VA 80803000
|
||||
.8byte 0x00000000200000CD # valid wx for VA 80804000 (illegal combination, but used to test tlbcontrol)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
hart_ids: [0]
|
||||
hart0:
|
||||
# ISA: RV64IMAFDCSUZicsr_Zicboz_Zifencei_Zca_Zba_Zbb_Zbc_Zbs # Zkbs_Zcb
|
||||
ISA: RV64IMAFDCSUZicsr_Zifencei_Zbb_Zbc_Zbs # Zkbs_Zcb
|
||||
# ISA: RV64IMAFDCSUZicsr_Zicboz_Zifencei_Zbb_Zbc_Zbs # Zkbs_Zcb
|
||||
ISA: RV64IMAFDCSUZicsr_Zifencei_Zca_Zcb_Zbb_Zbc_Zbs # Zkbs_Zcb
|
||||
physical_addr_sz: 56
|
||||
User_Spec_Version: '2.3'
|
||||
supported_xlen: [64]
|
||||
|
Loading…
Reference in New Issue
Block a user