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
wally-pipelined
config
buildroot
busybear
coremark-64i
coremark
coremark_bare
rv32ic
rv32icfd
rv64BP
rv64ic
rv64icfd
rv64imc
linux-testgen/testvector-generation
regression
src
cache
fpu
lsu
mmu
privileged
uncore
wally
testbench
@ -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 > {}",
|
||||
|
22
wally-pipelined/src/cache/dcache.sv
vendored
22
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,
|
||||
@ -53,7 +55,7 @@ module dcache
|
||||
input logic DTLBMissM,
|
||||
input logic CacheableM,
|
||||
input logic DTLBWriteM,
|
||||
input logic ITLBWriteF,
|
||||
input logic ITLBWriteF,
|
||||
// from ptw
|
||||
input logic SelPTW,
|
||||
input logic WalkerPageFaultM,
|
||||
@ -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);
|
||||
@ -416,7 +422,7 @@ module dcache
|
||||
if (reset) CurrState <= #1 STATE_READY;
|
||||
else CurrState <= #1 NextState;
|
||||
|
||||
|
||||
|
||||
// next state logic and some state ouputs.
|
||||
always_comb begin
|
||||
DCacheStall = 1'b0;
|
||||
@ -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,7 +480,8 @@ 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;
|
||||
SelAdrM = 1'b1;
|
||||
@ -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
|
||||
|
||||
|
||||
|
@ -25,23 +25,23 @@
|
||||
`include "wally-config.vh"
|
||||
|
||||
module fpu (
|
||||
input logic clk,
|
||||
input logic reset,
|
||||
input logic [2:0] FRM_REGW, // Rounding mode from CSR
|
||||
input logic [31:0] InstrD,
|
||||
input logic [`XLEN-1:0] ReadDataW, // Read data from memory
|
||||
input logic [`XLEN-1:0] SrcAE, // Integer input being processed
|
||||
input logic [`XLEN-1:0] SrcAM, // Integer input being written into fpreg
|
||||
input logic StallE, StallM, StallW,
|
||||
input logic FlushE, FlushM, FlushW,
|
||||
input logic [4:0] RdE, RdM, RdW,
|
||||
output logic FRegWriteM,
|
||||
output logic FStallD, // Stall the decode stage
|
||||
output logic FWriteIntE, FWriteIntM, FWriteIntW, // Write integer register enable
|
||||
output logic [`XLEN-1:0] FWriteDataE, // Data to be written to memory
|
||||
output logic [`XLEN-1:0] FIntResM,
|
||||
output logic FDivBusyE, // Is the divison/sqrt unit busy
|
||||
output logic IllegalFPUInstrD, // Is the instruction an illegal fpu instruction
|
||||
input logic clk,
|
||||
input logic reset,
|
||||
input logic [2:0] FRM_REGW, // Rounding mode from CSR
|
||||
input logic [31:0] InstrD,
|
||||
input logic [`XLEN-1:0] ReadDataW, // Read data from memory
|
||||
input logic [`XLEN-1:0] SrcAE, // Integer input being processed
|
||||
input logic [`XLEN-1:0] SrcAM, // Integer input being written into fpreg
|
||||
input logic StallE, StallM, StallW,
|
||||
input logic FlushE, FlushM, FlushW,
|
||||
input logic [4:0] RdE, RdM, RdW,
|
||||
output logic FRegWriteM,
|
||||
output logic FStallD, // Stall the decode stage
|
||||
output logic FWriteIntE, FWriteIntM, FWriteIntW, // Write integer register enable
|
||||
output logic [`XLEN-1:0] FWriteDataE, // Data to be written to memory
|
||||
output logic [`XLEN-1:0] FIntResM,
|
||||
output logic FDivBusyE, // Is the divison/sqrt unit busy
|
||||
output logic IllegalFPUInstrD, // Is the instruction an illegal fpu instruction
|
||||
output logic [4:0] SetFflagsM); // FPU result
|
||||
// *** change FMA to do 16 - 32 - 64 - 128 FEXPBITS
|
||||
// *** folder at same level of src for tests fpu tests
|
||||
@ -50,254 +50,256 @@ module fpu (
|
||||
generate
|
||||
if (`F_SUPPORTED | `D_SUPPORTED) begin
|
||||
// control logic signal instantiation
|
||||
logic FRegWriteD, FRegWriteE, FRegWriteW; // FP register write enable
|
||||
logic [2:0] FrmD, FrmE, FrmM; // FP rounding mode
|
||||
logic FmtD, FmtE, FmtM, FmtW; // FP precision 0-single 1-double
|
||||
logic FDivStartD, FDivStartE; // Start division
|
||||
logic FWriteIntD; // Write to integer register
|
||||
logic [1:0] FForwardXE, FForwardYE, FForwardZE; // Input3 forwarding mux control signal
|
||||
logic [2:0] FResultSelD, FResultSelE, FResultSelM, FResultSelW; // Select FP result
|
||||
logic [3:0] FOpCtrlD, FOpCtrlE, FOpCtrlM; // Select which opperation to do in each component
|
||||
logic [1:0] FResSelD, FResSelE, FResSelM;
|
||||
logic [1:0] FIntResSelD, FIntResSelE, FIntResSelM;
|
||||
logic [4:0] Adr1E, Adr2E, Adr3E;
|
||||
|
||||
// regfile signals
|
||||
logic [63:0] FRD1D, FRD2D, FRD3D; // Read Data from FP register - decode stage
|
||||
logic [63:0] FRD1E, FRD2E, FRD3E; // Read Data from FP register - execute stage
|
||||
logic [`XLEN-1:0] FSrcXMAligned;
|
||||
logic [63:0] FSrcXE, FSrcXM; // Input 1 to the various units (after forwarding)
|
||||
logic [63:0] FSrcYE; // Input 2 to the various units (after forwarding)
|
||||
logic [63:0] FSrcZE; // Input 3 to the various units (after forwarding)
|
||||
|
||||
// unpacking signals
|
||||
logic XSgnE, YSgnE, ZSgnE;
|
||||
logic [10:0] XExpE, YExpE, ZExpE;
|
||||
logic [51:0] XFracE, YFracE, ZFracE;
|
||||
logic XAssumed1E, YAssumed1E, ZAssumed1E;
|
||||
logic XNaNE, YNaNE, ZNaNE;
|
||||
logic XSNaNE, YSNaNE, ZSNaNE;
|
||||
logic XDenormE, YDenormE, ZDenormE;
|
||||
logic XZeroE, YZeroE, ZZeroE;
|
||||
logic [10:0] BiasE;
|
||||
logic XInfE, YInfE, ZInfE;
|
||||
logic XExpMaxE;
|
||||
logic XNormE;
|
||||
|
||||
logic XSgnM, YSgnM, ZSgnM;
|
||||
logic [10:0] XExpM, YExpM, ZExpM;
|
||||
logic [51:0] XFracM, YFracM, ZFracM;
|
||||
logic XNaNM, YNaNM, ZNaNM;
|
||||
logic XSNaNM, YSNaNM, ZSNaNM;
|
||||
logic XZeroM, YZeroM, ZZeroM;
|
||||
logic XInfM, YInfM, ZInfM;
|
||||
|
||||
// div/sqrt signals
|
||||
logic [63:0] FDivResultM, FDivResultW;
|
||||
logic [4:0] FDivSqrtFlgM, FDivSqrtFlgW;
|
||||
logic FDivSqrtDoneE;
|
||||
logic [63:0] DivInput1E, DivInput2E;
|
||||
logic HoldInputs; // keep forwarded inputs arround durring division
|
||||
|
||||
//fpu signals
|
||||
logic [63:0] FMAResM, FMAResW;
|
||||
logic [4:0] FMAFlgM, FMAFlgW;
|
||||
|
||||
|
||||
logic [63:0] ReadResW;
|
||||
|
||||
// add/cvt signals
|
||||
logic [63:0] FAddResM, FAddResW;
|
||||
logic [4:0] FAddFlgM, FAddFlgW;
|
||||
logic [63:0] CvtResE, CvtResM;
|
||||
logic [4:0] CvtFlgE, CvtFlgM;
|
||||
|
||||
// cmp signals
|
||||
logic CmpNVE, CmpNVM, CmpNVW;
|
||||
logic [63:0] CmpResE, CmpResM, CmpResW;
|
||||
|
||||
// fsgn signals
|
||||
logic [63:0] SgnResE, SgnResM;
|
||||
logic SgnNVE, SgnNVM, SgnNVW;
|
||||
logic [63:0] FResM, FResW;
|
||||
logic [4:0] FFlgM, FFlgW;
|
||||
|
||||
// instantiation of W stage regfile signals
|
||||
logic [63:0] AlignedSrcAM;
|
||||
|
||||
// classify signals
|
||||
logic [63:0] ClassResE, ClassResM;
|
||||
|
||||
// 64-bit FPU result
|
||||
logic [63:0] FPUResultW;
|
||||
logic [4:0] FPUFlagsW;
|
||||
|
||||
|
||||
//DECODE STAGE
|
||||
|
||||
// top-level controller for FPU
|
||||
fctrl fctrl (.Funct7D(InstrD[31:25]), .OpD(InstrD[6:0]), .Rs2D(InstrD[24:20]), .Funct3D(InstrD[14:12]),
|
||||
.FRM_REGW, .IllegalFPUInstrD, .FRegWriteD, .FDivStartD, .FResultSelD, .FOpCtrlD, .FResSelD,
|
||||
.FIntResSelD, .FmtD, .FrmD, .FWriteIntD);
|
||||
|
||||
// regfile instantiation
|
||||
fregfile fregfile (clk, reset, FRegWriteW,
|
||||
InstrD[19:15], InstrD[24:20], InstrD[31:27], RdW,
|
||||
FPUResultW,
|
||||
FRD1D, FRD2D, FRD3D);
|
||||
|
||||
//*****************
|
||||
// D/E pipe registers
|
||||
//*****************
|
||||
flopenrc #(64) DEReg1(clk, reset, FlushE, ~StallE, FRD1D, FRD1E);
|
||||
flopenrc #(64) DEReg2(clk, reset, FlushE, ~StallE, FRD2D, FRD2E);
|
||||
flopenrc #(64) DEReg3(clk, reset, FlushE, ~StallE, FRD3D, FRD3E);
|
||||
flopenrc #(1) DECtrlRegE1(clk, reset, FlushE, ~StallE, FDivStartD, FDivStartE);
|
||||
flopenrc #(15) DECtrlRegE2(clk, reset, FlushE, ~StallE, {InstrD[19:15], InstrD[24:20], InstrD[31:27]},
|
||||
{Adr1E, Adr2E, Adr3E});
|
||||
flopenrc #(17) DECtrlReg3(clk, reset, FlushE, ~StallE,
|
||||
{FRegWriteD, FResultSelD, FResSelD, FIntResSelD, FrmD, FmtD, FOpCtrlD, FWriteIntD},
|
||||
{FRegWriteE, FResultSelE, FResSelE, FIntResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE});
|
||||
|
||||
|
||||
//EXECUTION STAGE
|
||||
|
||||
// Hazard unit for FPU
|
||||
fhazard fhazard(.Adr1E, .Adr2E, .Adr3E, .FRegWriteM, .FRegWriteW, .RdM, .RdW, .FResultSelM, .FStallD,
|
||||
logic FRegWriteD, FRegWriteE, FRegWriteW; // FP register write enable
|
||||
logic [2:0] FrmD, FrmE, FrmM; // FP rounding mode
|
||||
logic FmtD, FmtE, FmtM, FmtW; // FP precision 0-single 1-double
|
||||
logic FDivStartD, FDivStartE; // Start division
|
||||
logic FWriteIntD; // Write to integer register
|
||||
logic [1:0] FForwardXE, FForwardYE, FForwardZE; // Input3 forwarding mux control signal
|
||||
logic [2:0] FResultSelD, FResultSelE, FResultSelM, FResultSelW; // Select FP result
|
||||
logic [3:0] FOpCtrlD, FOpCtrlE, FOpCtrlM; // Select which opperation to do in each component
|
||||
logic [1:0] FResSelD, FResSelE, FResSelM;
|
||||
logic [1:0] FIntResSelD, FIntResSelE, FIntResSelM;
|
||||
logic [4:0] Adr1E, Adr2E, Adr3E;
|
||||
|
||||
// regfile signals
|
||||
logic [63:0] FRD1D, FRD2D, FRD3D; // Read Data from FP register - decode stage
|
||||
logic [63:0] FRD1E, FRD2E, FRD3E; // Read Data from FP register - execute stage
|
||||
logic [`XLEN-1:0] FSrcXMAligned;
|
||||
logic [63:0] FSrcXE, FSrcXM; // Input 1 to the various units (after forwarding)
|
||||
logic [63:0] FSrcYE; // Input 2 to the various units (after forwarding)
|
||||
logic [63:0] FSrcZE; // Input 3 to the various units (after forwarding)
|
||||
|
||||
// unpacking signals
|
||||
logic XSgnE, YSgnE, ZSgnE;
|
||||
logic [10:0] XExpE, YExpE, ZExpE;
|
||||
logic [51:0] XFracE, YFracE, ZFracE;
|
||||
logic XAssumed1E, YAssumed1E, ZAssumed1E;
|
||||
logic XNaNE, YNaNE, ZNaNE;
|
||||
logic XSNaNE, YSNaNE, ZSNaNE;
|
||||
logic XDenormE, YDenormE, ZDenormE;
|
||||
logic XZeroE, YZeroE, ZZeroE;
|
||||
logic [10:0] BiasE;
|
||||
logic XInfE, YInfE, ZInfE;
|
||||
logic XExpMaxE;
|
||||
logic XNormE;
|
||||
|
||||
logic XSgnM, YSgnM, ZSgnM;
|
||||
logic [10:0] XExpM, YExpM, ZExpM;
|
||||
logic [51:0] XFracM, YFracM, ZFracM;
|
||||
logic XNaNM, YNaNM, ZNaNM;
|
||||
logic XSNaNM, YSNaNM, ZSNaNM;
|
||||
logic XZeroM, YZeroM, ZZeroM;
|
||||
logic XInfM, YInfM, ZInfM;
|
||||
|
||||
// div/sqrt signals
|
||||
logic [63:0] FDivResultM, FDivResultW;
|
||||
logic [4:0] FDivSqrtFlgM, FDivSqrtFlgW;
|
||||
logic FDivSqrtDoneE;
|
||||
logic [63:0] DivInput1E, DivInput2E;
|
||||
logic HoldInputs; // keep forwarded inputs arround durring division
|
||||
|
||||
//fpu signals
|
||||
logic [63:0] FMAResM, FMAResW;
|
||||
logic [4:0] FMAFlgM, FMAFlgW;
|
||||
|
||||
logic [63:0] ReadResW;
|
||||
|
||||
// add/cvt signals
|
||||
logic [63:0] FAddResM, FAddResW;
|
||||
logic [4:0] FAddFlgM, FAddFlgW;
|
||||
logic [63:0] CvtResE, CvtResM;
|
||||
logic [4:0] CvtFlgE, CvtFlgM;
|
||||
|
||||
// cmp signals
|
||||
logic CmpNVE, CmpNVM, CmpNVW;
|
||||
logic [63:0] CmpResE, CmpResM, CmpResW;
|
||||
|
||||
// fsgn signals
|
||||
logic [63:0] SgnResE, SgnResM;
|
||||
logic SgnNVE, SgnNVM, SgnNVW;
|
||||
logic [63:0] FResM, FResW;
|
||||
logic [4:0] FFlgM, FFlgW;
|
||||
|
||||
// instantiation of W stage regfile signals
|
||||
logic [63:0] AlignedSrcAM;
|
||||
|
||||
// classify signals
|
||||
logic [63:0] ClassResE, ClassResM;
|
||||
|
||||
// 64-bit FPU result
|
||||
logic [63:0] FPUResultW;
|
||||
logic [4:0] FPUFlagsW;
|
||||
|
||||
//DECODE STAGE
|
||||
|
||||
// top-level controller for FPU
|
||||
fctrl fctrl (.Funct7D(InstrD[31:25]), .OpD(InstrD[6:0]), .Rs2D(InstrD[24:20]), .Funct3D(InstrD[14:12]),
|
||||
.FRM_REGW, .IllegalFPUInstrD, .FRegWriteD, .FDivStartD, .FResultSelD, .FOpCtrlD, .FResSelD,
|
||||
.FIntResSelD, .FmtD, .FrmD, .FWriteIntD);
|
||||
|
||||
// regfile instantiation
|
||||
fregfile fregfile (clk, reset, FRegWriteW,
|
||||
InstrD[19:15], InstrD[24:20], InstrD[31:27], RdW,
|
||||
FPUResultW,
|
||||
FRD1D, FRD2D, FRD3D);
|
||||
|
||||
//*****************
|
||||
// D/E pipe registers
|
||||
//*****************
|
||||
flopenrc #(64) DEReg1(clk, reset, FlushE, ~StallE, FRD1D, FRD1E);
|
||||
flopenrc #(64) DEReg2(clk, reset, FlushE, ~StallE, FRD2D, FRD2E);
|
||||
flopenrc #(64) DEReg3(clk, reset, FlushE, ~StallE, FRD3D, FRD3E);
|
||||
flopenrc #(1) DECtrlRegE1(clk, reset, FlushE, ~StallE, FDivStartD, FDivStartE);
|
||||
flopenrc #(15) DECtrlRegE2(clk, reset, FlushE, ~StallE, {InstrD[19:15], InstrD[24:20], InstrD[31:27]},
|
||||
{Adr1E, Adr2E, Adr3E});
|
||||
flopenrc #(17) DECtrlReg3(clk, reset, FlushE, ~StallE,
|
||||
{FRegWriteD, FResultSelD, FResSelD, FIntResSelD, FrmD, FmtD, FOpCtrlD, FWriteIntD},
|
||||
{FRegWriteE, FResultSelE, FResSelE, FIntResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE});
|
||||
|
||||
//EXECUTION STAGE
|
||||
|
||||
// Hazard unit for FPU
|
||||
fhazard fhazard(.Adr1E, .Adr2E, .Adr3E, .FRegWriteM, .FRegWriteW, .RdM, .RdW, .FResultSelM, .FStallD,
|
||||
.FForwardXE, .FForwardYE, .FForwardZE);
|
||||
|
||||
// forwarding muxs
|
||||
mux3 #(64) fxemux(FRD1E, FPUResultW, FResM, FForwardXE, FSrcXE);
|
||||
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);
|
||||
|
||||
// forwarding muxs
|
||||
mux3 #(64) fxemux(FRD1E, FPUResultW, FResM, FForwardXE, FSrcXE);
|
||||
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);
|
||||
// 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,
|
||||
// .FSrcXE, .FSrcYE, .FSrcZE, .FSrcXM, .FSrcYM, .FSrcZM,
|
||||
.FOpCtrlE(FOpCtrlE[2:0]), .FOpCtrlM(FOpCtrlM[2:0]),
|
||||
.FmtE, .FmtM, .FrmM, .FMAFlgM, .FMAResM);
|
||||
|
||||
// first and only instance of floating-point divider
|
||||
logic fpdivClk;
|
||||
|
||||
clockgater fpdivclkg(.E(FDivStartE),
|
||||
.SE(1'b0),
|
||||
.CLK(clk),
|
||||
.ECLK(fpdivClk));
|
||||
|
||||
// capture the inputs for div/sqrt
|
||||
flopenrc #(64) reg_input1 (.d(FSrcXE), .q(DivInput1E),
|
||||
.en(1'b1), .clear(FDivSqrtDoneE),
|
||||
.reset(reset), .clk(HoldInputs));
|
||||
flopenrc #(64) reg_input2 (.d(FSrcYE), .q(DivInput2E),
|
||||
.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));
|
||||
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,
|
||||
// .FSrcXE, .FSrcYE, .FSrcZE, .FSrcXM, .FSrcYM, .FSrcZM,
|
||||
.FOpCtrlE(FOpCtrlE[2:0]), .FOpCtrlM(FOpCtrlM[2:0]),
|
||||
.FmtE, .FmtM, .FrmM, .FMAFlgM, .FMAResM);
|
||||
|
||||
// first and only instance of floating-point divider
|
||||
logic fpdivClk;
|
||||
|
||||
clockgater fpdivclkg(.E(FDivStartE),
|
||||
.SE(1'b0),
|
||||
.CLK(clk),
|
||||
.ECLK(fpdivClk));
|
||||
|
||||
// capture the inputs for div/sqrt
|
||||
flopenrc #(64) reg_input1 (.d(FSrcXE), .q(DivInput1E),
|
||||
.en(1'b1), .clear(FDivSqrtDoneE),
|
||||
.reset(reset), .clk(HoldInputs));
|
||||
flopenrc #(64) reg_input2 (.d(FSrcYE), .q(DivInput2E),
|
||||
.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));
|
||||
|
||||
// .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);
|
||||
|
||||
// first and only instance of floating-point sign converter
|
||||
fsgn fsgn (.SgnOpCodeE(FOpCtrlE[1:0]), .XSgnE, .YSgnE, .XExpE, .XFracE, .FmtE, .SgnResE, .SgnNVE, .XExpMaxE);
|
||||
|
||||
// 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
|
||||
assign FWriteDataE = FSrcYE[`XLEN-1:0];
|
||||
|
||||
//*****************
|
||||
// E/M pipe registers
|
||||
//*****************
|
||||
flopenrc #(64) EMFpReg1(clk, reset, FlushM, ~StallM, FSrcXE, FSrcXM);
|
||||
// flopenrc #(64) EMFpReg2(clk, reset, FlushM, ~StallM, FSrcYE, FSrcYM);
|
||||
// flopenrc #(64) EMFpReg3(clk, reset, FlushM, ~StallM, FSrcZE, FSrcZM);
|
||||
flopenrc #(64) EMFpReg4(clk, reset, FlushM, ~StallM, {XSgnE,XExpE,XFracE}, {XSgnM,XExpM,XFracM});
|
||||
flopenrc #(64) EMFpReg5(clk, reset, FlushM, ~StallM, {YSgnE,YExpE,YFracE}, {YSgnM,YExpM,YFracM});
|
||||
flopenrc #(64) EMFpReg6(clk, reset, FlushM, ~StallM, {ZSgnE,ZExpE,ZFracE}, {ZSgnM,ZExpM,ZFracM});
|
||||
flopenrc #(12) EMFpReg7(clk, reset, FlushM, ~StallM,
|
||||
{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);
|
||||
|
||||
flopenrc #(64) EMRegSgn1(clk, reset, FlushM, ~StallM, SgnResE, SgnResM);
|
||||
flopenrc #(1) EMRegSgn2(clk, reset, FlushM, ~StallM, SgnNVE, SgnNVM);
|
||||
|
||||
flopenrc #(64) EMRegCvt1(clk, reset, FlushM, ~StallM, CvtResE, CvtResM);
|
||||
flopenrc #(5) EMRegCvt2(clk, reset, FlushM, ~StallM, CvtFlgE, CvtFlgM);
|
||||
|
||||
flopenrc #(17) EMCtrlReg(clk, reset, FlushM, ~StallM,
|
||||
{FRegWriteE, FResultSelE, FResSelE, FIntResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE},
|
||||
{FRegWriteM, FResultSelM, FResSelM, FIntResSelM, FrmM, FmtM, FOpCtrlM, FWriteIntM});
|
||||
|
||||
flopenrc #(64) EMRegClass(clk, reset, FlushM, ~StallM, ClassResE, ClassResM);
|
||||
|
||||
//BEGIN MEMORY STAGE
|
||||
mux4 #(64) FResMux(AlignedSrcAM, SgnResM, CmpResM, CvtResM, FResSelM, FResM);
|
||||
mux4 #(5) FFlgMux(5'b0, {4'b0, SgnNVM}, {4'b0, CmpNVM}, CvtFlgM, FResSelM, FFlgM);
|
||||
|
||||
// mux2 #(`XLEN) FSrcXAlignedMux({{`XLEN-32{1'b0}}, FSrcXM[63:32]}, FSrcXM[63:64-`XLEN], FmtM, FSrcXMAligned);
|
||||
mux4 #(`XLEN) IntResMux(CmpResM[`XLEN-1:0], FSrcXM[`XLEN-1:0], ClassResM[`XLEN-1:0], CvtResM[`XLEN-1:0], FIntResSelM, FIntResM);
|
||||
|
||||
// Align SrcA to MSB when single precicion
|
||||
mux2 #(64) SrcAMux({{32{1'b1}}, SrcAM[31:0]}, {{64-`XLEN{1'b1}}, SrcAM}, FmtM, AlignedSrcAM);
|
||||
mux5 #(5) FPUFlgMux(5'b0, FMAFlgM, FAddFlgM, FDivSqrtFlgM, FFlgM, FResultSelW, SetFflagsM);
|
||||
|
||||
//*****************
|
||||
// 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});
|
||||
|
||||
//#########################################
|
||||
// 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);
|
||||
|
||||
|
||||
end else begin // no F_SUPPORTED; tie outputs low
|
||||
assign FStallD = 0;
|
||||
assign FWriteIntE = 0;
|
||||
assign FWriteIntM = 0;
|
||||
assign FWriteIntW = 0;
|
||||
assign FWriteDataE = 0;
|
||||
assign FIntResM = 0;
|
||||
assign FDivBusyE = 0;
|
||||
assign IllegalFPUInstrD = 1;
|
||||
assign SetFflagsM = 0;
|
||||
end
|
||||
// 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);
|
||||
|
||||
// first and only instance of floating-point sign converter
|
||||
fsgn fsgn (.SgnOpCodeE(FOpCtrlE[1:0]), .XSgnE, .YSgnE, .XExpE, .XFracE, .FmtE, .SgnResE, .SgnNVE, .XExpMaxE);
|
||||
|
||||
// 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
|
||||
assign FWriteDataE = FSrcYE[`XLEN-1:0];
|
||||
|
||||
//*****************
|
||||
// E/M pipe registers
|
||||
//*****************
|
||||
flopenrc #(64) EMFpReg1(clk, reset, FlushM, ~StallM, FSrcXE, FSrcXM);
|
||||
// flopenrc #(64) EMFpReg2(clk, reset, FlushM, ~StallM, FSrcYE, FSrcYM);
|
||||
// flopenrc #(64) EMFpReg3(clk, reset, FlushM, ~StallM, FSrcZE, FSrcZM);
|
||||
flopenrc #(64) EMFpReg4(clk, reset, FlushM, ~StallM, {XSgnE,XExpE,XFracE}, {XSgnM,XExpM,XFracM});
|
||||
flopenrc #(64) EMFpReg5(clk, reset, FlushM, ~StallM, {YSgnE,YExpE,YFracE}, {YSgnM,YExpM,YFracM});
|
||||
flopenrc #(64) EMFpReg6(clk, reset, FlushM, ~StallM, {ZSgnE,ZExpE,ZFracE}, {ZSgnM,ZExpM,ZFracM});
|
||||
flopenrc #(12) EMFpReg7(clk, reset, FlushM, ~StallM,
|
||||
{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);
|
||||
|
||||
flopenrc #(64) EMRegSgn1(clk, reset, FlushM, ~StallM, SgnResE, SgnResM);
|
||||
flopenrc #(1) EMRegSgn2(clk, reset, FlushM, ~StallM, SgnNVE, SgnNVM);
|
||||
|
||||
flopenrc #(64) EMRegCvt1(clk, reset, FlushM, ~StallM, CvtResE, CvtResM);
|
||||
flopenrc #(5) EMRegCvt2(clk, reset, FlushM, ~StallM, CvtFlgE, CvtFlgM);
|
||||
|
||||
flopenrc #(17) EMCtrlReg(clk, reset, FlushM, ~StallM,
|
||||
{FRegWriteE, FResultSelE, FResSelE, FIntResSelE, FrmE, FmtE, FOpCtrlE, FWriteIntE},
|
||||
{FRegWriteM, FResultSelM, FResSelM, FIntResSelM, FrmM, FmtM, FOpCtrlM, FWriteIntM});
|
||||
|
||||
flopenrc #(64) EMRegClass(clk, reset, FlushM, ~StallM, ClassResE, ClassResM);
|
||||
|
||||
//BEGIN MEMORY STAGE
|
||||
mux4 #(64) FResMux(AlignedSrcAM, SgnResM, CmpResM, CvtResM, FResSelM, FResM);
|
||||
mux4 #(5) FFlgMux(5'b0, {4'b0, SgnNVM}, {4'b0, CmpNVM}, CvtFlgM, FResSelM, FFlgM);
|
||||
|
||||
// mux2 #(`XLEN) FSrcXAlignedMux({{`XLEN-32{1'b0}}, FSrcXM[63:32]}, FSrcXM[63:64-`XLEN], FmtM, FSrcXMAligned);
|
||||
mux4 #(`XLEN) IntResMux(CmpResM[`XLEN-1:0], FSrcXM[`XLEN-1:0], ClassResM[`XLEN-1:0], CvtResM[`XLEN-1:0], FIntResSelM, FIntResM);
|
||||
|
||||
// Align SrcA to MSB when single precicion
|
||||
mux2 #(64) SrcAMux({{32{1'b1}}, SrcAM[31:0]}, {{64-`XLEN{1'b1}}, SrcAM}, FmtM, AlignedSrcAM);
|
||||
mux5 #(5) FPUFlgMux(5'b0, FMAFlgM, FAddFlgM, FDivSqrtFlgM, FFlgM, FResultSelW, SetFflagsM);
|
||||
|
||||
//*****************
|
||||
// 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});
|
||||
|
||||
//#########################################
|
||||
// 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);
|
||||
|
||||
|
||||
end else begin // no F_SUPPORTED; tie outputs low
|
||||
assign FStallD = 0;
|
||||
assign FWriteIntE = 0;
|
||||
assign FWriteIntM = 0;
|
||||
assign FWriteIntW = 0;
|
||||
assign FWriteDataE = 0;
|
||||
assign FIntResM = 0;
|
||||
assign FDivBusyE = 0;
|
||||
assign IllegalFPUInstrD = 1;
|
||||
assign SetFflagsM = 0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
endmodule // fpu
|
||||
|
@ -6,7 +6,7 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
input clk;
|
||||
input reset;
|
||||
input start;
|
||||
// input error;
|
||||
// input error;
|
||||
input op_type;
|
||||
//***can use divbusy insted of holdinputs
|
||||
output done;
|
||||
@ -113,8 +113,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S1:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -129,8 +129,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S2: // iteration 1
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b1;
|
||||
load_regc = 1'b0;
|
||||
@ -145,8 +145,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S3:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -161,8 +161,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S4: // iteration 2
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b1;
|
||||
load_regc = 1'b0;
|
||||
@ -177,8 +177,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S5:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -193,8 +193,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S6: // iteration 3
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b1;
|
||||
load_regc = 1'b0;
|
||||
@ -209,8 +209,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S7:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -225,8 +225,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S8: // q,qm,qp
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -241,8 +241,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S9: // rem
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -257,8 +257,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S10: // done
|
||||
begin
|
||||
done = 1'b1;
|
||||
divBusy = 1'b0;
|
||||
holdInputs = 1'b0;
|
||||
divBusy = 1'b0;
|
||||
holdInputs = 1'b0;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -273,8 +273,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S13: // start of sqrt path
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -289,8 +289,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S14:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -305,8 +305,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S15: // iteration 1
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b1;
|
||||
load_regc = 1'b0;
|
||||
@ -321,8 +321,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S16:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -337,8 +337,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S17:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -353,8 +353,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S18: // iteration 2
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b1;
|
||||
load_regc = 1'b0;
|
||||
@ -369,8 +369,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S19:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -385,8 +385,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S20:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -401,8 +401,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S21: // iteration 3
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b1;
|
||||
load_regc = 1'b0;
|
||||
@ -417,8 +417,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S22:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -433,8 +433,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S23:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b1;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b1;
|
||||
@ -449,8 +449,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S24: // q,qm,qp
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -465,8 +465,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
S25: // rem
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
divBusy = 1'b1;
|
||||
holdInputs = 1'b1;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -476,13 +476,13 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
sel_muxa = 3'b011;
|
||||
sel_muxb = 3'b110;
|
||||
sel_muxr = 1'b1;
|
||||
NEXT_STATE = S26;
|
||||
end
|
||||
NEXT_STATE = S27;
|
||||
end
|
||||
S26: // done
|
||||
begin
|
||||
done = 1'b1;
|
||||
divBusy = 1'b0;
|
||||
holdInputs = 1'b0;
|
||||
divBusy = 1'b0;
|
||||
holdInputs = 1'b0;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
@ -497,8 +497,8 @@ module fsm (done, load_rega, load_regb, load_regc,
|
||||
default:
|
||||
begin
|
||||
done = 1'b0;
|
||||
divBusy = 1'b0;
|
||||
holdInputs = 1'b0;
|
||||
divBusy = 1'b0;
|
||||
holdInputs = 1'b0;
|
||||
load_rega = 1'b0;
|
||||
load_regb = 1'b0;
|
||||
load_regc = 1'b0;
|
||||
|
@ -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
|
||||
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
|
||||
// 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;
|
||||
|
||||
// *** 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
|
||||
assign y = a & nolower;
|
||||
|
||||
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);
|
||||
@ -509,4 +513,4 @@ module csrc #(parameter
|
||||
end // end for else
|
||||
endgenerate
|
||||
endmodule
|
||||
*/
|
||||
*/
|
||||
|
@ -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),
|
||||
@ -185,7 +187,9 @@ module wallypipelinedhart
|
||||
.AtomicM(AtomicM),
|
||||
.ExceptionM(ExceptionM),
|
||||
.PendingInterruptM(PendingInterruptM),
|
||||
.CommittedM(CommittedM),
|
||||
.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,120 +202,95 @@ 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
|
||||
// If Wally's PCD has updated
|
||||
if (dut.hart.ifu.PCD !== lastPCD) begin
|
||||
lastInstrDExpected = InstrDExpected;
|
||||
lastPC <= dut.hart.ifu.PCD;
|
||||
lastPC2 <= lastPC;
|
||||
// If PCD isn't going to be flushed
|
||||
if (~PCDwrong || lastPC == PCDexpected) begin
|
||||
#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
|
||||
// If Wally's PCD has updated
|
||||
if (dut.hart.ifu.PCD !== lastPCD) begin
|
||||
lastInstrDExpected = InstrDExpected;
|
||||
lastPC <= dut.hart.ifu.PCD;
|
||||
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!!!");
|
||||
`ERROR
|
||||
end
|
||||
|
||||
// Stop if we've reached the end
|
||||
if($feof(data_file_PCF)) begin
|
||||
$display("no more PC data to read... CONGRATULATIONS!!!");
|
||||
`ERROR
|
||||
end
|
||||
// Increment PC
|
||||
`SCAN_PC(data_file_PCF, scan_file_PCF, PCtextF, PCtextF2, InstrFExpected, PCFexpected);
|
||||
`SCAN_PC(data_file_PCD, scan_file_PCD, PCtextD, PCtextD2, InstrDExpected, PCDexpected);
|
||||
|
||||
// Increment PC
|
||||
`SCAN_PC(data_file_PCF, scan_file_PCF, PCtextF, PCtextF2, InstrFExpected, PCFexpected);
|
||||
`SCAN_PC(data_file_PCD, scan_file_PCD, PCtextD, PCtextD2, InstrDExpected, PCDexpected);
|
||||
|
||||
// NOP out certain instructions
|
||||
if(dut.hart.ifu.PCD===PCDexpected) begin
|
||||
if((dut.hart.ifu.PCD == 32'h80001dc6) || // for now, NOP out any stores to PLIC
|
||||
(dut.hart.ifu.PCD == 32'h80001de0) ||
|
||||
(dut.hart.ifu.PCD == 32'h80001de2)) begin
|
||||
$display("warning: NOPing out %s at PCD=%0x, instr %0d, time %0t", PCtextD, dut.hart.ifu.PCD, instrs, $time);
|
||||
force InstrDExpected = 32'b0010011;
|
||||
force dut.hart.ifu.InstrRawD = 32'b0010011;
|
||||
while (clk != 0) #1;
|
||||
while (clk != 1) #1;
|
||||
release dut.hart.ifu.InstrRawD;
|
||||
release InstrDExpected;
|
||||
warningCount += 1;
|
||||
forcedInstr = 1;
|
||||
end else begin
|
||||
forcedInstr = 0;
|
||||
end
|
||||
end
|
||||
|
||||
// Increment instruction count
|
||||
if (instrs <= 10 || (instrs <= 100 && instrs % 10 == 0) ||
|
||||
(instrs <= 1000 && instrs % 100 == 0) || (instrs <= 10000 && instrs % 1000 == 0) ||
|
||||
(instrs <= 100000 && instrs % 10000 == 0) || (instrs % 100000 == 0)) begin
|
||||
$display("loaded %0d instructions", instrs);
|
||||
end
|
||||
instrs += 1;
|
||||
|
||||
// Stop before bugs so "do" file can turn on waves
|
||||
if (instrs == waveOnICount) begin
|
||||
$display("turning on waves at %0d instructions", instrs);
|
||||
$stop;
|
||||
end else if (instrs == stopICount && stopICount != 0) begin
|
||||
$display("Ending sim at %0d instructions (set stopICount to 0 to let the sim go on)", instrs);
|
||||
$stop;
|
||||
end
|
||||
|
||||
// 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
|
||||
end
|
||||
|
||||
// Check PCD, InstrD
|
||||
if (~PCDwrong && ~(dut.hart.ifu.PCD === PCDexpected)) begin
|
||||
$display("%0t ps, instr %0d: PC does not equal PC expected: %x, %x", $time, instrs, dut.hart.ifu.PCD, PCDexpected);
|
||||
`ERROR
|
||||
end
|
||||
InstrMask = InstrDExpected[1:0] == 2'b11 ? 32'hFFFFFFFF : 32'h0000FFFF;
|
||||
if ((~forcedInstr) && (~PCDwrong) && ((InstrMask & dut.hart.ifu.InstrRawD) !== (InstrMask & InstrDExpected))) begin
|
||||
$display("%0t ps, PCD %x, instr %0d: InstrD %x %s does not equal InstrDExpected %x %s", $time, dut.hart.ifu.PCD, instrs, dut.hart.ifu.InstrRawD, InstrDName, InstrDExpected, PCtextD);
|
||||
`ERROR
|
||||
end
|
||||
|
||||
// Repeated instruction means QEMU had an interrupt which we need to spoof
|
||||
if (PCFexpected == PCDexpected) begin
|
||||
$display("Note at %0t ps, PCM %x %s, instr %0d: spoofing an interrupt", $time, dut.hart.ifu.PCM, PCtextM, instrs);
|
||||
// Increment file pointers past the repeated instruction.
|
||||
`SCAN_PC(data_file_PCF, scan_file_PCF, PCtextF, PCtextF2, InstrFExpected, PCFexpected);
|
||||
`SCAN_PC(data_file_PCD, scan_file_PCD, PCtextD, PCtextD2, InstrDExpected, PCDexpected);
|
||||
scan_file_memR = $fscanf(data_file_memR, "%x\n", readAdrExpected);
|
||||
scan_file_memR = $fscanf(data_file_memR, "%x\n", readDataExpected);
|
||||
// Next force a timer interrupt (*** this may later need generalizing)
|
||||
force dut.uncore.genblk1.clint.MTIME = dut.uncore.genblk1.clint.MTIMECMP + 1;
|
||||
// NOP out certain instructions
|
||||
if(dut.hart.ifu.PCD===PCDexpected) begin
|
||||
if((dut.hart.ifu.PCD == 32'h80001dc6) || // for now, NOP out any stores to PLIC
|
||||
(dut.hart.ifu.PCD == 32'h80001de0) ||
|
||||
(dut.hart.ifu.PCD == 32'h80001de2)) begin
|
||||
$display("warning: NOPing out %s at PCD=%0x, instr %0d, time %0t", PCtextD, dut.hart.ifu.PCD, instrs, $time);
|
||||
force InstrDExpected = 32'b0010011;
|
||||
force dut.hart.ifu.InstrRawD = 32'b0010011;
|
||||
while (clk != 0) #1;
|
||||
while (clk != 1) #1;
|
||||
release dut.uncore.genblk1.clint.MTIME;
|
||||
while (clk != 1) #1;
|
||||
release dut.hart.ifu.InstrRawD;
|
||||
release InstrDExpected;
|
||||
warningCount += 1;
|
||||
forcedInstr = 1;
|
||||
end else begin
|
||||
forcedInstr = 0;
|
||||
end
|
||||
end
|
||||
|
||||
// Increment instruction count
|
||||
if (instrs <= 10 || (instrs <= 100 && instrs % 10 == 0) ||
|
||||
(instrs <= 1000 && instrs % 100 == 0) || (instrs <= 10000 && instrs % 1000 == 0) ||
|
||||
(instrs <= 100000 && instrs % 10000 == 0) || (instrs % 100000 == 0)) begin
|
||||
$display("loaded %0d instructions", instrs);
|
||||
end
|
||||
instrs += 1;
|
||||
|
||||
// Stop before bugs so "do" file can turn on waves
|
||||
if (instrs == waveOnICount) begin
|
||||
$display("turning on waves at %0d instructions", instrs);
|
||||
$stop;
|
||||
end else if (instrs == stopICount && stopICount != 0) begin
|
||||
$display("Ending sim at %0d instructions (set stopICount to 0 to let the sim go on)", instrs);
|
||||
$stop;
|
||||
end
|
||||
|
||||
// Check if PCD is going to be flushed due to a branch or jump
|
||||
if (`BPRED_ENABLED) begin
|
||||
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
|
||||
if (~PCDwrong && ~(dut.hart.ifu.PCD === PCDexpected)) begin
|
||||
$display("%0t ps, instr %0d: PC does not equal PC expected: %x, %x", $time, instrs, dut.hart.ifu.PCD, PCDexpected);
|
||||
`ERROR
|
||||
end
|
||||
InstrMask = InstrDExpected[1:0] == 2'b11 ? 32'hFFFFFFFF : 32'h0000FFFF;
|
||||
if ((~forcedInstr) && (~PCDwrong) && ((InstrMask & dut.hart.ifu.InstrRawD) !== (InstrMask & InstrDExpected))) begin
|
||||
$display("%0t ps, PCD %x, instr %0d: InstrD %x %s does not equal InstrDExpected %x %s", $time, dut.hart.ifu.PCD, instrs, dut.hart.ifu.InstrRawD, InstrDName, InstrDExpected, PCtextD);
|
||||
`ERROR
|
||||
end
|
||||
|
||||
// Repeated instruction means QEMU had an interrupt which we need to spoof
|
||||
if (PCFexpected == PCDexpected) begin
|
||||
$display("Note at %0t ps, PCM %x %s, instr %0d: spoofing an interrupt", $time, dut.hart.ifu.PCM, PCtextM, instrs);
|
||||
// Increment file pointers past the repeated instruction.
|
||||
`SCAN_PC(data_file_PCF, scan_file_PCF, PCtextF, PCtextF2, InstrFExpected, PCFexpected);
|
||||
`SCAN_PC(data_file_PCD, scan_file_PCD, PCtextD, PCtextD2, InstrDExpected, PCDexpected);
|
||||
scan_file_memR = $fscanf(data_file_memR, "%x\n", readAdrExpected);
|
||||
scan_file_memR = $fscanf(data_file_memR, "%x\n", readDataExpected);
|
||||
// Next force a timer interrupt (*** this may later need generalizing)
|
||||
force dut.uncore.genblk1.clint.MTIME = dut.uncore.genblk1.clint.MTIMECMP + 1;
|
||||
while (clk != 0) #1;
|
||||
while (clk != 1) #1;
|
||||
release dut.uncore.genblk1.clint.MTIME;
|
||||
end
|
||||
end
|
||||
lastPCD = dut.hart.ifu.PCD;
|
||||
end
|
||||
lastPCD = dut.hart.ifu.PCD;
|
||||
end
|
||||
end
|
||||
|
||||
@ -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,45 +516,61 @@ 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); \
|
||||
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 \
|
||||
$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, StartCSRname[j], ``PATH``.``CSR``_REGW, StartCSRexpected[j]); \
|
||||
`ERROR \
|
||||
end \
|
||||
end \
|
||||
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 \
|
||||
$display("CSRs' intital states look good"); \
|
||||
end else begin \
|
||||
if (!(`BUILDROOT == 1 && ``CSR``name == MSTATUSstring)) begin \
|
||||
for(integer j=0; j<totalCSR; j++) begin \
|
||||
if(!StartCSRname[j].icompare(``CSR``name)) begin \
|
||||
if(``PATH``.``CSR``_REGW != StartCSRexpected[j]) 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, StartCSRname[j], ``PATH``.``CSR``_REGW, StartCSRexpected[j]); \
|
||||
`ERROR \
|
||||
end \
|
||||
// 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 \
|
||||
|
Loading…
Reference in New Issue
Block a user