forked from Github_Repos/cvw
Updated riscv64-unknown-elf-gcc location so that it can be easily accessed
This commit is contained in:
commit
89dc9ba6e4
@ -43,15 +43,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1 // Domenico Ottolia 4/15: Support for vectored interrupts in _tvec csrs. Just implemented in src/privileged/trap.sv around line 75. Pretty sure this should be 1.
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
`define PMP_ENTRIES 16
|
||||
|
||||
|
@ -44,15 +44,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1 // Domenico Ottolia 4/15: Support for vectored interrupts in _tvec csrs. Just implemented in src/privileged/trap.sv around line 75. Pretty sure this should be 1.
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
`define PMP_ENTRIES 16
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
//////////////////////////////////////////
|
||||
// wally-config.vh
|
||||
//
|
||||
// Written: David_Harris@hmc.edu 4 January 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: Specify which features are configured
|
||||
// Macros to determine which modes are supported based on MISA
|
||||
//
|
||||
// A component of the Wally configurable RISC-V project.
|
||||
//
|
||||
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
///////////////////////////////////////////
|
||||
|
||||
// include shared configuration
|
||||
`include "wally-shared.vh"
|
||||
|
||||
// RV32 or RV64: XLEN = 32 or 64
|
||||
`define XLEN 64
|
||||
|
||||
//`define MISA (32'h00000104)
|
||||
`define MISA (32'h00000104 | 1<<5 | 1<<18 | 1 << 20)
|
||||
`define ZCSR_SUPPORTED 1
|
||||
`define ZCOUNTERS_SUPPORTED 1
|
||||
|
||||
// Microarchitectural Features
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_VIRTMEM 0
|
||||
|
||||
// Address space
|
||||
`define RESET_VECTOR 64'h0000000000001000
|
||||
|
||||
// Bus Interface width
|
||||
`define AHBW 64
|
||||
|
||||
// Peripheral Addresses
|
||||
// Peripheral memory space extends from BASE to BASE+RANGE
|
||||
// Range should be a thermometer code with 0's in the upper bits and 1s in the lower bits
|
||||
|
||||
`define BOOTTIM_SUPPORTED 1'b1
|
||||
`define BOOTTIM_BASE 56'h00001000
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 56'h02000000
|
||||
`define CLINT_RANGE 56'h0000FFFF
|
||||
`define GPIO_SUPPORTED 1'b1
|
||||
`define GPIO_BASE 56'h10012000
|
||||
`define GPIO_RANGE 56'h000000FF
|
||||
`define UART_SUPPORTED 1'b1
|
||||
`define UART_BASE 56'h10000000
|
||||
`define UART_RANGE 56'h00000007
|
||||
`define PLIC_SUPPORTED 1'b1
|
||||
`define PLIC_BASE 56'h0C000000
|
||||
`define PLIC_RANGE 56'h03FFFFFF
|
||||
|
||||
// Test modes
|
||||
|
||||
// Tie GPIO outputs back to inputs
|
||||
`define GPIO_LOOPBACK_TEST 0
|
||||
|
||||
|
||||
// Hardware configuration
|
||||
`define UART_PRESCALE 1
|
||||
|
@ -43,15 +43,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 0
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Address space
|
||||
`define RESET_VECTOR 64'h00000000000100b0
|
||||
|
||||
|
@ -44,15 +44,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
`define PMP_ENTRIES 64
|
||||
|
||||
|
@ -42,15 +42,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
`define PMP_ENTRIES 16
|
||||
|
||||
|
@ -42,15 +42,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
`define PMP_ENTRIES 16
|
||||
|
||||
|
@ -44,15 +44,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Address space
|
||||
`define RESET_VECTOR 64'h0000000000000000
|
||||
|
||||
|
@ -43,15 +43,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
`define PMP_ENTRIES 64
|
||||
|
||||
@ -73,7 +84,7 @@
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
`define TIM_RANGE 56'h7FFFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 56'h02000000
|
||||
`define CLINT_RANGE 56'h0000FFFF
|
||||
|
@ -43,15 +43,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
`define PMP_ENTRIES 16
|
||||
|
||||
|
@ -42,15 +42,26 @@
|
||||
`define UARCH_PIPELINED 1
|
||||
`define UARCH_SUPERSCALR 0
|
||||
`define UARCH_SINGLECYCLE 0
|
||||
`define MEM_DCACHE 0
|
||||
`define MEM_DCACHE 1
|
||||
`define MEM_DTIM 1
|
||||
`define MEM_ICACHE 0
|
||||
`define MEM_ICACHE 1
|
||||
`define MEM_VIRTMEM 1
|
||||
`define VECTORED_INTERRUPTS_SUPPORTED 1
|
||||
|
||||
// TLB configuration. Entries should be a power of 2
|
||||
`define ITLB_ENTRIES 32
|
||||
`define DTLB_ENTRIES 32
|
||||
|
||||
// Cache configuration. Sizes should be a power of two
|
||||
// typical configuration 4 ways, 4096 bytes per way, 256 bit or more blocks
|
||||
`define DCACHE_NUMWAYS 4
|
||||
`define DCACHE_WAYSIZEINBYTES 2048
|
||||
`define DCACHE_BLOCKLENINBITS 256
|
||||
`define DCACHE_REPLBITS 3
|
||||
`define ICACHE_NUMWAYS 1
|
||||
`define ICACHE_WAYSIZEINBYTES 4096
|
||||
`define ICACHE_BLOCKLENINBITS 256
|
||||
|
||||
// Address space
|
||||
`define RESET_VECTOR 64'h0000000080000000
|
||||
|
||||
|
@ -14,7 +14,7 @@ outDir="../linux-testvectors"
|
||||
# Uncomment this version for QEMU debugging of kernel
|
||||
# - good for poking around VM if it boots up
|
||||
# - good for running QEMU commands (press "Ctrl-A" then "c" to open QEMU command prompt)
|
||||
$customQemu -M virt -nographic -bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio
|
||||
#$customQemu -M virt -nographic -bios $imageDir/fw_jump.elf -kernel $imageDir/Image -append "root=/dev/vda ro" -initrd $imageDir/rootfs.cpio
|
||||
# Uncomment this version for GDB debugging of kernel
|
||||
# - attempts to load in symbols from "vmlinux"
|
||||
# - good for looking at backtraces when Linux gets stuck for some reason
|
||||
@ -30,9 +30,9 @@ $customQemu -M virt -nographic -bios $imageDir/fw_jump.elf -kernel $imageDir/Ima
|
||||
# - Makes qemu_in_gdb_format.txt
|
||||
# - Splits qemu_in_gdb_format.txt into chunks of 100,000 instrs
|
||||
#cat $intermedDir/qemu_output.txt | ./parse_qemu.py >$intermedDir/qemu_in_gdb_format.txt
|
||||
#cd $intermedDir
|
||||
#split -d -l 5600000 ./qemu_in_gdb_format.txt --verbose
|
||||
#cd ../../testvector-generation
|
||||
cd $intermedDir
|
||||
split -d -l 5000000 ./qemu_in_gdb_format.txt --verbose
|
||||
cd ../../testvector-generation
|
||||
|
||||
# Uncomment this version for parse_gdb_output.py debugging
|
||||
# - Uses qemu_in_gdb_format.txt
|
||||
|
@ -6,3 +6,5 @@ c
|
||||
file ../buildroot-image-output/vmlinux
|
||||
b plic_init
|
||||
c
|
||||
b do_idle
|
||||
c
|
||||
|
@ -23,11 +23,11 @@ TestCase = namedtuple("TestCase", ['name', 'cmd', 'grepstr'])
|
||||
|
||||
# edit this list to add more test cases
|
||||
configs = [
|
||||
TestCase(
|
||||
name="busybear",
|
||||
cmd="vsim -do wally-busybear-batch.do -c > {}",
|
||||
grepstr="loaded 100000 instructions"
|
||||
),
|
||||
#TestCase(
|
||||
# name="busybear",
|
||||
# cmd="vsim -do wally-busybear-batch.do -c > {}",
|
||||
# grepstr="loaded 100000 instructions"
|
||||
#),
|
||||
TestCase(
|
||||
name="buildroot",
|
||||
cmd="vsim -do wally-buildroot-batch.do -c > {}",
|
||||
|
16
wally-pipelined/src/cache/dcache.sv
vendored
16
wally-pipelined/src/cache/dcache.sv
vendored
@ -46,6 +46,8 @@ module dcache
|
||||
output logic [`XLEN-1:0] ReadDataM,
|
||||
output logic DCacheStall,
|
||||
output logic CommittedM,
|
||||
output logic DCacheMiss,
|
||||
output logic DCacheAccess,
|
||||
|
||||
// inputs from TLB and PMA/P
|
||||
input logic ExceptionM,
|
||||
@ -66,10 +68,14 @@ module dcache
|
||||
output logic [`XLEN-1:0] HWDATA // to ahb
|
||||
);
|
||||
|
||||
localparam integer BLOCKLEN = 256;
|
||||
/* localparam integer BLOCKLEN = 256;
|
||||
localparam integer NUMLINES = 64;
|
||||
localparam integer NUMWAYS = 4;
|
||||
localparam integer NUMREPL_BITS = 3;
|
||||
localparam integer NUMREPL_BITS = 3;*/
|
||||
localparam integer BLOCKLEN = `DCACHE_BLOCKLENINBITS;
|
||||
localparam integer NUMLINES = `DCACHE_WAYSIZEINBYTES*8/BLOCKLEN;
|
||||
localparam integer NUMWAYS = `DCACHE_NUMWAYS;
|
||||
localparam integer NUMREPL_BITS = `DCACHE_REPLBITS;
|
||||
|
||||
localparam integer BLOCKBYTELEN = BLOCKLEN/8;
|
||||
localparam integer OFFSETLEN = $clog2(BLOCKBYTELEN);
|
||||
@ -437,6 +443,8 @@ module dcache
|
||||
CommittedM = 1'b0;
|
||||
SelUncached = 1'b0;
|
||||
SelEvict = 1'b0;
|
||||
DCacheAccess = 1'b0;
|
||||
DCacheMiss = 1'b0;
|
||||
|
||||
case (CurrState)
|
||||
STATE_READY: begin
|
||||
@ -472,6 +480,7 @@ module dcache
|
||||
// read hit valid cached
|
||||
else if(MemRWM[1] & CacheableM & ~(ExceptionM | PendingInterruptM) & CacheHit & ~DTLBMissM) begin
|
||||
DCacheStall = 1'b0;
|
||||
DCacheAccess = 1'b1;
|
||||
|
||||
if(StallW) begin
|
||||
NextState = STATE_CPU_BUSY;
|
||||
@ -485,6 +494,7 @@ module dcache
|
||||
DCacheStall = 1'b0;
|
||||
SRAMWordWriteEnableM = 1'b1;
|
||||
SetDirtyM = 1'b1;
|
||||
DCacheStall = 1'b1;
|
||||
|
||||
if(StallW) begin
|
||||
NextState = STATE_CPU_BUSY;
|
||||
@ -497,6 +507,8 @@ module dcache
|
||||
NextState = STATE_MISS_FETCH_WDV;
|
||||
CntReset = 1'b1;
|
||||
DCacheStall = 1'b1;
|
||||
DCacheAccess = 1'b1;
|
||||
DCacheMiss = 1'b1;
|
||||
end
|
||||
// uncached write
|
||||
else if(MemRWM[0] & ~CacheableM & ~(ExceptionM | PendingInterruptM) & ~DTLBMissM) begin
|
||||
|
5
wally-pipelined/src/cache/icache.sv
vendored
5
wally-pipelined/src/cache/icache.sv
vendored
@ -53,9 +53,8 @@ module icache
|
||||
);
|
||||
|
||||
// Configuration parameters
|
||||
// TODO Move these to a config file
|
||||
localparam integer BLOCKLEN = 256;
|
||||
localparam integer NUMLINES = 512;
|
||||
localparam integer BLOCKLEN = `ICACHE_BLOCKLENINBITS;
|
||||
localparam integer NUMLINES = `ICACHE_WAYSIZEINBYTES*8/`ICACHE_BLOCKLENINBITS;
|
||||
|
||||
// Input signals to cache memory
|
||||
logic FlushMem;
|
||||
|
@ -89,15 +89,15 @@ module fma1(
|
||||
input logic [2:0] FOpCtrlE, // 000 = fmadd (X*Y)+Z, 001 = fmsub (X*Y)-Z, 010 = fnmsub -(X*Y)+Z, 011 = fnmadd -(X*Y)-Z, 100 = fmul (X*Y)
|
||||
input logic FmtE, // precision 1 = double 0 = single
|
||||
output logic [2*`NF+1:0] ProdManE, // 1.X frac * 1.Y frac in U(2.2Nf) format
|
||||
output logic [3*`NF+5:0] AlignedAddendE, // Z aligned for addition in *** format
|
||||
output logic [3*`NF+5:0] AlignedAddendE, // Z aligned for addition in U(NF+5.2NF+1)
|
||||
output logic [`NE+1:0] ProdExpE, // X exponent + Y exponent - bias in B(NE+2.0) format; adds 2 bits to allow for size of number and negative sign
|
||||
output logic AddendStickyE, // sticky bit that is calculated during alignment
|
||||
output logic KillProdE // set the product to zero before addition if the product is too small to matter
|
||||
);
|
||||
|
||||
logic [`NE+1:0] AlignCnt; // how far to shift the addend to align with the product in Q(NE+2.0) format *** is this enough bits?
|
||||
logic [4*`NF+5:0] ZManShifted; // output of the alignment shifter including sticky bit
|
||||
logic [4*`NF+5:0] ZManPreShifted; // input to the alignment shifter
|
||||
logic [4*`NF+5:0] ZManShifted; // output of the alignment shifter including sticky bits U(NF+5.3NF+1)
|
||||
logic [4*`NF+5:0] ZManPreShifted; // input to the alignment shifter U(NF+5.3NF+1)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Calculate the product
|
||||
@ -132,7 +132,7 @@ module fma1(
|
||||
// |1'b0| addnend |
|
||||
|
||||
// the 1'b0 before the added is because the product's mantissa has two bits before the binary point (xx.xxxxxxxxxx...)
|
||||
assign ZManPreShifted = {55'b0, {ZAssumed1E, ZFracE}, 106'b0};
|
||||
assign ZManPreShifted = {(`NF+3)'(0), {ZAssumed1E, ZFracE}, /*106*/(2*`NF+2)'(0)};
|
||||
always_comb
|
||||
begin
|
||||
|
||||
@ -140,7 +140,7 @@ module fma1(
|
||||
|
||||
// | 54'b0 | 106'b(product) | 2'b0 |
|
||||
// | addnend |
|
||||
if ($signed(AlignCnt) <= $signed(-13'd56)) begin
|
||||
if ($signed(AlignCnt) <= /*$signed(-13'd56)*/-(`NF+4)) begin
|
||||
KillProdE = 1;
|
||||
ZManShifted = ZManPreShifted;//{107'b0, {~ZAssumed1E, ZFrac}, 54'b0};
|
||||
AddendStickyE = ~(XZeroE|YZeroE);
|
||||
@ -149,7 +149,7 @@ module fma1(
|
||||
|
||||
// | 54'b0 | 106'b(product) | 2'b0 |
|
||||
// | addnend |
|
||||
end else if($signed(AlignCnt) <= $signed(13'd0)) begin
|
||||
end else if($signed(AlignCnt) <= 0) begin
|
||||
KillProdE = 0;
|
||||
ZManShifted = ZManPreShifted << -AlignCnt;
|
||||
AddendStickyE = |(ZManShifted[51:0]);
|
||||
@ -158,7 +158,7 @@ module fma1(
|
||||
|
||||
// | 54'b0 | 106'b(product) | 2'b0 |
|
||||
// | addnend |
|
||||
end else if ($signed(AlignCnt)<=$signed(13'd106)) begin
|
||||
end else if ($signed(AlignCnt)<=(2*`NF+2)) begin
|
||||
KillProdE = 0;
|
||||
ZManShifted = ZManPreShifted >> AlignCnt;
|
||||
AddendStickyE = |(ZManShifted[51:0]);
|
||||
@ -176,7 +176,7 @@ module fma1(
|
||||
|
||||
end
|
||||
end
|
||||
assign AlignedAddendE = ZManShifted[213:52];
|
||||
assign AlignedAddendE = ZManShifted[(4*`NF+5):`NF];
|
||||
endmodule
|
||||
|
||||
|
||||
|
@ -103,7 +103,6 @@ module fpu (
|
||||
logic [63:0] FMAResM, FMAResW;
|
||||
logic [4:0] FMAFlgM, FMAFlgW;
|
||||
|
||||
|
||||
logic [63:0] ReadResW;
|
||||
|
||||
// add/cvt signals
|
||||
@ -132,7 +131,6 @@ module fpu (
|
||||
logic [63:0] FPUResultW;
|
||||
logic [4:0] FPUFlagsW;
|
||||
|
||||
|
||||
//DECODE STAGE
|
||||
|
||||
// top-level controller for FPU
|
||||
@ -159,7 +157,6 @@ module fpu (
|
||||
{FRegWriteD, FResultSelD, FResSelD, FIntResSelD, FrmD, FmtD, FOpCtrlD, FWriteIntD},
|
||||
{FRegWriteE, FResultSelE, FResSelE, FIntResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE});
|
||||
|
||||
|
||||
//EXECUTION STAGE
|
||||
|
||||
// Hazard unit for FPU
|
||||
@ -171,11 +168,19 @@ module fpu (
|
||||
mux3 #(64) fyemux(FRD2E, FPUResultW, FResM, FForwardYE, FSrcYE);
|
||||
mux3 #(64) fzemux(FRD3E, FPUResultW, FResM, FForwardZE, FSrcZE);
|
||||
|
||||
unpacking unpacking(.X(FSrcXE), .Y(FSrcYE), .Z(FSrcZE), .FOpCtrlE(FOpCtrlE[2:0]), .FmtE, .XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE, .XFracE, .YFracE, .ZFracE, .XAssumed1E, .YAssumed1E, .ZAssumed1E, .XNaNE, .YNaNE, .ZNaNE, .XSNaNE, .YSNaNE, .ZSNaNE, .XDenormE, .YDenormE, .ZDenormE, .XZeroE, .YZeroE, .ZZeroE, .BiasE, .XInfE, .YInfE, .ZInfE, .XExpMaxE, .XNormE);
|
||||
unpacking unpacking(.X(FSrcXE), .Y(FSrcYE), .Z(FSrcZE),
|
||||
.FOpCtrlE(FOpCtrlE[2:0]), .FmtE, .XSgnE, .YSgnE,
|
||||
.ZSgnE, .XExpE, .YExpE, .ZExpE, .XFracE, .YFracE, .ZFracE,
|
||||
.XAssumed1E, .YAssumed1E, .ZAssumed1E, .XNaNE, .YNaNE, .ZNaNE,
|
||||
.XSNaNE, .YSNaNE, .ZSNaNE, .XDenormE, .YDenormE, .ZDenormE,
|
||||
.XZeroE, .YZeroE, .ZZeroE, .BiasE, .XInfE, .YInfE, .ZInfE, .XExpMaxE, .XNormE);
|
||||
// first of two-stage instance of floating-point fused multiply-add unit
|
||||
fma fma (.clk, .reset, .FlushM, .StallM,
|
||||
.XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE, .XFracE, .YFracE, .ZFracE, .XAssumed1E, .YAssumed1E, .ZAssumed1E, .XDenormE, .YDenormE, .ZDenormE, .XZeroE, .YZeroE, .ZZeroE, .BiasE,
|
||||
.XSgnM, .YSgnM, .ZSgnM, .XExpM, .YExpM, .ZExpM, .XFracM, .YFracM, .ZFracM, .XNaNM, .YNaNM, .ZNaNM, .XZeroM, .YZeroM, .ZZeroM, .XInfM, .YInfM, .ZInfM, .XSNaNM, .YSNaNM, .ZSNaNM,
|
||||
.XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE, .XFracE, .YFracE, .
|
||||
ZFracE, .XAssumed1E, .YAssumed1E, .ZAssumed1E, .XDenormE, .YDenormE,
|
||||
.ZDenormE, .XZeroE, .YZeroE, .ZZeroE, .BiasE,
|
||||
.XSgnM, .YSgnM, .ZSgnM, .XExpM, .YExpM, .ZExpM, .XFracM,
|
||||
.YFracM, .ZFracM, .XNaNM, .YNaNM, .ZNaNM, .XZeroM, .YZeroM, .ZZeroM, .XInfM, .YInfM, .ZInfM, .XSNaNM, .YSNaNM, .ZSNaNM,
|
||||
// .FSrcXE, .FSrcYE, .FSrcZE, .FSrcXM, .FSrcYM, .FSrcZM,
|
||||
.FOpCtrlE(FOpCtrlE[2:0]), .FOpCtrlM(FOpCtrlM[2:0]),
|
||||
.FmtE, .FmtM, .FrmM, .FMAFlgM, .FMAResM);
|
||||
@ -196,18 +201,24 @@ module fpu (
|
||||
.en(1'b1), .clear(FDivSqrtDoneE),
|
||||
.reset(reset), .clk(HoldInputs));
|
||||
//*** add round to nearest ties to max magnitude
|
||||
fpdiv fdivsqrt (.op1(DivInput1E), .op2(DivInput2E), .done(FDivSqrtDoneE), .rm(FrmE[1:0]), .op_type(FOpCtrlE[0]), .P(~FmtE), .FDivBusyE, .HoldInputs,
|
||||
.OvEn(1'b1), .UnEn(1'b1), .start(FDivStartE), .reset, .clk(~clk), .AS_Result(FDivResultM), .Flags(FDivSqrtFlgM));
|
||||
fpdiv fdivsqrt (.op1(DivInput1E), .op2(DivInput2E), .done(FDivSqrtDoneE), .rm(FrmE[1:0]), .op_type(FOpCtrlE[0]),
|
||||
.P(~FmtE), .FDivBusyE, .HoldInputs,
|
||||
.OvEn(1'b1), .UnEn(1'b1),
|
||||
.start(FDivStartE), .reset, .clk(~clk), .AS_Result(FDivResultM), .Flags(FDivSqrtFlgM));
|
||||
|
||||
// .DivOpType(FOpCtrlE[0]), .clk(fpdivClk), .FmtE(~FmtE), .DivInput1E, .DivInput2E,
|
||||
// .FrmE, .DivOvEn(1'b1), .DivUnEn(1'b1), .FDivStartE, .FDivResultM, .FDivSqrtFlgM,
|
||||
// .FDivSqrtDoneE, .FDivBusyE, .HoldInputs, .reset);
|
||||
// assign FDivBusyE = 0;
|
||||
|
||||
// first of two-stage instance of floating-point add/cvt unit
|
||||
faddcvt faddcvt (.clk, .reset, .FlushM, .StallM, .FrmM, .FOpCtrlM, .FmtE, .FmtM,
|
||||
.FSrcXE, .FSrcYE, .FOpCtrlE, .FAddResM, .FAddFlgM);
|
||||
|
||||
// first and only instance of floating-point comparator
|
||||
fcmp fcmp (.op1({XSgnE,XExpE,XFracE}), .op2({YSgnE,YExpE,YFracE}), .FSrcXE, .FSrcYE, .FOpCtrlE(FOpCtrlE[2:0]), .FmtE, .Invalid(CmpNVE), .CmpResE, .XNaNE, .YNaNE, .XZeroE, .YZeroE);
|
||||
fcmp fcmp (.op1({XSgnE,XExpE,XFracE}), .op2({YSgnE,YExpE,YFracE}), .FSrcXE,
|
||||
.FSrcYE, .FOpCtrlE(FOpCtrlE[2:0]), .FmtE,
|
||||
.Invalid(CmpNVE), .CmpResE, .XNaNE, .YNaNE, .XZeroE, .YZeroE);
|
||||
|
||||
// first and only instance of floating-point sign converter
|
||||
fsgn fsgn (.SgnOpCodeE(FOpCtrlE[1:0]), .XSgnE, .YSgnE, .XExpE, .XFracE, .FmtE, .SgnResE, .SgnNVE, .XExpMaxE);
|
||||
@ -215,7 +226,6 @@ module fpu (
|
||||
// first and only instance of floating-point classify unit
|
||||
fclassify fclassify (.XSgnE, .XFracE, .XDenormE, .XZeroE, .XNaNE, .XInfE, .XNormE, .XSNaNE, .ClassResE);
|
||||
|
||||
|
||||
fcvt fcvt (.XSgnE, .XExpE, .XFracE, .XAssumed1E, .XZeroE, .XNaNE, .XInfE, .XDenormE, .BiasE, .SrcAE, .FOpCtrlE, .FmtE, .FrmE, .CvtResE, .CvtFlgE);
|
||||
|
||||
// output for store instructions
|
||||
@ -234,8 +244,6 @@ module fpu (
|
||||
{XZeroE, YZeroE, ZZeroE, XInfE, YInfE, ZInfE, XNaNE, YNaNE, ZNaNE, XSNaNE, YSNaNE, ZSNaNE},
|
||||
{XZeroM, YZeroM, ZZeroM, XInfM, YInfM, ZInfM, XNaNM, YNaNM, ZNaNM, XSNaNM, YSNaNM, ZSNaNM});
|
||||
|
||||
|
||||
|
||||
flopenrc #(1) EMRegCmp1(clk, reset, FlushM, ~StallM, CmpNVE, CmpNVM);
|
||||
flopenrc #(64) EMRegCmp2(clk, reset, FlushM, ~StallM, CmpResE, CmpResM);
|
||||
|
||||
@ -266,15 +274,10 @@ module fpu (
|
||||
// M/W pipe registers
|
||||
//*****************
|
||||
flopenrc #(64) MWRegFma1(clk, reset, FlushW, ~StallW, FMAResM, FMAResW);
|
||||
|
||||
flopenrc #(64) MWRegDiv1(clk, reset, FlushW, ~StallW, FDivResultM, FDivResultW);
|
||||
|
||||
flopenrc #(64) MWRegAdd1(clk, reset, FlushW, ~StallW, FAddResM, FAddResW);
|
||||
|
||||
flopenrc #(64) MWRegCmp3(clk, reset, FlushW, ~StallW, CmpResM, CmpResW);
|
||||
|
||||
flopenrc #(64) MWRegClass2(clk, reset, FlushW, ~StallW, FResM, FResW);
|
||||
|
||||
flopenrc #(6) MWCtrlReg(clk, reset, FlushW, ~StallW,
|
||||
{FRegWriteM, FResultSelM, FmtM, FWriteIntM},
|
||||
{FRegWriteW, FResultSelW, FmtW, FWriteIntW});
|
||||
@ -282,7 +285,6 @@ module fpu (
|
||||
//#########################################
|
||||
// BEGIN WRITEBACK STAGE
|
||||
//#########################################
|
||||
|
||||
mux2 #(64) ReadResMux({{32{1'b1}}, ReadDataW[31:0]}, {{64-`XLEN{1'b1}}, ReadDataW}, FmtW, ReadResW);
|
||||
mux5 #(64) FPUResultMux(ReadResW, FMAResW, FAddResW, FDivResultW, FResW, FResultSelW, FPUResultW);
|
||||
|
||||
|
@ -476,7 +476,7 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
sel_muxa = 3'b011;
|
||||
sel_muxb = 3'b110;
|
||||
sel_muxr = 1'b1;
|
||||
NEXT_STATE = S26;
|
||||
NEXT_STATE = S27;
|
||||
end
|
||||
S26: // done
|
||||
begin
|
||||
|
@ -45,6 +45,8 @@ module lsu
|
||||
output logic CommittedM,
|
||||
output logic SquashSCW,
|
||||
output logic DataMisalignedM,
|
||||
output logic DCacheMiss,
|
||||
output logic DCacheAccess,
|
||||
|
||||
// address and write data
|
||||
input logic [`XLEN-1:0] MemAdrM,
|
||||
@ -315,6 +317,8 @@ module lsu
|
||||
.ReadDataM(HPTWReadPTE),
|
||||
.DCacheStall(DCacheStall),
|
||||
.CommittedM(CommittedMfromDCache),
|
||||
.DCacheMiss,
|
||||
.DCacheAccess,
|
||||
.ExceptionM(ExceptionM),
|
||||
.PendingInterruptM(PendingInterruptMtoDCache),
|
||||
.DTLBMissM(DTLBMissM),
|
||||
|
@ -34,9 +34,10 @@ module pmpadrdec (
|
||||
input logic [7:0] PMPCfg,
|
||||
input logic [`XLEN-1:0] PMPAdr,
|
||||
input logic PAgePMPAdrIn,
|
||||
input logic NoLowerMatchIn,
|
||||
// input logic NoLowerMatchIn,
|
||||
input logic FirstMatch,
|
||||
output logic PAgePMPAdrOut,
|
||||
output logic NoLowerMatchOut,
|
||||
// output logic NoLowerMatchOut,
|
||||
output logic Match, Active,
|
||||
output logic L, X, W, R
|
||||
);
|
||||
@ -47,7 +48,7 @@ module pmpadrdec (
|
||||
|
||||
logic TORMatch, NAMatch;
|
||||
logic PAltPMPAdr;
|
||||
logic FirstMatch;
|
||||
// logic FirstMatch;
|
||||
logic [`PA_BITS-1:0] CurrentAdrFull;
|
||||
logic [1:0] AdrMode;
|
||||
|
||||
@ -69,16 +70,30 @@ module pmpadrdec (
|
||||
|
||||
// verilator lint_off UNOPTFLAT
|
||||
logic [`PA_BITS-1:0] Mask;
|
||||
genvar i;
|
||||
//genvar i;
|
||||
|
||||
// create a mask of which bits to ignore
|
||||
generate
|
||||
// generate
|
||||
// assign Mask[1:0] = 2'b11;
|
||||
// assign Mask[2] = (AdrMode == NAPOT); // mask has 0s in upper bis for NA4 region
|
||||
// for (i=3; i < `PA_BITS; i=i+1) begin:mask
|
||||
// assign Mask[i] = Mask[i-1] & PMPAdr[i-3]; // NAPOT mask: 1's indicate bits to ignore
|
||||
// end
|
||||
// endgenerate
|
||||
prioritycircuit #(.ENTRIES(`PA_BITS-2), .FINAL_OP("NONE")) maskgen(.a(~PMPAdr[`PA_BITS-3:0]), .FirstPin(AdrMode==NAPOT), .y(Mask[`PA_BITS-1:2]));
|
||||
assign Mask[1:0] = 2'b11;
|
||||
assign Mask[2] = (AdrMode == NAPOT); // mask has 0s in upper bis for NA4 region
|
||||
for (i=3; i < `PA_BITS; i=i+1) begin:mask
|
||||
assign Mask[i] = Mask[i-1] & PMPAdr[i-3]; // NAPOT mask: 1's indicate bits to ignore
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// *** possible experiments:
|
||||
/* PA < PMP addr could be in its own module,
|
||||
preeserving hierarchy so we can know if this is the culprit on the critical path
|
||||
Should take logarthmic time, so more like 6 levels than 40 should be expected
|
||||
|
||||
update mask generation
|
||||
Should be concurrent with the subtraction/comparison
|
||||
if one is the critical path, the other shouldn't be which makes us think the mask generation is the culprit.
|
||||
|
||||
Hopefully just use the priority circuit here
|
||||
*/
|
||||
// verilator lint_on UNOPTFLAT
|
||||
|
||||
assign NAMatch = &((PhysicalAddress ~^ CurrentAdrFull) | Mask);
|
||||
@ -87,8 +102,6 @@ module pmpadrdec (
|
||||
(AdrMode == NA4 || AdrMode == NAPOT) ? NAMatch :
|
||||
0;
|
||||
|
||||
assign FirstMatch = NoLowerMatchIn & Match;
|
||||
assign NoLowerMatchOut = NoLowerMatchIn & ~Match;
|
||||
assign L = PMPCfg[7] & FirstMatch;
|
||||
assign X = PMPCfg[2] & FirstMatch;
|
||||
assign W = PMPCfg[1] & FirstMatch;
|
||||
|
@ -55,12 +55,9 @@ module pmpchecker (
|
||||
// Bit i is high when the address falls in PMP region i
|
||||
logic EnforcePMP;
|
||||
logic [7:0] PMPCfg[`PMP_ENTRIES-1:0];
|
||||
logic [`PMP_ENTRIES-1:0] Match; // PMP Entry matches
|
||||
logic [`PMP_ENTRIES-1:0] Match, FirstMatch; // PMP Entry matches
|
||||
logic [`PMP_ENTRIES-1:0] Active; // PMP register i is non-null
|
||||
logic [`PMP_ENTRIES-1:0] L, X, W, R; // PMP matches and has flag set
|
||||
// verilator lint_off UNOPTFLAT
|
||||
logic [`PMP_ENTRIES-1:0] NoLowerMatch; // None of the lower PMP entries match
|
||||
// verilator lint_on UNOPTFLAT
|
||||
logic [`PMP_ENTRIES-1:0] PAgePMPAdr; // for TOR PMP matching, PhysicalAddress > PMPAdr[i]
|
||||
genvar i,j;
|
||||
|
||||
@ -70,9 +67,9 @@ module pmpchecker (
|
||||
.PMPAdr(PMPADDR_ARRAY_REGW),
|
||||
.PAgePMPAdrIn({PAgePMPAdr[`PMP_ENTRIES-2:0], 1'b1}),
|
||||
.PAgePMPAdrOut(PAgePMPAdr),
|
||||
.NoLowerMatchIn({NoLowerMatch[`PMP_ENTRIES-2:0], 1'b1}),
|
||||
.NoLowerMatchOut(NoLowerMatch),
|
||||
.Match, .Active, .L, .X, .W, .R);
|
||||
.FirstMatch, .Match, .Active, .L, .X, .W, .R);
|
||||
|
||||
prioritycircuit #(.ENTRIES(`PMP_ENTRIES), .FINAL_OP("AND")) pmppriority(.a(Match), .FirstPin(1'b1), .y(FirstMatch)); // Take the ripple gates/signals out of the pmpadrdec and into another unit.
|
||||
|
||||
// Only enforce PMP checking for S and U modes when at least one PMP is active or in Machine mode when L bit is set in selected region
|
||||
assign EnforcePMP = (PrivilegeModeW == `M_MODE) ? |L : |Active;
|
||||
|
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////
|
||||
// tlbpriority.sv
|
||||
// prioritycircuit.sv
|
||||
//
|
||||
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 7 April 2021
|
||||
// Modified: Teo Ene 15 Apr 2021:
|
||||
@ -30,8 +30,10 @@
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module tlbpriority #(parameter ENTRIES = 8) (
|
||||
module prioritycircuit #(parameter ENTRIES = 8,
|
||||
parameter FINAL_OP = "AND") (
|
||||
input logic [ENTRIES-1:0] a,
|
||||
input logic FirstPin,
|
||||
output logic [ENTRIES-1:0] y
|
||||
);
|
||||
// verilator lint_off UNOPTFLAT
|
||||
@ -40,11 +42,19 @@ module tlbpriority #(parameter ENTRIES = 8) (
|
||||
// generate thermometer code mask
|
||||
genvar i;
|
||||
generate
|
||||
assign nolower[0] = 1;
|
||||
assign nolower[0] = FirstPin;
|
||||
for (i=1; i<ENTRIES; i++) begin:therm
|
||||
assign nolower[i] = nolower[i-1] & ~a[i-1];
|
||||
end
|
||||
endgenerate
|
||||
// verilator lint_on UNOPTFLAT
|
||||
|
||||
generate
|
||||
if (FINAL_OP=="AND") begin
|
||||
assign y = a & nolower;
|
||||
end else if (FINAL_OP=="NONE") begin
|
||||
assign y = nolower;
|
||||
end // *** So far these are the only two operations I need to do at the end, but feel free to add more as needed.
|
||||
endgenerate
|
||||
// assign y = a & nolower;
|
||||
endmodule
|
@ -39,7 +39,7 @@ module tlblru #(parameter TLB_ENTRIES = 8) (
|
||||
logic AllUsed; // High if the next access causes all RU bits to be 1
|
||||
|
||||
// Find the first line not recently used
|
||||
tlbpriority #(TLB_ENTRIES) nru(~RUBits, WriteLines);
|
||||
prioritycircuit #(.ENTRIES(TLB_ENTRIES), .FINAL_OP("AND")) nru(.a(~RUBits), .FirstPin(1'b1), .y(WriteLines));
|
||||
|
||||
// Track recently used lines, updating on a CAM Hit or TLB write
|
||||
assign WriteEnables = WriteLines & {(TLB_ENTRIES){TLBWrite}};
|
||||
|
@ -46,6 +46,8 @@ module csr #(parameter
|
||||
input logic RASPredPCWrongM,
|
||||
input logic BPPredClassNonCFIWrongM,
|
||||
input logic [4:0] InstrClassM,
|
||||
input logic DCacheMiss,
|
||||
input logic DCacheAccess,
|
||||
input logic [1:0] NextPrivilegeModeM, PrivilegeModeW,
|
||||
input logic [`XLEN-1:0] CauseM, NextFaultMtvalM,
|
||||
input logic BreakpointFaultM, EcallFaultM,
|
||||
|
@ -78,6 +78,8 @@ module csrc #(parameter
|
||||
input logic RASPredPCWrongM,
|
||||
input logic BPPredClassNonCFIWrongM,
|
||||
input logic [4:0] InstrClassM,
|
||||
input logic DCacheMiss,
|
||||
input logic DCacheAccess,
|
||||
input logic [11:0] CSRAdrM,
|
||||
input logic [1:0] PrivilegeModeW,
|
||||
input logic [`XLEN-1:0] CSRWriteValM,
|
||||
@ -143,7 +145,9 @@ module csrc #(parameter
|
||||
assign CounterEvent[8] = RASPredPCWrongM & ~StallM;
|
||||
assign CounterEvent[9] = InstrClassM[3] & ~StallM;
|
||||
assign CounterEvent[10] = BPPredClassNonCFIWrongM & ~StallM;
|
||||
assign CounterEvent[`COUNTERS-1:11] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
|
||||
assign CounterEvent[11] = DCacheAccess & ~StallM;
|
||||
assign CounterEvent[12] = DCacheMiss & ~StallM;
|
||||
assign CounterEvent[`COUNTERS-1:13] = 0; // eventually give these sources, including FP instructions, I$/D$ misses, branches and mispredictions
|
||||
|
||||
for (i = 3; i < `COUNTERS; i = i+1) begin
|
||||
assign WriteHPMCOUNTERM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERBASE + i);
|
||||
|
@ -45,6 +45,8 @@ module privileged (
|
||||
input logic RASPredPCWrongM,
|
||||
input logic BPPredClassNonCFIWrongM,
|
||||
input logic [4:0] InstrClassM,
|
||||
input logic DCacheMiss,
|
||||
input logic DCacheAccess,
|
||||
input logic PrivilegedM,
|
||||
input logic ITLBInstrPageFaultF, DTLBLoadPageFaultM, DTLBStorePageFaultM,
|
||||
input logic WalkerInstrPageFaultF, WalkerLoadPageFaultM, WalkerStorePageFaultM,
|
||||
|
@ -82,7 +82,7 @@ module clint (
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= (`XLEN)'(-1);
|
||||
MTIMECMP <= (64)'(0);
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite) begin
|
||||
if (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
@ -112,7 +112,7 @@ module clint (
|
||||
always_ff @(posedge HCLK or negedge HRESETn)
|
||||
if (~HRESETn) begin
|
||||
MSIP <= 0;
|
||||
MTIMECMP <= (`XLEN)'(-1);
|
||||
MTIMECMP <= (64)'(0);
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite) begin
|
||||
if (entryd == 16'h0000) MSIP <= HWDATA[0];
|
||||
|
@ -164,6 +164,8 @@ module wallypipelinedhart
|
||||
|
||||
logic ExceptionM;
|
||||
logic PendingInterruptM;
|
||||
logic DCacheMiss;
|
||||
logic DCacheAccess;
|
||||
|
||||
|
||||
ifu ifu(.InstrInF(InstrRData),
|
||||
@ -186,6 +188,8 @@ module wallypipelinedhart
|
||||
.ExceptionM(ExceptionM),
|
||||
.PendingInterruptM(PendingInterruptM),
|
||||
.CommittedM(CommittedM),
|
||||
.DCacheMiss,
|
||||
.DCacheAccess,
|
||||
.SquashSCW(SquashSCW),
|
||||
.DataMisalignedM(DataMisalignedM),
|
||||
.MemAdrE(MemAdrE),
|
||||
|
@ -737,12 +737,26 @@ endmodule
|
||||
module riscvassertions();
|
||||
// Legal number of PMP entries are 0, 16, or 64
|
||||
initial begin
|
||||
assert (`PMP_ENTRIES == 0 || `PMP_ENTRIES==16 || `PMP_ENTRIES==64) else $error("Illegal number of PMP entries");
|
||||
assert (`PMP_ENTRIES == 0 || `PMP_ENTRIES==16 || `PMP_ENTRIES==64) else $error("Illegal number of PMP entries: PMP_ENTRIES must be 0, 16, or 64");
|
||||
assert (`F_SUPPORTED || ~`D_SUPPORTED) else $error("Can't support double without supporting float");
|
||||
assert (`XLEN == 64 || ~`D_SUPPORTED) else $error("Wally does not yet support D extensions on RV32");
|
||||
assert (`DCACHE_WAYSIZEINBYTES <= 4096 || `MEM_DCACHE == 0 || `MEM_VIRTMEM == 0) else $error("DCACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing)");
|
||||
assert (`DCACHE_BLOCKLENINBITS >= 128 || `MEM_DCACHE == 0) else $error("DCACHE_BLOCKLENINBITS must be at least 128 when caches are enabled");
|
||||
assert (`DCACHE_BLOCKLENINBITS < `DCACHE_WAYSIZEINBYTES*8) else $error("DCACHE_BLOCKLENINBITS must be smaller than way size");
|
||||
assert (`ICACHE_WAYSIZEINBYTES <= 4096 || `MEM_ICACHE == 0 || `MEM_VIRTMEM == 0) else $error("ICACHE_WAYSIZEINBYTES cannot exceed 4 KiB when caches and vitual memory is enabled (to prevent aliasing)");
|
||||
assert (`ICACHE_BLOCKLENINBITS >= 32 || `MEM_ICACHE == 0) else $error("ICACHE_BLOCKLENINBITS must be at least 32 when caches are enabled");
|
||||
assert (`ICACHE_BLOCKLENINBITS < `ICACHE_WAYSIZEINBYTES*8) else $error("ICACHE_BLOCKLENINBITS must be smaller than way size");
|
||||
assert (2**$clog2(`DCACHE_BLOCKLENINBITS) == `DCACHE_BLOCKLENINBITS) else $error("DCACHE_BLOCKLENINBITS must be a power of 2");
|
||||
assert (2**$clog2(`DCACHE_WAYSIZEINBYTES) == `DCACHE_WAYSIZEINBYTES) else $error("DCACHE_WAYSIZEINBYTES must be a power of 2");
|
||||
assert (2**$clog2(`ICACHE_BLOCKLENINBITS) == `ICACHE_BLOCKLENINBITS) else $error("ICACHE_BLOCKLENINBITS must be a power of 2");
|
||||
assert (2**$clog2(`ICACHE_WAYSIZEINBYTES) == `ICACHE_WAYSIZEINBYTES) else $error("ICACHE_WAYSIZEINBYTES must be a power of 2");
|
||||
assert (`ICACHE_NUMWAYS == 1 || `MEM_ICACHE == 0) else $error("Multiple Instruction Cache ways not yet implemented");
|
||||
assert (2**$clog2(`ITLB_ENTRIES) == `ITLB_ENTRIES) else $error("ITLB_ENTRIES must be a power of 2");
|
||||
assert (2**$clog2(`DTLB_ENTRIES) == `DTLB_ENTRIES) else $error("DTLB_ENTRIES must be a power of 2");
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
||||
/* verilator lint_on STMTDLY */
|
||||
/* verilator lint_on WIDTH */
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
module testbench();
|
||||
|
||||
parameter waveOnICount = `BUSYBEAR*140000 + `BUILDROOT*0459700; // # of instructions at which to turn on waves in graphical sim
|
||||
parameter waveOnICount = `BUSYBEAR*140000 + `BUILDROOT*0900000; // # of instructions at which to turn on waves in graphical sim
|
||||
parameter stopICount = `BUSYBEAR*143898 + `BUILDROOT*0000000; // # instructions at which to halt sim completely (set to 0 to let it run as far as it can)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -103,6 +103,7 @@ module testbench();
|
||||
logic [99:0] StartCSRexpected[63:0];
|
||||
string StartCSRname[99:0];
|
||||
integer data_file_csr, scan_file_csr;
|
||||
logic IllegalInstrFaultd;
|
||||
|
||||
// -----------
|
||||
// Error Macro
|
||||
@ -153,21 +154,22 @@ module testbench();
|
||||
clk <= 1; # 5; clk <= 0; # 5;
|
||||
end
|
||||
|
||||
// -------------------
|
||||
// Additional Hardware
|
||||
// -------------------
|
||||
always @(posedge clk)
|
||||
IllegalInstrFaultd = dut.hart.priv.IllegalInstrFaultM;
|
||||
|
||||
// -------------------------------------
|
||||
// Special warnings for important faults
|
||||
// -------------------------------------
|
||||
always @(dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW) begin
|
||||
if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 2 && instrs > 1) begin
|
||||
$display("!!!!!! illegal instruction !!!!!!!!!!");
|
||||
$display("(as a reminder, MCAUSE and MEPC are set by this)");
|
||||
$display("at %0t ps, PCM %x, instr %0d, dut.hart.lsu.dcache.MemPAdrM %x", $time, dut.hart.ifu.PCM, instrs, dut.hart.lsu.dcache.MemPAdrM);
|
||||
`ERROR
|
||||
// This is sometimes okay if the source code intentionally causes it.
|
||||
$display("Warning: illegal instruction exception at %0t ps, InstrNum %0d, PCM %x, InstrM %s", $time, instrs, dut.hart.ifu.PCM, PCtextM);
|
||||
end
|
||||
if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 5 && instrs != 0) begin
|
||||
$display("!!!!!! illegal (physical) memory access !!!!!!!!!!");
|
||||
$display("(as a reminder, MCAUSE and MEPC are set by this)");
|
||||
$display("at %0t ps, PCM %x, instr %0d, dut.hart.lsu.dcache.MemPAdrM %x", $time, dut.hart.ifu.PCM, instrs, dut.hart.lsu.dcache.MemPAdrM);
|
||||
`ERROR
|
||||
$display("Warning: illegal physical memory access exception at %0t ps, InstrNum %0d, PCM %x, InstrM %s", $time, instrs, dut.hart.ifu.PCM, PCtextM);
|
||||
end
|
||||
end
|
||||
|
||||
@ -185,8 +187,14 @@ module testbench();
|
||||
// Hack to compensate for QEMU's incorrect MSTATUS
|
||||
end else if (PCtextW.substr(0,3) == "csrr" && PCtextW.substr(10,16) == "mstatus") begin
|
||||
force dut.hart.ieu.dp.regf.wd3 = dut.hart.ieu.dp.WriteDataW & ~64'ha00000000;
|
||||
end else
|
||||
release dut.hart.ieu.dp.regf.wd3;
|
||||
end else release dut.hart.ieu.dp.regf.wd3;
|
||||
// Hack to compensate for QEMU's correct but different MTVAL (according to spec, storing the faulting instr is an optional feature)
|
||||
if (PCtextW.substr(0,3) == "csrr" && PCtextW.substr(10,14) == "mtval") begin
|
||||
force dut.hart.ieu.dp.WriteDataW = 0;
|
||||
// Hack to compensate for QEMU's correct but different mhpmcounter's (these too are optional)
|
||||
end else if (PCtextW.substr(0,3) == "csrr" && PCtextW.substr(10,20) == "mhpmcounter") begin
|
||||
force dut.hart.ieu.dp.WriteDataW = 0;
|
||||
end else release dut.hart.ieu.dp.WriteDataW;
|
||||
end
|
||||
end
|
||||
|
||||
@ -194,7 +202,6 @@ module testbench();
|
||||
// Big Chunky Block
|
||||
// ----------------
|
||||
always @(reset or dut.hart.ifu.InstrRawD or dut.hart.ifu.PCD) begin// or negedge dut.hart.ifu.StallE) begin // Why do we care about StallE? Everything seems to run fine without it.
|
||||
if(~dut.hart.lsu.dcache.MemRWM) begin // *** Should this need to consider dut.hart.lsu.dcache.MemRWM?
|
||||
#2;
|
||||
// If PCD/InstrD aren't garbage
|
||||
if (~reset && dut.hart.ifu.InstrRawD[15:0] !== {16{1'bx}} && dut.hart.ifu.PCD !== 64'h0) begin // && ~dut.hart.ifu.StallE) begin
|
||||
@ -205,7 +212,6 @@ module testbench();
|
||||
lastPC2 <= lastPC;
|
||||
// If PCD isn't going to be flushed
|
||||
if (~PCDwrong || lastPC == PCDexpected) begin
|
||||
|
||||
// Stop if we've reached the end
|
||||
if($feof(data_file_PCF)) begin
|
||||
$display("no more PC data to read... CONGRATULATIONS!!!");
|
||||
@ -254,29 +260,7 @@ module testbench();
|
||||
|
||||
// Check if PCD is going to be flushed due to a branch or jump
|
||||
if (`BPRED_ENABLED) begin
|
||||
PCDwrong = dut.hart.hzu.FlushD; //Old version: dut.hart.ifu.bpred.bpred.BPPredWrongE; <-- This old version failed to account for MRET.
|
||||
end else begin
|
||||
casex (lastInstrDExpected[31:0])
|
||||
32'b00000000001000000000000001110011, // URET
|
||||
32'b00010000001000000000000001110011, // SRET
|
||||
32'b00110000001000000000000001110011, // MRET
|
||||
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1101111, // JAL
|
||||
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100111, // JALR
|
||||
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100011, // B
|
||||
32'bXXXXXXXXXXXXXXXX110XXXXXXXXXXX01, // C.BEQZ
|
||||
32'bXXXXXXXXXXXXXXXX111XXXXXXXXXXX01, // C.BNEZ
|
||||
32'bXXXXXXXXXXXXXXXX101XXXXXXXXXXX01: // C.J
|
||||
PCDwrong = 1;
|
||||
32'bXXXXXXXXXXXXXXXX1001000000000010, // C.EBREAK:
|
||||
32'bXXXXXXXXXXXXXXXXX000XXXXX1110011: // Something that's not CSRR*
|
||||
PCDwrong = 0; // tbh don't really know what should happen here
|
||||
32'b000110000000XXXXXXXXXXXXX1110011, // CSR* SATP, *
|
||||
32'bXXXXXXXXXXXXXXXX1000XXXXX0000010, // C.JR
|
||||
32'bXXXXXXXXXXXXXXXX1001XXXXX0000010: // C.JALR //this is RV64 only so no C.JAL
|
||||
PCDwrong = 1;
|
||||
default:
|
||||
PCDwrong = 0;
|
||||
endcase
|
||||
PCDwrong = dut.hart.hzu.FlushD || (PCtextE.substr(0,3) == "mret"); //Old version: dut.hart.ifu.bpred.bpred.BPPredWrongE; <-- This old version failed to account for MRET.
|
||||
end
|
||||
|
||||
// Check PCD, InstrD
|
||||
@ -309,7 +293,6 @@ module testbench();
|
||||
lastPCD = dut.hart.ifu.PCD;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////// PC,Instr Checking ///////////////////////////////
|
||||
@ -360,9 +343,8 @@ module testbench();
|
||||
end
|
||||
`SCAN_PC(data_file_PCM, scan_file_PCM, trashString, trashString, InstrMExpected, PCMexpected);
|
||||
`SCAN_PC(data_file_PCW, scan_file_PCW, trashString, trashString, InstrWExpected, PCWexpected);
|
||||
// If repeated instr
|
||||
// If repeated or instruction, we want to skip over it (indicates an interrupt)
|
||||
if (PCMexpected == PCWexpected) begin
|
||||
// Increment file pointers past the repeated instruction.
|
||||
`SCAN_PC(data_file_PCM, scan_file_PCM, trashString, trashString, InstrMExpected, PCMexpected);
|
||||
`SCAN_PC(data_file_PCW, scan_file_PCW, trashString, trashString, InstrWExpected, PCWexpected);
|
||||
end
|
||||
@ -371,6 +353,11 @@ module testbench();
|
||||
`ERROR
|
||||
end
|
||||
end
|
||||
// Skip over faulting instructions because they do not make it to the W stage.
|
||||
if (IllegalInstrFaultd) begin
|
||||
`SCAN_PC(data_file_PCM, scan_file_PCM, trashString, trashString, InstrMExpected, PCMexpected);
|
||||
`SCAN_PC(data_file_PCW, scan_file_PCW, trashString, trashString, InstrWExpected, PCWexpected);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -453,8 +440,7 @@ module testbench();
|
||||
// Read Checker
|
||||
// ------------
|
||||
always @(negedge clk) begin
|
||||
//if (dut.hart.MemRWM[1] && ~dut.hart.StallM && ~dut.hart.FlushM && dut.hart.ieu.InstrValidM) begin <-- This doesn't work because ReadDataM can be used for other things (namely page table walking) while the pipeline is stalled, leaving it in a different state when the pipeline unstalls
|
||||
if (dut.hart.MemRWM[1] && dut.hart.lsu.dcache.ReadDataWEn) begin // <-- ReadDataWEn is a good indicator that the pipeline is using the current contents of ReadDataM
|
||||
if (dut.hart.MemRWM[1] && ~dut.hart.StallM && ~dut.hart.FlushM && dut.hart.ieu.InstrValidM) begin
|
||||
if($feof(data_file_memR)) begin
|
||||
$display("no more memR data to read");
|
||||
`ERROR
|
||||
@ -530,39 +516,24 @@ module testbench();
|
||||
// --------------
|
||||
// Checker Macros
|
||||
// --------------
|
||||
string MSTATUSstring = "MSTATUS"; // string variables seem to compare more reliably than string literals (they gave me a lot of hassle), but *** there's probably a better way to do this
|
||||
// String variables seem to compare more reliably than string literals (they gave me a lot of hassle),
|
||||
// but *** there's probably a better way to do this.
|
||||
// You can't just use the "__name" variables though because you need to declare variables before using them.
|
||||
string MSTATUSstring = "MSTATUS";
|
||||
string MIPstring = "MIP";
|
||||
string MEPCstring = "MEPC";
|
||||
string MCAUSEstring = "MCAUSE";
|
||||
string MTVALstring = "MTVAL";
|
||||
string SEPCstring = "SEPC";
|
||||
string SCAUSEstring = "SCAUSE";
|
||||
string SSTATUSstring = "SSTATUS";
|
||||
|
||||
logic [63:0] expectedCSR;
|
||||
string expectedCSRname;
|
||||
`define CHECK_CSR2(CSR, PATH) \
|
||||
logic [63:0] expected``CSR``; \
|
||||
string CSR; \
|
||||
string ``CSR``name = `"CSR`"; \
|
||||
string expected``CSR``name; \
|
||||
always @(``PATH``.``CSR``_REGW) begin \
|
||||
if ($time > 1 && (`BUILDROOT != 1 || ``CSR``name != SSTATUSstring)) begin \
|
||||
// This is some feeble hackery designed to control the order in which CSRs are checked \
|
||||
// when multiple change at the same time. \
|
||||
if (``CSR``name == SEPCstring) #1; \
|
||||
if (``CSR``name == SCAUSEstring) #2; \
|
||||
if (``CSR``name == SSTATUSstring) #3; \
|
||||
scan_file_csr = $fscanf(data_file_csr, "%s\n", expected``CSR``name); \
|
||||
scan_file_csr = $fscanf(data_file_csr, "%x\n", expected``CSR``); \
|
||||
if(expected``CSR``name.icompare(``CSR``name)) begin \
|
||||
$display("%0t ps, PCM %x %s, instr %0d: %s changed, expected %s", $time, dut.hart.ifu.PCM, PCtextM, instrs, `"CSR`", expected``CSR``name); \
|
||||
end \
|
||||
if (``CSR``name == MSTATUSstring) begin \
|
||||
if (``PATH``.``CSR``_REGW != ((``expected``CSR) | 64'ha00000000)) begin \
|
||||
$display("%0t ps, PCM %x %s, instr %0d: %s (should be MSTATUS) does not equal %s expected: %x, %x", $time, dut.hart.ifu.PCM, PCtextM, instrs, ``CSR``name, expected``CSR``name, ``PATH``.``CSR``_REGW, (``expected``CSR) | 64'ha00000000); \
|
||||
`ERROR \
|
||||
end \
|
||||
end else \
|
||||
if (``PATH``.``CSR``_REGW != ``expected``CSR[$bits(``PATH``.``CSR``_REGW)-1:0]) begin \
|
||||
$display("%0t ps, PCM %x %s, instr %0d: %s does not equal %s expected: %x, %x", $time, dut.hart.ifu.PCM, PCtextM, instrs, ``CSR``name, expected``CSR``name, ``PATH``.``CSR``_REGW, ``expected``CSR); \
|
||||
`ERROR \
|
||||
end \
|
||||
end else begin \
|
||||
if (!(`BUILDROOT == 1 && ``CSR``name == MSTATUSstring)) begin \
|
||||
if (instrs == 0 && ~reset) begin \
|
||||
for(integer j=0; j<totalCSR; j++) begin \
|
||||
if(!StartCSRname[j].icompare(``CSR``name)) begin \
|
||||
if(``PATH``.``CSR``_REGW != StartCSRexpected[j]) begin \
|
||||
@ -571,6 +542,37 @@ module testbench();
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
$display("CSRs' intital states look good"); \
|
||||
end else begin \
|
||||
// MIP is not checked because QEMU bodges it (MTIP in particular), and even if QEMU reported it correctly, the timing would still be off \
|
||||
// MTVAL is not checked on illegal instr faults because QEMU chooses not to implement the behavior where MTVAL is written with the faulting instruction \
|
||||
if (~reset && ``CSR``name != MIPstring && ~(IllegalInstrFaultd && ``CSR``name == MTVALstring)) begin \
|
||||
// This is some feeble hackery designed to control the order in which CSRs are checked \
|
||||
// when multiple change at the same time. \
|
||||
// *** it would be better for each CSR to have its own testvector file \
|
||||
// so as to avoid this awkward ordering problem. \
|
||||
if (``CSR``name == MEPCstring) #1; \
|
||||
if (``CSR``name == MCAUSEstring) #2; \
|
||||
if (``CSR``name == MTVALstring) #3; \
|
||||
if (``CSR``name == SEPCstring) #1; \
|
||||
if (``CSR``name == SCAUSEstring) #2; \
|
||||
if (``CSR``name == SSTATUSstring) #3; \
|
||||
scan_file_csr = $fscanf(data_file_csr, "%s\n", expectedCSRname); \
|
||||
scan_file_csr = $fscanf(data_file_csr, "%x\n", expectedCSR); \
|
||||
if(expectedCSRname.icompare(``CSR``name)) begin \
|
||||
$display("%0t ps, PCM %x %s, instr %0d: %s changed, expected %s", $time, dut.hart.ifu.PCM, PCtextM, instrs, `"CSR`", expectedCSRname); \
|
||||
end \
|
||||
if (``CSR``name == MSTATUSstring) begin \
|
||||
if (``PATH``.``CSR``_REGW != ((expectedCSR) | 64'ha00000000)) begin \
|
||||
$display("%0t ps, PCM %x %s, instr %0d: %s (should be MSTATUS) does not equal %s expected: %x, %x", $time, dut.hart.ifu.PCM, PCtextM, instrs, ``CSR``name, expectedCSRname, ``PATH``.``CSR``_REGW, expectedCSR | 64'ha00000000); \
|
||||
`ERROR \
|
||||
end \
|
||||
end else begin \
|
||||
if (``PATH``.``CSR``_REGW != expectedCSR[$bits(``PATH``.``CSR``_REGW)-1:0]) begin \
|
||||
$display("%0t ps, PCM %x %s, instr %0d: %s does not equal %s expected: %x, %x", $time, dut.hart.ifu.PCM, PCtextM, instrs, ``CSR``name, expectedCSRname, ``PATH``.``CSR``_REGW, expectedCSR); \
|
||||
`ERROR \
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
end \
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user