Updated riscv64-unknown-elf-gcc location so that it can be easily accessed

This commit is contained in:
Abe 2021-07-20 14:18:13 -04:00
commit 89dc9ba6e4
31 changed files with 721 additions and 628 deletions

View File

@ -43,15 +43,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 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. `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 ITLB_ENTRIES 32
`define DTLB_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 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -44,15 +44,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 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. `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 ITLB_ENTRIES 32
`define DTLB_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 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -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

View File

@ -43,15 +43,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 0 `define MEM_VIRTMEM 0
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Address space
`define RESET_VECTOR 64'h00000000000100b0 `define RESET_VECTOR 64'h00000000000100b0

View File

@ -44,15 +44,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 1 `define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 64 `define PMP_ENTRIES 64

View File

@ -42,15 +42,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 1 `define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -42,15 +42,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 1 `define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -44,15 +44,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 1 `define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Address space
`define RESET_VECTOR 64'h0000000000000000 `define RESET_VECTOR 64'h0000000000000000

View File

@ -43,15 +43,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 1 `define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 64 `define PMP_ENTRIES 64
@ -73,7 +84,7 @@
`define BOOTTIM_RANGE 56'h00000FFF `define BOOTTIM_RANGE 56'h00000FFF
`define TIM_SUPPORTED 1'b1 `define TIM_SUPPORTED 1'b1
`define TIM_BASE 56'h80000000 `define TIM_BASE 56'h80000000
`define TIM_RANGE 56'h07FFFFFF `define TIM_RANGE 56'h7FFFFFFF
`define CLINT_SUPPORTED 1'b1 `define CLINT_SUPPORTED 1'b1
`define CLINT_BASE 56'h02000000 `define CLINT_BASE 56'h02000000
`define CLINT_RANGE 56'h0000FFFF `define CLINT_RANGE 56'h0000FFFF

View File

@ -43,15 +43,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 1 `define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Legal number of PMP entries are 0, 16, or 64
`define PMP_ENTRIES 16 `define PMP_ENTRIES 16

View File

@ -42,15 +42,26 @@
`define UARCH_PIPELINED 1 `define UARCH_PIPELINED 1
`define UARCH_SUPERSCALR 0 `define UARCH_SUPERSCALR 0
`define UARCH_SINGLECYCLE 0 `define UARCH_SINGLECYCLE 0
`define MEM_DCACHE 0 `define MEM_DCACHE 1
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 1
`define MEM_VIRTMEM 1 `define MEM_VIRTMEM 1
`define VECTORED_INTERRUPTS_SUPPORTED 1 `define VECTORED_INTERRUPTS_SUPPORTED 1
// TLB configuration. Entries should be a power of 2
`define ITLB_ENTRIES 32 `define ITLB_ENTRIES 32
`define DTLB_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 // Address space
`define RESET_VECTOR 64'h0000000080000000 `define RESET_VECTOR 64'h0000000080000000

View File

@ -14,7 +14,7 @@ outDir="../linux-testvectors"
# Uncomment this version for QEMU debugging of kernel # Uncomment this version for QEMU debugging of kernel
# - good for poking around VM if it boots up # - good for poking around VM if it boots up
# - good for running QEMU commands (press "Ctrl-A" then "c" to open QEMU command prompt) # - 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 # Uncomment this version for GDB debugging of kernel
# - attempts to load in symbols from "vmlinux" # - attempts to load in symbols from "vmlinux"
# - good for looking at backtraces when Linux gets stuck for some reason # - 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 # - Makes qemu_in_gdb_format.txt
# - Splits qemu_in_gdb_format.txt into chunks of 100,000 instrs # - 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 #cat $intermedDir/qemu_output.txt | ./parse_qemu.py >$intermedDir/qemu_in_gdb_format.txt
#cd $intermedDir cd $intermedDir
#split -d -l 5600000 ./qemu_in_gdb_format.txt --verbose split -d -l 5000000 ./qemu_in_gdb_format.txt --verbose
#cd ../../testvector-generation cd ../../testvector-generation
# Uncomment this version for parse_gdb_output.py debugging # Uncomment this version for parse_gdb_output.py debugging
# - Uses qemu_in_gdb_format.txt # - Uses qemu_in_gdb_format.txt

View File

@ -6,3 +6,5 @@ c
file ../buildroot-image-output/vmlinux file ../buildroot-image-output/vmlinux
b plic_init b plic_init
c c
b do_idle
c

View File

@ -23,11 +23,11 @@ TestCase = namedtuple("TestCase", ['name', 'cmd', 'grepstr'])
# edit this list to add more test cases # edit this list to add more test cases
configs = [ configs = [
TestCase( #TestCase(
name="busybear", # name="busybear",
cmd="vsim -do wally-busybear-batch.do -c > {}", # cmd="vsim -do wally-busybear-batch.do -c > {}",
grepstr="loaded 100000 instructions" # grepstr="loaded 100000 instructions"
), #),
TestCase( TestCase(
name="buildroot", name="buildroot",
cmd="vsim -do wally-buildroot-batch.do -c > {}", cmd="vsim -do wally-buildroot-batch.do -c > {}",

View File

@ -46,6 +46,8 @@ module dcache
output logic [`XLEN-1:0] ReadDataM, output logic [`XLEN-1:0] ReadDataM,
output logic DCacheStall, output logic DCacheStall,
output logic CommittedM, output logic CommittedM,
output logic DCacheMiss,
output logic DCacheAccess,
// inputs from TLB and PMA/P // inputs from TLB and PMA/P
input logic ExceptionM, input logic ExceptionM,
@ -66,10 +68,14 @@ module dcache
output logic [`XLEN-1:0] HWDATA // to ahb output logic [`XLEN-1:0] HWDATA // to ahb
); );
localparam integer BLOCKLEN = 256; /* localparam integer BLOCKLEN = 256;
localparam integer NUMLINES = 64; localparam integer NUMLINES = 64;
localparam integer NUMWAYS = 4; 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 BLOCKBYTELEN = BLOCKLEN/8;
localparam integer OFFSETLEN = $clog2(BLOCKBYTELEN); localparam integer OFFSETLEN = $clog2(BLOCKBYTELEN);
@ -437,6 +443,8 @@ module dcache
CommittedM = 1'b0; CommittedM = 1'b0;
SelUncached = 1'b0; SelUncached = 1'b0;
SelEvict = 1'b0; SelEvict = 1'b0;
DCacheAccess = 1'b0;
DCacheMiss = 1'b0;
case (CurrState) case (CurrState)
STATE_READY: begin STATE_READY: begin
@ -472,6 +480,7 @@ module dcache
// read hit valid cached // read hit valid cached
else if(MemRWM[1] & CacheableM & ~(ExceptionM | PendingInterruptM) & CacheHit & ~DTLBMissM) begin else if(MemRWM[1] & CacheableM & ~(ExceptionM | PendingInterruptM) & CacheHit & ~DTLBMissM) begin
DCacheStall = 1'b0; DCacheStall = 1'b0;
DCacheAccess = 1'b1;
if(StallW) begin if(StallW) begin
NextState = STATE_CPU_BUSY; NextState = STATE_CPU_BUSY;
@ -485,6 +494,7 @@ module dcache
DCacheStall = 1'b0; DCacheStall = 1'b0;
SRAMWordWriteEnableM = 1'b1; SRAMWordWriteEnableM = 1'b1;
SetDirtyM = 1'b1; SetDirtyM = 1'b1;
DCacheStall = 1'b1;
if(StallW) begin if(StallW) begin
NextState = STATE_CPU_BUSY; NextState = STATE_CPU_BUSY;
@ -497,6 +507,8 @@ module dcache
NextState = STATE_MISS_FETCH_WDV; NextState = STATE_MISS_FETCH_WDV;
CntReset = 1'b1; CntReset = 1'b1;
DCacheStall = 1'b1; DCacheStall = 1'b1;
DCacheAccess = 1'b1;
DCacheMiss = 1'b1;
end end
// uncached write // uncached write
else if(MemRWM[0] & ~CacheableM & ~(ExceptionM | PendingInterruptM) & ~DTLBMissM) begin else if(MemRWM[0] & ~CacheableM & ~(ExceptionM | PendingInterruptM) & ~DTLBMissM) begin

View File

@ -53,9 +53,8 @@ module icache
); );
// Configuration parameters // Configuration parameters
// TODO Move these to a config file localparam integer BLOCKLEN = `ICACHE_BLOCKLENINBITS;
localparam integer BLOCKLEN = 256; localparam integer NUMLINES = `ICACHE_WAYSIZEINBYTES*8/`ICACHE_BLOCKLENINBITS;
localparam integer NUMLINES = 512;
// Input signals to cache memory // Input signals to cache memory
logic FlushMem; logic FlushMem;

View File

@ -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 [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 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 [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 [`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 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 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 [`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] 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 logic [4*`NF+5:0] ZManPreShifted; // input to the alignment shifter U(NF+5.3NF+1)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Calculate the product // Calculate the product
@ -132,7 +132,7 @@ module fma1(
// |1'b0| addnend | // |1'b0| addnend |
// the 1'b0 before the added is because the product's mantissa has two bits before the binary point (xx.xxxxxxxxxx...) // 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 always_comb
begin begin
@ -140,7 +140,7 @@ module fma1(
// | 54'b0 | 106'b(product) | 2'b0 | // | 54'b0 | 106'b(product) | 2'b0 |
// | addnend | // | addnend |
if ($signed(AlignCnt) <= $signed(-13'd56)) begin if ($signed(AlignCnt) <= /*$signed(-13'd56)*/-(`NF+4)) begin
KillProdE = 1; KillProdE = 1;
ZManShifted = ZManPreShifted;//{107'b0, {~ZAssumed1E, ZFrac}, 54'b0}; ZManShifted = ZManPreShifted;//{107'b0, {~ZAssumed1E, ZFrac}, 54'b0};
AddendStickyE = ~(XZeroE|YZeroE); AddendStickyE = ~(XZeroE|YZeroE);
@ -149,7 +149,7 @@ module fma1(
// | 54'b0 | 106'b(product) | 2'b0 | // | 54'b0 | 106'b(product) | 2'b0 |
// | addnend | // | addnend |
end else if($signed(AlignCnt) <= $signed(13'd0)) begin end else if($signed(AlignCnt) <= 0) begin
KillProdE = 0; KillProdE = 0;
ZManShifted = ZManPreShifted << -AlignCnt; ZManShifted = ZManPreShifted << -AlignCnt;
AddendStickyE = |(ZManShifted[51:0]); AddendStickyE = |(ZManShifted[51:0]);
@ -158,7 +158,7 @@ module fma1(
// | 54'b0 | 106'b(product) | 2'b0 | // | 54'b0 | 106'b(product) | 2'b0 |
// | addnend | // | addnend |
end else if ($signed(AlignCnt)<=$signed(13'd106)) begin end else if ($signed(AlignCnt)<=(2*`NF+2)) begin
KillProdE = 0; KillProdE = 0;
ZManShifted = ZManPreShifted >> AlignCnt; ZManShifted = ZManPreShifted >> AlignCnt;
AddendStickyE = |(ZManShifted[51:0]); AddendStickyE = |(ZManShifted[51:0]);
@ -176,7 +176,7 @@ module fma1(
end end
end end
assign AlignedAddendE = ZManShifted[213:52]; assign AlignedAddendE = ZManShifted[(4*`NF+5):`NF];
endmodule endmodule

View File

@ -103,7 +103,6 @@ module fpu (
logic [63:0] FMAResM, FMAResW; logic [63:0] FMAResM, FMAResW;
logic [4:0] FMAFlgM, FMAFlgW; logic [4:0] FMAFlgM, FMAFlgW;
logic [63:0] ReadResW; logic [63:0] ReadResW;
// add/cvt signals // add/cvt signals
@ -132,7 +131,6 @@ module fpu (
logic [63:0] FPUResultW; logic [63:0] FPUResultW;
logic [4:0] FPUFlagsW; logic [4:0] FPUFlagsW;
//DECODE STAGE //DECODE STAGE
// top-level controller for FPU // top-level controller for FPU
@ -159,7 +157,6 @@ module fpu (
{FRegWriteD, FResultSelD, FResSelD, FIntResSelD, FrmD, FmtD, FOpCtrlD, FWriteIntD}, {FRegWriteD, FResultSelD, FResSelD, FIntResSelD, FrmD, FmtD, FOpCtrlD, FWriteIntD},
{FRegWriteE, FResultSelE, FResSelE, FIntResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE}); {FRegWriteE, FResultSelE, FResSelE, FIntResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE});
//EXECUTION STAGE //EXECUTION STAGE
// Hazard unit for FPU // Hazard unit for FPU
@ -171,11 +168,19 @@ module fpu (
mux3 #(64) fyemux(FRD2E, FPUResultW, FResM, FForwardYE, FSrcYE); mux3 #(64) fyemux(FRD2E, FPUResultW, FResM, FForwardYE, FSrcYE);
mux3 #(64) fzemux(FRD3E, FPUResultW, FResM, FForwardZE, FSrcZE); 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 // first of two-stage instance of floating-point fused multiply-add unit
fma fma (.clk, .reset, .FlushM, .StallM, 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, .XSgnE, .YSgnE, .ZSgnE, .XExpE, .YExpE, .ZExpE, .XFracE, .YFracE, .
.XSgnM, .YSgnM, .ZSgnM, .XExpM, .YExpM, .ZExpM, .XFracM, .YFracM, .ZFracM, .XNaNM, .YNaNM, .ZNaNM, .XZeroM, .YZeroM, .ZZeroM, .XInfM, .YInfM, .ZInfM, .XSNaNM, .YSNaNM, .ZSNaNM, 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, // .FSrcXE, .FSrcYE, .FSrcZE, .FSrcXM, .FSrcYM, .FSrcZM,
.FOpCtrlE(FOpCtrlE[2:0]), .FOpCtrlM(FOpCtrlM[2:0]), .FOpCtrlE(FOpCtrlE[2:0]), .FOpCtrlM(FOpCtrlM[2:0]),
.FmtE, .FmtM, .FrmM, .FMAFlgM, .FMAResM); .FmtE, .FmtM, .FrmM, .FMAFlgM, .FMAResM);
@ -196,18 +201,24 @@ module fpu (
.en(1'b1), .clear(FDivSqrtDoneE), .en(1'b1), .clear(FDivSqrtDoneE),
.reset(reset), .clk(HoldInputs)); .reset(reset), .clk(HoldInputs));
//*** add round to nearest ties to max magnitude //*** 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, fpdiv fdivsqrt (.op1(DivInput1E), .op2(DivInput2E), .done(FDivSqrtDoneE), .rm(FrmE[1:0]), .op_type(FOpCtrlE[0]),
.OvEn(1'b1), .UnEn(1'b1), .start(FDivStartE), .reset, .clk(~clk), .AS_Result(FDivResultM), .Flags(FDivSqrtFlgM)); .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, // .DivOpType(FOpCtrlE[0]), .clk(fpdivClk), .FmtE(~FmtE), .DivInput1E, .DivInput2E,
// .FrmE, .DivOvEn(1'b1), .DivUnEn(1'b1), .FDivStartE, .FDivResultM, .FDivSqrtFlgM, // .FrmE, .DivOvEn(1'b1), .DivUnEn(1'b1), .FDivStartE, .FDivResultM, .FDivSqrtFlgM,
// .FDivSqrtDoneE, .FDivBusyE, .HoldInputs, .reset); // .FDivSqrtDoneE, .FDivBusyE, .HoldInputs, .reset);
// assign FDivBusyE = 0; // assign FDivBusyE = 0;
// first of two-stage instance of floating-point add/cvt unit // first of two-stage instance of floating-point add/cvt unit
faddcvt faddcvt (.clk, .reset, .FlushM, .StallM, .FrmM, .FOpCtrlM, .FmtE, .FmtM, faddcvt faddcvt (.clk, .reset, .FlushM, .StallM, .FrmM, .FOpCtrlM, .FmtE, .FmtM,
.FSrcXE, .FSrcYE, .FOpCtrlE, .FAddResM, .FAddFlgM); .FSrcXE, .FSrcYE, .FOpCtrlE, .FAddResM, .FAddFlgM);
// first and only instance of floating-point comparator // 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 // first and only instance of floating-point sign converter
fsgn fsgn (.SgnOpCodeE(FOpCtrlE[1:0]), .XSgnE, .YSgnE, .XExpE, .XFracE, .FmtE, .SgnResE, .SgnNVE, .XExpMaxE); 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 // first and only instance of floating-point classify unit
fclassify fclassify (.XSgnE, .XFracE, .XDenormE, .XZeroE, .XNaNE, .XInfE, .XNormE, .XSNaNE, .ClassResE); 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); fcvt fcvt (.XSgnE, .XExpE, .XFracE, .XAssumed1E, .XZeroE, .XNaNE, .XInfE, .XDenormE, .BiasE, .SrcAE, .FOpCtrlE, .FmtE, .FrmE, .CvtResE, .CvtFlgE);
// output for store instructions // output for store instructions
@ -234,8 +244,6 @@ module fpu (
{XZeroE, YZeroE, ZZeroE, XInfE, YInfE, ZInfE, XNaNE, YNaNE, ZNaNE, XSNaNE, YSNaNE, ZSNaNE}, {XZeroE, YZeroE, ZZeroE, XInfE, YInfE, ZInfE, XNaNE, YNaNE, ZNaNE, XSNaNE, YSNaNE, ZSNaNE},
{XZeroM, YZeroM, ZZeroM, XInfM, YInfM, ZInfM, XNaNM, YNaNM, ZNaNM, XSNaNM, YSNaNM, ZSNaNM}); {XZeroM, YZeroM, ZZeroM, XInfM, YInfM, ZInfM, XNaNM, YNaNM, ZNaNM, XSNaNM, YSNaNM, ZSNaNM});
flopenrc #(1) EMRegCmp1(clk, reset, FlushM, ~StallM, CmpNVE, CmpNVM); flopenrc #(1) EMRegCmp1(clk, reset, FlushM, ~StallM, CmpNVE, CmpNVM);
flopenrc #(64) EMRegCmp2(clk, reset, FlushM, ~StallM, CmpResE, CmpResM); flopenrc #(64) EMRegCmp2(clk, reset, FlushM, ~StallM, CmpResE, CmpResM);
@ -266,15 +274,10 @@ module fpu (
// M/W pipe registers // M/W pipe registers
//***************** //*****************
flopenrc #(64) MWRegFma1(clk, reset, FlushW, ~StallW, FMAResM, FMAResW); flopenrc #(64) MWRegFma1(clk, reset, FlushW, ~StallW, FMAResM, FMAResW);
flopenrc #(64) MWRegDiv1(clk, reset, FlushW, ~StallW, FDivResultM, FDivResultW); flopenrc #(64) MWRegDiv1(clk, reset, FlushW, ~StallW, FDivResultM, FDivResultW);
flopenrc #(64) MWRegAdd1(clk, reset, FlushW, ~StallW, FAddResM, FAddResW); flopenrc #(64) MWRegAdd1(clk, reset, FlushW, ~StallW, FAddResM, FAddResW);
flopenrc #(64) MWRegCmp3(clk, reset, FlushW, ~StallW, CmpResM, CmpResW); flopenrc #(64) MWRegCmp3(clk, reset, FlushW, ~StallW, CmpResM, CmpResW);
flopenrc #(64) MWRegClass2(clk, reset, FlushW, ~StallW, FResM, FResW); flopenrc #(64) MWRegClass2(clk, reset, FlushW, ~StallW, FResM, FResW);
flopenrc #(6) MWCtrlReg(clk, reset, FlushW, ~StallW, flopenrc #(6) MWCtrlReg(clk, reset, FlushW, ~StallW,
{FRegWriteM, FResultSelM, FmtM, FWriteIntM}, {FRegWriteM, FResultSelM, FmtM, FWriteIntM},
{FRegWriteW, FResultSelW, FmtW, FWriteIntW}); {FRegWriteW, FResultSelW, FmtW, FWriteIntW});
@ -282,7 +285,6 @@ module fpu (
//######################################### //#########################################
// BEGIN WRITEBACK STAGE // BEGIN WRITEBACK STAGE
//######################################### //#########################################
mux2 #(64) ReadResMux({{32{1'b1}}, ReadDataW[31:0]}, {{64-`XLEN{1'b1}}, ReadDataW}, FmtW, ReadResW); 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); mux5 #(64) FPUResultMux(ReadResW, FMAResW, FAddResW, FDivResultW, FResW, FResultSelW, FPUResultW);

View File

@ -6,7 +6,7 @@ module fsm (done, load_rega, load_regb, load_regc,
input clk; input clk;
input reset; input reset;
input start; input start;
// input error; // input error;
input op_type; input op_type;
//***can use divbusy insted of holdinputs //***can use divbusy insted of holdinputs
output done; output done;
@ -476,7 +476,7 @@ module fsm (done, load_rega, load_regb, load_regc,
sel_muxa = 3'b011; sel_muxa = 3'b011;
sel_muxb = 3'b110; sel_muxb = 3'b110;
sel_muxr = 1'b1; sel_muxr = 1'b1;
NEXT_STATE = S26; NEXT_STATE = S27;
end end
S26: // done S26: // done
begin begin

View File

@ -45,6 +45,8 @@ module lsu
output logic CommittedM, output logic CommittedM,
output logic SquashSCW, output logic SquashSCW,
output logic DataMisalignedM, output logic DataMisalignedM,
output logic DCacheMiss,
output logic DCacheAccess,
// address and write data // address and write data
input logic [`XLEN-1:0] MemAdrM, input logic [`XLEN-1:0] MemAdrM,
@ -315,6 +317,8 @@ module lsu
.ReadDataM(HPTWReadPTE), .ReadDataM(HPTWReadPTE),
.DCacheStall(DCacheStall), .DCacheStall(DCacheStall),
.CommittedM(CommittedMfromDCache), .CommittedM(CommittedMfromDCache),
.DCacheMiss,
.DCacheAccess,
.ExceptionM(ExceptionM), .ExceptionM(ExceptionM),
.PendingInterruptM(PendingInterruptMtoDCache), .PendingInterruptM(PendingInterruptMtoDCache),
.DTLBMissM(DTLBMissM), .DTLBMissM(DTLBMissM),

View File

@ -34,9 +34,10 @@ module pmpadrdec (
input logic [7:0] PMPCfg, input logic [7:0] PMPCfg,
input logic [`XLEN-1:0] PMPAdr, input logic [`XLEN-1:0] PMPAdr,
input logic PAgePMPAdrIn, input logic PAgePMPAdrIn,
input logic NoLowerMatchIn, // input logic NoLowerMatchIn,
input logic FirstMatch,
output logic PAgePMPAdrOut, output logic PAgePMPAdrOut,
output logic NoLowerMatchOut, // output logic NoLowerMatchOut,
output logic Match, Active, output logic Match, Active,
output logic L, X, W, R output logic L, X, W, R
); );
@ -47,7 +48,7 @@ module pmpadrdec (
logic TORMatch, NAMatch; logic TORMatch, NAMatch;
logic PAltPMPAdr; logic PAltPMPAdr;
logic FirstMatch; // logic FirstMatch;
logic [`PA_BITS-1:0] CurrentAdrFull; logic [`PA_BITS-1:0] CurrentAdrFull;
logic [1:0] AdrMode; logic [1:0] AdrMode;
@ -69,16 +70,30 @@ module pmpadrdec (
// verilator lint_off UNOPTFLAT // verilator lint_off UNOPTFLAT
logic [`PA_BITS-1:0] Mask; logic [`PA_BITS-1:0] Mask;
genvar i; //genvar i;
// create a mask of which bits to ignore // 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[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 // *** possible experiments:
assign Mask[i] = Mask[i-1] & PMPAdr[i-3]; // NAPOT mask: 1's indicate bits to ignore /* PA < PMP addr could be in its own module,
end preeserving hierarchy so we can know if this is the culprit on the critical path
endgenerate 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 // verilator lint_on UNOPTFLAT
assign NAMatch = &((PhysicalAddress ~^ CurrentAdrFull) | Mask); assign NAMatch = &((PhysicalAddress ~^ CurrentAdrFull) | Mask);
@ -87,8 +102,6 @@ module pmpadrdec (
(AdrMode == NA4 || AdrMode == NAPOT) ? NAMatch : (AdrMode == NA4 || AdrMode == NAPOT) ? NAMatch :
0; 0;
assign FirstMatch = NoLowerMatchIn & Match;
assign NoLowerMatchOut = NoLowerMatchIn & ~Match;
assign L = PMPCfg[7] & FirstMatch; assign L = PMPCfg[7] & FirstMatch;
assign X = PMPCfg[2] & FirstMatch; assign X = PMPCfg[2] & FirstMatch;
assign W = PMPCfg[1] & FirstMatch; assign W = PMPCfg[1] & FirstMatch;

View File

@ -55,12 +55,9 @@ module pmpchecker (
// Bit i is high when the address falls in PMP region i // Bit i is high when the address falls in PMP region i
logic EnforcePMP; logic EnforcePMP;
logic [7:0] PMPCfg[`PMP_ENTRIES-1:0]; 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] Active; // PMP register i is non-null
logic [`PMP_ENTRIES-1:0] L, X, W, R; // PMP matches and has flag set 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] logic [`PMP_ENTRIES-1:0] PAgePMPAdr; // for TOR PMP matching, PhysicalAddress > PMPAdr[i]
genvar i,j; genvar i,j;
@ -70,9 +67,9 @@ module pmpchecker (
.PMPAdr(PMPADDR_ARRAY_REGW), .PMPAdr(PMPADDR_ARRAY_REGW),
.PAgePMPAdrIn({PAgePMPAdr[`PMP_ENTRIES-2:0], 1'b1}), .PAgePMPAdrIn({PAgePMPAdr[`PMP_ENTRIES-2:0], 1'b1}),
.PAgePMPAdrOut(PAgePMPAdr), .PAgePMPAdrOut(PAgePMPAdr),
.NoLowerMatchIn({NoLowerMatch[`PMP_ENTRIES-2:0], 1'b1}), .FirstMatch, .Match, .Active, .L, .X, .W, .R);
.NoLowerMatchOut(NoLowerMatch),
.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 // 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; assign EnforcePMP = (PrivilegeModeW == `M_MODE) ? |L : |Active;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////// ///////////////////////////////////////////
// tlbpriority.sv // prioritycircuit.sv
// //
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 7 April 2021 // Written: tfleming@hmc.edu & jtorrey@hmc.edu 7 April 2021
// Modified: Teo Ene 15 Apr 2021: // Modified: Teo Ene 15 Apr 2021:
@ -30,8 +30,10 @@
`include "wally-config.vh" `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 [ENTRIES-1:0] a,
input logic FirstPin,
output logic [ENTRIES-1:0] y output logic [ENTRIES-1:0] y
); );
// verilator lint_off UNOPTFLAT // verilator lint_off UNOPTFLAT
@ -40,11 +42,19 @@ module tlbpriority #(parameter ENTRIES = 8) (
// generate thermometer code mask // generate thermometer code mask
genvar i; genvar i;
generate generate
assign nolower[0] = 1; assign nolower[0] = FirstPin;
for (i=1; i<ENTRIES; i++) begin:therm for (i=1; i<ENTRIES; i++) begin:therm
assign nolower[i] = nolower[i-1] & ~a[i-1]; assign nolower[i] = nolower[i-1] & ~a[i-1];
end end
endgenerate endgenerate
// verilator lint_on UNOPTFLAT // verilator lint_on UNOPTFLAT
generate
if (FINAL_OP=="AND") begin
assign y = a & nolower; 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 endmodule

View File

@ -39,7 +39,7 @@ module tlblru #(parameter TLB_ENTRIES = 8) (
logic AllUsed; // High if the next access causes all RU bits to be 1 logic AllUsed; // High if the next access causes all RU bits to be 1
// Find the first line not recently used // 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 // Track recently used lines, updating on a CAM Hit or TLB write
assign WriteEnables = WriteLines & {(TLB_ENTRIES){TLBWrite}}; assign WriteEnables = WriteLines & {(TLB_ENTRIES){TLBWrite}};

View File

@ -46,6 +46,8 @@ module csr #(parameter
input logic RASPredPCWrongM, input logic RASPredPCWrongM,
input logic BPPredClassNonCFIWrongM, input logic BPPredClassNonCFIWrongM,
input logic [4:0] InstrClassM, input logic [4:0] InstrClassM,
input logic DCacheMiss,
input logic DCacheAccess,
input logic [1:0] NextPrivilegeModeM, PrivilegeModeW, input logic [1:0] NextPrivilegeModeM, PrivilegeModeW,
input logic [`XLEN-1:0] CauseM, NextFaultMtvalM, input logic [`XLEN-1:0] CauseM, NextFaultMtvalM,
input logic BreakpointFaultM, EcallFaultM, input logic BreakpointFaultM, EcallFaultM,

View File

@ -78,6 +78,8 @@ module csrc #(parameter
input logic RASPredPCWrongM, input logic RASPredPCWrongM,
input logic BPPredClassNonCFIWrongM, input logic BPPredClassNonCFIWrongM,
input logic [4:0] InstrClassM, input logic [4:0] InstrClassM,
input logic DCacheMiss,
input logic DCacheAccess,
input logic [11:0] CSRAdrM, input logic [11:0] CSRAdrM,
input logic [1:0] PrivilegeModeW, input logic [1:0] PrivilegeModeW,
input logic [`XLEN-1:0] CSRWriteValM, input logic [`XLEN-1:0] CSRWriteValM,
@ -143,7 +145,9 @@ module csrc #(parameter
assign CounterEvent[8] = RASPredPCWrongM & ~StallM; assign CounterEvent[8] = RASPredPCWrongM & ~StallM;
assign CounterEvent[9] = InstrClassM[3] & ~StallM; assign CounterEvent[9] = InstrClassM[3] & ~StallM;
assign CounterEvent[10] = BPPredClassNonCFIWrongM & ~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 for (i = 3; i < `COUNTERS; i = i+1) begin
assign WriteHPMCOUNTERM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERBASE + i); assign WriteHPMCOUNTERM[i] = CSRMWriteM && (CSRAdrM == MHPMCOUNTERBASE + i);

View File

@ -45,6 +45,8 @@ module privileged (
input logic RASPredPCWrongM, input logic RASPredPCWrongM,
input logic BPPredClassNonCFIWrongM, input logic BPPredClassNonCFIWrongM,
input logic [4:0] InstrClassM, input logic [4:0] InstrClassM,
input logic DCacheMiss,
input logic DCacheAccess,
input logic PrivilegedM, input logic PrivilegedM,
input logic ITLBInstrPageFaultF, DTLBLoadPageFaultM, DTLBStorePageFaultM, input logic ITLBInstrPageFaultF, DTLBLoadPageFaultM, DTLBStorePageFaultM,
input logic WalkerInstrPageFaultF, WalkerLoadPageFaultM, WalkerStorePageFaultM, input logic WalkerInstrPageFaultF, WalkerLoadPageFaultM, WalkerStorePageFaultM,

View File

@ -82,7 +82,7 @@ module clint (
always_ff @(posedge HCLK or negedge HRESETn) always_ff @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin if (~HRESETn) begin
MSIP <= 0; MSIP <= 0;
MTIMECMP <= (`XLEN)'(-1); MTIMECMP <= (64)'(0);
// MTIMECMP is not reset // MTIMECMP is not reset
end else if (memwrite) begin end else if (memwrite) begin
if (entryd == 16'h0000) MSIP <= HWDATA[0]; if (entryd == 16'h0000) MSIP <= HWDATA[0];
@ -112,7 +112,7 @@ module clint (
always_ff @(posedge HCLK or negedge HRESETn) always_ff @(posedge HCLK or negedge HRESETn)
if (~HRESETn) begin if (~HRESETn) begin
MSIP <= 0; MSIP <= 0;
MTIMECMP <= (`XLEN)'(-1); MTIMECMP <= (64)'(0);
// MTIMECMP is not reset // MTIMECMP is not reset
end else if (memwrite) begin end else if (memwrite) begin
if (entryd == 16'h0000) MSIP <= HWDATA[0]; if (entryd == 16'h0000) MSIP <= HWDATA[0];

View File

@ -164,6 +164,8 @@ module wallypipelinedhart
logic ExceptionM; logic ExceptionM;
logic PendingInterruptM; logic PendingInterruptM;
logic DCacheMiss;
logic DCacheAccess;
ifu ifu(.InstrInF(InstrRData), ifu ifu(.InstrInF(InstrRData),
@ -186,6 +188,8 @@ module wallypipelinedhart
.ExceptionM(ExceptionM), .ExceptionM(ExceptionM),
.PendingInterruptM(PendingInterruptM), .PendingInterruptM(PendingInterruptM),
.CommittedM(CommittedM), .CommittedM(CommittedM),
.DCacheMiss,
.DCacheAccess,
.SquashSCW(SquashSCW), .SquashSCW(SquashSCW),
.DataMisalignedM(DataMisalignedM), .DataMisalignedM(DataMisalignedM),
.MemAdrE(MemAdrE), .MemAdrE(MemAdrE),

View File

@ -737,12 +737,26 @@ endmodule
module riscvassertions(); module riscvassertions();
// Legal number of PMP entries are 0, 16, or 64 // Legal number of PMP entries are 0, 16, or 64
initial begin 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 (`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 (`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 end
endmodule endmodule
/* verilator lint_on STMTDLY */ /* verilator lint_on STMTDLY */
/* verilator lint_on WIDTH */ /* verilator lint_on WIDTH */

View File

@ -27,7 +27,7 @@
module testbench(); 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) 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]; logic [99:0] StartCSRexpected[63:0];
string StartCSRname[99:0]; string StartCSRname[99:0];
integer data_file_csr, scan_file_csr; integer data_file_csr, scan_file_csr;
logic IllegalInstrFaultd;
// ----------- // -----------
// Error Macro // Error Macro
@ -153,21 +154,22 @@ module testbench();
clk <= 1; # 5; clk <= 0; # 5; clk <= 1; # 5; clk <= 0; # 5;
end end
// -------------------
// Additional Hardware
// -------------------
always @(posedge clk)
IllegalInstrFaultd = dut.hart.priv.IllegalInstrFaultM;
// ------------------------------------- // -------------------------------------
// Special warnings for important faults // Special warnings for important faults
// ------------------------------------- // -------------------------------------
always @(dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW) begin always @(dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW) begin
if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 2 && instrs > 1) begin if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 2 && instrs > 1) begin
$display("!!!!!! illegal instruction !!!!!!!!!!"); // This is sometimes okay if the source code intentionally causes it.
$display("(as a reminder, MCAUSE and MEPC are set by this)"); $display("Warning: illegal instruction exception at %0t ps, InstrNum %0d, PCM %x, InstrM %s", $time, instrs, dut.hart.ifu.PCM, PCtextM);
$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
end end
if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 5 && instrs != 0) begin if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 5 && instrs != 0) begin
$display("!!!!!! illegal (physical) memory access !!!!!!!!!!"); $display("Warning: illegal physical memory access exception at %0t ps, InstrNum %0d, PCM %x, InstrM %s", $time, instrs, dut.hart.ifu.PCM, PCtextM);
$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
end end
end end
@ -185,8 +187,14 @@ module testbench();
// Hack to compensate for QEMU's incorrect MSTATUS // Hack to compensate for QEMU's incorrect MSTATUS
end else if (PCtextW.substr(0,3) == "csrr" && PCtextW.substr(10,16) == "mstatus") begin 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; force dut.hart.ieu.dp.regf.wd3 = dut.hart.ieu.dp.WriteDataW & ~64'ha00000000;
end else end else release dut.hart.ieu.dp.regf.wd3;
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
end end
@ -194,7 +202,6 @@ module testbench();
// Big Chunky Block // 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. 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; #2;
// If PCD/InstrD aren't garbage // 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 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; lastPC2 <= lastPC;
// If PCD isn't going to be flushed // If PCD isn't going to be flushed
if (~PCDwrong || lastPC == PCDexpected) begin if (~PCDwrong || lastPC == PCDexpected) begin
// Stop if we've reached the end // Stop if we've reached the end
if($feof(data_file_PCF)) begin if($feof(data_file_PCF)) begin
$display("no more PC data to read... CONGRATULATIONS!!!"); $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 // Check if PCD is going to be flushed due to a branch or jump
if (`BPRED_ENABLED) begin 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. 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 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
end end
// Check PCD, InstrD // Check PCD, InstrD
@ -309,7 +293,6 @@ module testbench();
lastPCD = dut.hart.ifu.PCD; lastPCD = dut.hart.ifu.PCD;
end end
end end
end
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
///////////////////////////// PC,Instr Checking /////////////////////////////// ///////////////////////////// PC,Instr Checking ///////////////////////////////
@ -360,9 +343,8 @@ module testbench();
end end
`SCAN_PC(data_file_PCM, scan_file_PCM, trashString, trashString, InstrMExpected, PCMexpected); `SCAN_PC(data_file_PCM, scan_file_PCM, trashString, trashString, InstrMExpected, PCMexpected);
`SCAN_PC(data_file_PCW, scan_file_PCW, trashString, trashString, InstrWExpected, PCWexpected); `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 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_PCM, scan_file_PCM, trashString, trashString, InstrMExpected, PCMexpected);
`SCAN_PC(data_file_PCW, scan_file_PCW, trashString, trashString, InstrWExpected, PCWexpected); `SCAN_PC(data_file_PCW, scan_file_PCW, trashString, trashString, InstrWExpected, PCWexpected);
end end
@ -371,6 +353,11 @@ module testbench();
`ERROR `ERROR
end end
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 end
@ -453,8 +440,7 @@ module testbench();
// Read Checker // Read Checker
// ------------ // ------------
always @(negedge clk) begin 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.StallM && ~dut.hart.FlushM && dut.hart.ieu.InstrValidM) begin
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($feof(data_file_memR)) begin if($feof(data_file_memR)) begin
$display("no more memR data to read"); $display("no more memR data to read");
`ERROR `ERROR
@ -530,39 +516,24 @@ module testbench();
// -------------- // --------------
// Checker Macros // 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 SEPCstring = "SEPC";
string SCAUSEstring = "SCAUSE"; string SCAUSEstring = "SCAUSE";
string SSTATUSstring = "SSTATUS"; string SSTATUSstring = "SSTATUS";
logic [63:0] expectedCSR;
string expectedCSRname;
`define CHECK_CSR2(CSR, PATH) \ `define CHECK_CSR2(CSR, PATH) \
logic [63:0] expected``CSR``; \
string CSR; \
string ``CSR``name = `"CSR`"; \ string ``CSR``name = `"CSR`"; \
string expected``CSR``name; \
always @(``PATH``.``CSR``_REGW) begin \ always @(``PATH``.``CSR``_REGW) begin \
if ($time > 1 && (`BUILDROOT != 1 || ``CSR``name != SSTATUSstring)) begin \ if (instrs == 0 && ~reset) 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 \
for(integer j=0; j<totalCSR; j++) begin \ for(integer j=0; j<totalCSR; j++) begin \
if(!StartCSRname[j].icompare(``CSR``name)) begin \ if(!StartCSRname[j].icompare(``CSR``name)) begin \
if(``PATH``.``CSR``_REGW != StartCSRexpected[j]) begin \ if(``PATH``.``CSR``_REGW != StartCSRexpected[j]) begin \
@ -571,6 +542,37 @@ module testbench();
end \ end \
end \ 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 \ end \
end end