forked from Github_Repos/cvw
Merge branch 'main' of github.com:davidharrishmc/riscv-wally into main
This commit is contained in:
commit
7f62808544
@ -62,10 +62,8 @@
|
||||
// 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'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 56'h00003FFF
|
||||
//`define BOOTTIM_BASE 56'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`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
|
||||
|
@ -64,10 +64,10 @@
|
||||
// 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'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 56'h00003FFF
|
||||
//`define BOOTTIM_BASE 56'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 56'h00000FFF
|
||||
//`define BOOTTIM_BASE 56'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 56'h00003FFF
|
||||
`define BOOTTIM_BASE 56'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
|
@ -55,25 +55,23 @@
|
||||
// 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 32'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 32'h00003FFF
|
||||
//`define BOOTTIM_BASE 32'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 32'h00000FFF
|
||||
`define BOOTTIM_BASE 56'h00001000
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 32'h80000000
|
||||
`define TIM_RANGE 32'h07FFFFFF
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 32'h02000000
|
||||
`define CLINT_RANGE 32'h0000FFFF
|
||||
`define CLINT_BASE 56'h02000000
|
||||
`define CLINT_RANGE 56'h0000FFFF
|
||||
`define GPIO_SUPPORTED 1'b1
|
||||
`define GPIO_BASE 32'h10012000
|
||||
`define GPIO_RANGE 32'h000000FF
|
||||
`define GPIO_BASE 56'h10012000
|
||||
`define GPIO_RANGE 56'h000000FF
|
||||
`define UART_SUPPORTED 1'b1
|
||||
`define UART_BASE 32'h10000000
|
||||
`define UART_RANGE 32'h00000007
|
||||
`define UART_BASE 56'h10000000
|
||||
`define UART_RANGE 56'h00000007
|
||||
`define PLIC_SUPPORTED 1'b1
|
||||
`define PLIC_BASE 32'h0C000000
|
||||
`define PLIC_RANGE 32'h03FFFFFF
|
||||
`define PLIC_BASE 56'h0C000000
|
||||
`define PLIC_RANGE 56'h03FFFFFF
|
||||
|
||||
// Test modes
|
||||
|
||||
|
@ -63,25 +63,23 @@
|
||||
// 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 32'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 32'h00003FFF
|
||||
//`define BOOTTIM_BASE 32'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 32'h00000FFF
|
||||
`define BOOTTIM_BASE 34'h00001000
|
||||
`define BOOTTIM_RANGE 34'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 32'h80000000
|
||||
`define TIM_RANGE 32'h07FFFFFF
|
||||
`define TIM_BASE 34'h80000000
|
||||
`define TIM_RANGE 34'h07FFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 32'h02000000
|
||||
`define CLINT_RANGE 32'h0000FFFF
|
||||
`define CLINT_BASE 34'h02000000
|
||||
`define CLINT_RANGE 34'h0000FFFF
|
||||
`define GPIO_SUPPORTED 1'b1
|
||||
`define GPIO_BASE 32'h10012000
|
||||
`define GPIO_RANGE 32'h000000FF
|
||||
`define GPIO_BASE 34'h10012000
|
||||
`define GPIO_RANGE 34'h000000FF
|
||||
`define UART_SUPPORTED 1'b1
|
||||
`define UART_BASE 32'h10000000
|
||||
`define UART_RANGE 32'h00000007
|
||||
`define UART_BASE 34'h10000000
|
||||
`define UART_RANGE 34'h00000007
|
||||
`define PLIC_SUPPORTED 1'b1
|
||||
`define PLIC_BASE 32'h0C000000
|
||||
`define PLIC_RANGE 32'h03FFFFFF
|
||||
`define PLIC_BASE 34'h0C000000
|
||||
`define PLIC_RANGE 34'h03FFFFFF
|
||||
|
||||
// Test modes
|
||||
|
||||
|
@ -66,25 +66,23 @@
|
||||
// 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 32'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 32'h00003FFF
|
||||
//`define BOOTTIM_BASE 32'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 32'h00000FFF
|
||||
`define BOOTTIM_BASE 34'h00001000
|
||||
`define BOOTTIM_RANGE 34'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 32'h80000000
|
||||
`define TIM_RANGE 32'h07FFFFFF
|
||||
`define TIM_BASE 34'h80000000
|
||||
`define TIM_RANGE 34'h07FFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 32'h02000000
|
||||
`define CLINT_RANGE 32'h0000FFFF
|
||||
`define CLINT_BASE 34'h02000000
|
||||
`define CLINT_RANGE 34'h0000FFFF
|
||||
`define GPIO_SUPPORTED 1'b1
|
||||
`define GPIO_BASE 32'h10012000
|
||||
`define GPIO_RANGE 32'h000000FF
|
||||
`define GPIO_BASE 34'h10012000
|
||||
`define GPIO_RANGE 34'h000000FF
|
||||
`define UART_SUPPORTED 1'b1
|
||||
`define UART_BASE 32'h10000000
|
||||
`define UART_RANGE 32'h00000007
|
||||
`define UART_BASE 34'h10000000
|
||||
`define UART_RANGE 34'h00000007
|
||||
`define PLIC_SUPPORTED 1'b1
|
||||
`define PLIC_BASE 32'h0C000000
|
||||
`define PLIC_RANGE 32'h03FFFFFF
|
||||
`define PLIC_BASE 34'h0C000000
|
||||
`define PLIC_RANGE 34'h03FFFFFF
|
||||
|
||||
// Test modes
|
||||
|
||||
|
@ -63,10 +63,8 @@
|
||||
|
||||
// *** each of these is `PA_BITS wide. is this paramaterizable INSIDE the config file?
|
||||
`define BOOTTIM_SUPPORTED 1'b1
|
||||
`define BOOTTIM_BASE 34'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 34'h00003FFF
|
||||
//`define BOOTTIM_BASE 34'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 34'h00000FFF
|
||||
`define BOOTTIM_BASE 34'h00001000
|
||||
`define BOOTTIM_RANGE 34'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 34'h80000000
|
||||
`define TIM_RANGE 34'h07FFFFFF
|
||||
|
@ -64,25 +64,23 @@
|
||||
// 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 32'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 32'h00003FFF
|
||||
//`define BOOTTIM_BASE 32'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 32'h00000FFF
|
||||
`define BOOTTIM_BASE 56'h00001000
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 32'h80000000
|
||||
`define TIM_RANGE 32'h07FFFFFF
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 32'h02000000
|
||||
`define CLINT_RANGE 32'h0000FFFF
|
||||
`define CLINT_BASE 56'h02000000
|
||||
`define CLINT_RANGE 56'h0000FFFF
|
||||
`define GPIO_SUPPORTED 1'b1
|
||||
`define GPIO_BASE 32'h10012000
|
||||
`define GPIO_RANGE 32'h000000FF
|
||||
`define GPIO_BASE 56'h10012000
|
||||
`define GPIO_RANGE 56'h000000FF
|
||||
`define UART_SUPPORTED 1'b1
|
||||
`define UART_BASE 32'h10000000
|
||||
`define UART_RANGE 32'h00000007
|
||||
`define UART_BASE 56'h10000000
|
||||
`define UART_RANGE 56'h00000007
|
||||
`define PLIC_SUPPORTED 1'b1
|
||||
`define PLIC_BASE 32'h0C000000
|
||||
`define PLIC_RANGE 32'h03FFFFFF
|
||||
`define PLIC_BASE 56'h0C000000
|
||||
`define PLIC_RANGE 56'h03FFFFFF
|
||||
|
||||
// Test modes
|
||||
|
||||
|
@ -67,10 +67,10 @@
|
||||
|
||||
// *** each of these is `PA_BITS wide. is this paramaterizable INSIDE the config file?
|
||||
`define BOOTTIM_SUPPORTED 1'b1
|
||||
`define BOOTTIM_RANGE 56'h00003FFF
|
||||
`define BOOTTIM_BASE 56'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_BASE 56'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 56'h00000FFF
|
||||
//`define BOOTTIM_RANGE 56'h00003FFF
|
||||
//`define BOOTTIM_BASE 56'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_BASE 56'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
|
@ -66,25 +66,23 @@
|
||||
// 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 32'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 32'h00003FFF
|
||||
//`define BOOTTIM_BASE 32'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 32'h00000FFF
|
||||
`define BOOTTIM_BASE 56'h00001000
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 32'h80000000
|
||||
`define TIM_RANGE 32'h07FFFFFF
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 32'h02000000
|
||||
`define CLINT_RANGE 32'h0000FFFF
|
||||
`define CLINT_BASE 56'h02000000
|
||||
`define CLINT_RANGE 56'h0000FFFF
|
||||
`define GPIO_SUPPORTED 1'b1
|
||||
`define GPIO_BASE 32'h10012000
|
||||
`define GPIO_RANGE 32'h000000FF
|
||||
`define GPIO_BASE 56'h10012000
|
||||
`define GPIO_RANGE 56'h000000FF
|
||||
`define UART_SUPPORTED 1'b1
|
||||
`define UART_BASE 32'h10000000
|
||||
`define UART_RANGE 32'h00000007
|
||||
`define UART_BASE 56'h10000000
|
||||
`define UART_RANGE 56'h00000007
|
||||
`define PLIC_SUPPORTED 1'b1
|
||||
`define PLIC_BASE 32'h0C000000
|
||||
`define PLIC_RANGE 32'h03FFFFFF
|
||||
`define PLIC_BASE 56'h0C000000
|
||||
`define PLIC_RANGE 56'h03FFFFFF
|
||||
|
||||
// Test modes
|
||||
|
||||
|
@ -62,25 +62,23 @@
|
||||
// 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 32'h00000000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
`define BOOTTIM_RANGE 32'h00003FFF
|
||||
//`define BOOTTIM_BASE 32'h00001000 // spec had been 0x1000 to 0x2FFF, but dh truncated to 0x1000 to 0x1FFF because upper half seems to be all zeros and this is easier for decoder
|
||||
//`define BOOTTIM_RANGE 32'h00000FFF
|
||||
`define BOOTTIM_BASE 56'h00001000
|
||||
`define BOOTTIM_RANGE 56'h00000FFF
|
||||
`define TIM_SUPPORTED 1'b1
|
||||
`define TIM_BASE 32'h80000000
|
||||
`define TIM_RANGE 32'h07FFFFFF
|
||||
`define TIM_BASE 56'h80000000
|
||||
`define TIM_RANGE 56'h07FFFFFF
|
||||
`define CLINT_SUPPORTED 1'b1
|
||||
`define CLINT_BASE 32'h02000000
|
||||
`define CLINT_RANGE 32'h0000FFFF
|
||||
`define CLINT_BASE 56'h02000000
|
||||
`define CLINT_RANGE 56'h0000FFFF
|
||||
`define GPIO_SUPPORTED 1'b1
|
||||
`define GPIO_BASE 32'h10012000
|
||||
`define GPIO_RANGE 32'h000000FF
|
||||
`define GPIO_BASE 56'h10012000
|
||||
`define GPIO_RANGE 56'h000000FF
|
||||
`define UART_SUPPORTED 1'b1
|
||||
`define UART_BASE 32'h10000000
|
||||
`define UART_RANGE 32'h00000007
|
||||
`define UART_BASE 56'h10000000
|
||||
`define UART_RANGE 56'h00000007
|
||||
`define PLIC_SUPPORTED 1'b1
|
||||
`define PLIC_BASE 32'h0C000000
|
||||
`define PLIC_RANGE 32'h03FFFFFF
|
||||
`define PLIC_BASE 56'h0C000000
|
||||
`define PLIC_RANGE 56'h03FFFFFF
|
||||
|
||||
// Test modes
|
||||
|
||||
|
@ -21,11 +21,12 @@
|
||||
# - Logs parse_qemu.py's simulated gdb output to qemu_in_gdb_format.txt
|
||||
#cat qemu_output.txt | ./parse_qemu.py >qemu_in_gdb_format.txt
|
||||
#cat qemu_output.txt | ./parse_qemu.py | ./parse_gdb_output.py "/courses/e190ax/buildroot_boot/"
|
||||
|
||||
# Uncomment this version in case you just want to have qemu_in_gdb_format.txt around
|
||||
# It is often helpful for general debugging
|
||||
#(qemu-system-riscv64 -M virt -nographic -bios /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/fw_jump.elf -kernel /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/Image -append "root=/dev/vda ro" -initrd /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/rootfs.cpio -d nochain,cpu,in_asm -serial /dev/null -singlestep -s -S 2>&1 >/dev/null | ./parse_qemu.py >qemu_in_gdb_format.txt) & riscv64-unknown-elf-gdb -x gdbinit_qemulog
|
||||
|
||||
(qemu-system-riscv64 -M virt -nographic -bios /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/fw_jump.elf -kernel /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/Image -append "root=/dev/vda ro" -initrd /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/rootfs.cpio -d nochain,cpu,in_asm -serial /dev/null -singlestep -s -S 2>&1 >/dev/null | ./parse_qemu.py >/courses/e190ax/buildroot_boot/qemu_in_gdb_format.txt) & riscv64-unknown-elf-gdb -x gdbinit_qemulog
|
||||
# Split qemu_in_gdb_format.txt into chunks of 100,000 instructions for easier inspection
|
||||
#cd /courses/e190ax/buildroot_boot
|
||||
#split -d -l 5600000 qemu_in_gdb_format.txt --verbose
|
||||
|
||||
# Uncomment this version for parse_gdb_output.py debugging
|
||||
@ -36,4 +37,4 @@
|
||||
# =========== Just Do the Thing ==========
|
||||
# Uncomment this version for the whole thing
|
||||
# - Logs info needed by buildroot testbench
|
||||
(qemu-system-riscv64 -M virt -nographic -bios /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/fw_jump.elf -kernel /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/Image -append "root=/dev/vda ro" -initrd /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/rootfs.cpio -d nochain,cpu,in_asm -serial /dev/null -singlestep -s -S 2>&1 >/dev/null | ./parse_qemu.py | ./parse_gdb_output.py "/courses/e190ax/buildroot_boot_new/") & riscv64-unknown-elf-gdb -x gdbinit_qemulog
|
||||
#(qemu-system-riscv64 -M virt -nographic -bios /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/fw_jump.elf -kernel /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/Image -append "root=/dev/vda ro" -initrd /courses/e190ax/qemu_sim/rv64_initrd/buildroot_experimental/output/images/rootfs.cpio -d nochain,cpu,in_asm -serial /dev/null -singlestep -s -S 2>&1 >/dev/null | ./parse_qemu.py | ./parse_gdb_output.py "/courses/e190ax/buildroot_boot_new/") & riscv64-unknown-elf-gdb -x gdbinit_qemulog
|
||||
|
@ -9,9 +9,10 @@ pageFaultCSRs = {}
|
||||
regs = {}
|
||||
pageFaultRegs = {}
|
||||
instrs = {}
|
||||
instrCount = 0
|
||||
|
||||
def printPC(l):
|
||||
global parseState, inPageFault, CSRs, pageFaultCSRs, regs, pageFaultCSRs, instrs
|
||||
global parseState, inPageFault, CSRs, pageFaultCSRs, regs, pageFaultCSRs, instrs, instrCount
|
||||
if not inPageFault:
|
||||
inst = l.split()
|
||||
if len(inst) > 3:
|
||||
@ -19,6 +20,9 @@ def printPC(l):
|
||||
else:
|
||||
print(f'=> {inst[1]}:\t{inst[2]}')
|
||||
print(f'{inst[0]} 0x{inst[1]}')
|
||||
instrCount += 1
|
||||
if ((instrCount % 100000) == 0):
|
||||
sys.stderr.write("QEMU parser reached "+str(instrCount)+" instrs\n")
|
||||
|
||||
def printCSRs():
|
||||
global parseState, inPageFault, CSRs, pageFaultCSRs, regs, pageFaultCSRs, instrs
|
||||
|
@ -35,5 +35,6 @@ vopt work_busybear.testbench -o workopt_busybear
|
||||
|
||||
vsim workopt_busybear -suppress 8852,12070
|
||||
|
||||
run -all
|
||||
run -all
|
||||
quit
|
||||
|
@ -35,9 +35,10 @@ vopt +acc work.testbench -o workopt
|
||||
|
||||
vsim workopt -suppress 8852,12070
|
||||
|
||||
do ./wave-dos/linux-waves.do
|
||||
|
||||
|
||||
#-- Run the Simulation
|
||||
run -all
|
||||
do ./wave-dos/linux-waves.do
|
||||
run -all
|
||||
##quit
|
||||
|
@ -122,8 +122,7 @@ add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrn/UEPC_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrn/UTVEC_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrn/UIP_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrn/UIE_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrm/PMPCFG01_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrm/PMPCFG23_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrm/PMPCFG_ARRAY_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrm/PMPADDR_ARRAY_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csrm/MISA_REGW
|
||||
add wave -hex sim:/testbench/dut/hart/priv/csr/genblk1/csru/FRM_REGW
|
||||
|
282
wally-pipelined/src/cache/ICacheCntrl.sv
vendored
282
wally-pipelined/src/cache/ICacheCntrl.sv
vendored
@ -71,11 +71,11 @@ module ICacheCntrl #(parameter BLOCKLEN = 256)
|
||||
);
|
||||
|
||||
// FSM states
|
||||
localparam STATE_READY = 0;
|
||||
localparam STATE_HIT_SPILL = 1; // spill, block 0 hit
|
||||
localparam STATE_HIT_SPILL_MISS_FETCH_WDV = 2; // block 1 miss, issue read to AHB and wait data.
|
||||
localparam STATE_HIT_SPILL_MISS_FETCH_DONE = 3; // write data into SRAM/LUT
|
||||
localparam STATE_HIT_SPILL_MERGE = 4; // Read block 0 of CPU access, should be able to optimize into STATE_HIT_SPILL.
|
||||
localparam STATE_READY = 'h0;
|
||||
localparam STATE_HIT_SPILL = 'h1; // spill, block 0 hit
|
||||
localparam STATE_HIT_SPILL_MISS_FETCH_WDV = 'h2; // block 1 miss, issue read to AHB and wait data.
|
||||
localparam STATE_HIT_SPILL_MISS_FETCH_DONE = 'h3; // write data into SRAM/LUT
|
||||
localparam STATE_HIT_SPILL_MERGE = 'h4; // Read block 0 of CPU access, should be able to optimize into STATE_HIT_SPILL.
|
||||
|
||||
// a challenge is the spill signal gets us out of the ready state and moves us to
|
||||
// 1 of the 2 spill branches. However the original fsm design had us return to
|
||||
@ -91,30 +91,30 @@ module ICacheCntrl #(parameter BLOCKLEN = 256)
|
||||
// between CPU stalling and that register.
|
||||
// Picking option 1.
|
||||
|
||||
localparam STATE_HIT_SPILL_FINAL = 5; // this state replicates STATE_READY's replay of the
|
||||
localparam STATE_HIT_SPILL_FINAL = 'h5; // this state replicates STATE_READY's replay of the
|
||||
// spill access but does nto consider spill. It also does not do another operation.
|
||||
|
||||
|
||||
localparam STATE_MISS_FETCH_WDV = 6; // aligned miss, issue read to AHB and wait for data.
|
||||
localparam STATE_MISS_FETCH_DONE = 7; // write data into SRAM/LUT
|
||||
localparam STATE_MISS_READ = 8; // read block 1 from SRAM/LUT
|
||||
localparam STATE_MISS_FETCH_WDV = 'h6; // aligned miss, issue read to AHB and wait for data.
|
||||
localparam STATE_MISS_FETCH_DONE = 'h7; // write data into SRAM/LUT
|
||||
localparam STATE_MISS_READ = 'h8; // read block 1 from SRAM/LUT
|
||||
|
||||
localparam STATE_MISS_SPILL_FETCH_WDV = 9; // spill, miss on block 0, issue read to AHB and wait
|
||||
localparam STATE_MISS_SPILL_FETCH_DONE = 10; // write data into SRAM/LUT
|
||||
localparam STATE_MISS_SPILL_READ1 = 11; // read block 0 from SRAM/LUT
|
||||
localparam STATE_MISS_SPILL_2 = 12; // return to ready if hit or do second block update.
|
||||
localparam STATE_MISS_SPILL_2_START = 13; // return to ready if hit or do second block update.
|
||||
localparam STATE_MISS_SPILL_MISS_FETCH_WDV = 14; // miss on block 1, issue read to AHB and wait
|
||||
localparam STATE_MISS_SPILL_MISS_FETCH_DONE = 15; // write data to SRAM/LUT
|
||||
localparam STATE_MISS_SPILL_MERGE = 16; // read block 0 of CPU access,
|
||||
localparam STATE_MISS_SPILL_FETCH_WDV = 'h9; // spill, miss on block 0, issue read to AHB and wait
|
||||
localparam STATE_MISS_SPILL_FETCH_DONE = 'ha; // write data into SRAM/LUT
|
||||
localparam STATE_MISS_SPILL_READ1 = 'hb; // read block 0 from SRAM/LUT
|
||||
localparam STATE_MISS_SPILL_2 = 'hc; // return to ready if hit or do second block update.
|
||||
localparam STATE_MISS_SPILL_2_START = 'hd; // return to ready if hit or do second block update.
|
||||
localparam STATE_MISS_SPILL_MISS_FETCH_WDV = 'he; // miss on block 1, issue read to AHB and wait
|
||||
localparam STATE_MISS_SPILL_MISS_FETCH_DONE = 'hf; // write data to SRAM/LUT
|
||||
localparam STATE_MISS_SPILL_MERGE = 'h10; // read block 0 of CPU access,
|
||||
|
||||
localparam STATE_MISS_SPILL_FINAL = 17; // this state replicates STATE_READY's replay of the
|
||||
localparam STATE_MISS_SPILL_FINAL = 'h11; // this state replicates STATE_READY's replay of the
|
||||
// spill access but does nto consider spill. It also does not do another operation.
|
||||
|
||||
|
||||
localparam STATE_INVALIDATE = 18; // *** not sure if invalidate or evict? invalidate by cache block or address?
|
||||
localparam STATE_TLB_MISS = 19;
|
||||
localparam STATE_TLB_MISS_DONE = 20;
|
||||
localparam STATE_INVALIDATE = 'h12; // *** not sure if invalidate or evict? invalidate by cache block or address?
|
||||
localparam STATE_TLB_MISS = 'h13;
|
||||
localparam STATE_TLB_MISS_DONE = 'h14;
|
||||
|
||||
|
||||
|
||||
@ -213,179 +213,175 @@ module ICacheCntrl #(parameter BLOCKLEN = 256)
|
||||
ICacheStallF = 1'b1;
|
||||
|
||||
case (CurrState)
|
||||
|
||||
STATE_READY: begin
|
||||
PCMux = 2'b00;
|
||||
ICacheReadEn = 1'b1;
|
||||
if (ITLBMissF) begin
|
||||
NextState = STATE_TLB_MISS;
|
||||
end else if (hit & ~spill) begin
|
||||
SavePC = 1'b1;
|
||||
ICacheStallF = 1'b0;
|
||||
NextState = STATE_READY;
|
||||
end else if (hit & spill) begin
|
||||
spillSave = 1'b1;
|
||||
PCMux = 2'b10;
|
||||
NextState = STATE_HIT_SPILL;
|
||||
end else if (~hit & ~spill) begin
|
||||
CntReset = 1'b1;
|
||||
NextState = STATE_MISS_FETCH_WDV;
|
||||
end else if (~hit & spill) begin
|
||||
CntReset = 1'b1;
|
||||
PCMux = 2'b01;
|
||||
NextState = STATE_MISS_SPILL_FETCH_WDV;
|
||||
end else begin
|
||||
PCMux = 2'b00;
|
||||
ICacheReadEn = 1'b1;
|
||||
if (ITLBMissF) begin
|
||||
NextState = STATE_TLB_MISS;
|
||||
end else if (hit & ~spill) begin
|
||||
SavePC = 1'b1;
|
||||
ICacheStallF = 1'b0;
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
end else if (hit & spill) begin
|
||||
spillSave = 1'b1;
|
||||
PCMux = 2'b10;
|
||||
NextState = STATE_HIT_SPILL;
|
||||
end else if (~hit & ~spill) begin
|
||||
CntReset = 1'b1;
|
||||
NextState = STATE_MISS_FETCH_WDV;
|
||||
end else if (~hit & spill) begin
|
||||
CntReset = 1'b1;
|
||||
PCMux = 2'b01;
|
||||
NextState = STATE_MISS_SPILL_FETCH_WDV;
|
||||
end else begin
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
end
|
||||
|
||||
// branch 1, hit spill and 2, miss spill hit
|
||||
STATE_HIT_SPILL: begin
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
ICacheReadEn = 1'b1;
|
||||
if (hit) begin
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
ICacheReadEn = 1'b1;
|
||||
if (hit) begin
|
||||
NextState = STATE_HIT_SPILL_FINAL;
|
||||
end else begin
|
||||
CntReset = 1'b1;
|
||||
end else begin
|
||||
CntReset = 1'b1;
|
||||
NextState = STATE_HIT_SPILL_MISS_FETCH_WDV;
|
||||
end
|
||||
end
|
||||
end
|
||||
STATE_HIT_SPILL_MISS_FETCH_WDV: begin
|
||||
PCMux = 2'b10;
|
||||
//InstrReadF = 1'b1;
|
||||
PreCntEn = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_HIT_SPILL_MISS_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_HIT_SPILL_MISS_FETCH_WDV;
|
||||
end
|
||||
PCMux = 2'b10;
|
||||
//InstrReadF = 1'b1;
|
||||
PreCntEn = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_HIT_SPILL_MISS_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_HIT_SPILL_MISS_FETCH_WDV;
|
||||
end
|
||||
end
|
||||
STATE_HIT_SPILL_MISS_FETCH_DONE: begin
|
||||
PCMux = 2'b10;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
PCMux = 2'b10;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
NextState = STATE_HIT_SPILL_MERGE;
|
||||
end
|
||||
STATE_HIT_SPILL_MERGE: begin
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_HIT_SPILL_FINAL;
|
||||
end
|
||||
STATE_HIT_SPILL_FINAL: begin
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b00;
|
||||
UnalignedSelect = 1'b1;
|
||||
SavePC = 1'b1;
|
||||
NextState = STATE_READY;
|
||||
ICacheStallF = 1'b0;
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b00;
|
||||
UnalignedSelect = 1'b1;
|
||||
SavePC = 1'b1;
|
||||
NextState = STATE_READY;
|
||||
ICacheStallF = 1'b0;
|
||||
end
|
||||
|
||||
// branch 3 miss no spill
|
||||
STATE_MISS_FETCH_WDV: begin
|
||||
PCMux = 2'b01;
|
||||
//InstrReadF = 1'b1;
|
||||
PreCntEn = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_MISS_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_MISS_FETCH_WDV;
|
||||
end
|
||||
PCMux = 2'b01;
|
||||
//InstrReadF = 1'b1;
|
||||
PreCntEn = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_MISS_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_MISS_FETCH_WDV;
|
||||
end
|
||||
end
|
||||
STATE_MISS_FETCH_DONE: begin
|
||||
PCMux = 2'b01;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
PCMux = 2'b01;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
NextState = STATE_MISS_READ;
|
||||
end
|
||||
STATE_MISS_READ: begin
|
||||
PCMux = 2'b01;
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_READY;
|
||||
PCMux = 2'b01;
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
|
||||
// branch 4 miss spill hit, and 5 miss spill miss
|
||||
STATE_MISS_SPILL_FETCH_WDV: begin
|
||||
PCMux = 2'b01;
|
||||
PreCntEn = 1'b1;
|
||||
//InstrReadF = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_MISS_SPILL_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_MISS_SPILL_FETCH_WDV;
|
||||
end
|
||||
PCMux = 2'b01;
|
||||
PreCntEn = 1'b1;
|
||||
//InstrReadF = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_MISS_SPILL_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_MISS_SPILL_FETCH_WDV;
|
||||
end
|
||||
end
|
||||
STATE_MISS_SPILL_FETCH_DONE: begin
|
||||
PCMux = 2'b01;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_READ1;
|
||||
PCMux = 2'b01;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_READ1;
|
||||
end
|
||||
STATE_MISS_SPILL_READ1: begin // always be a hit as we just wrote that cache block.
|
||||
PCMux = 2'b01; // there is a 1 cycle delay after setting the address before the date arrives.
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_2;
|
||||
PCMux = 2'b01; // there is a 1 cycle delay after setting the address before the date arrives.
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_2;
|
||||
end
|
||||
STATE_MISS_SPILL_2: begin
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
spillSave = 1'b1; /// *** Could pipeline these to make it clearer in the fsm.
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_2_START;
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
spillSave = 1'b1; /// *** Could pipeline these to make it clearer in the fsm.
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_2_START;
|
||||
end
|
||||
STATE_MISS_SPILL_2_START: begin
|
||||
if (~hit) begin
|
||||
CntReset = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_MISS_FETCH_WDV;
|
||||
end else begin
|
||||
NextState = STATE_READY;
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b00;
|
||||
UnalignedSelect = 1'b1;
|
||||
SavePC = 1'b1;
|
||||
ICacheStallF = 1'b0;
|
||||
end
|
||||
if (~hit) begin
|
||||
CntReset = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_MISS_FETCH_WDV;
|
||||
end else begin
|
||||
NextState = STATE_READY;
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b00;
|
||||
UnalignedSelect = 1'b1;
|
||||
SavePC = 1'b1;
|
||||
ICacheStallF = 1'b0;
|
||||
end
|
||||
end
|
||||
STATE_MISS_SPILL_MISS_FETCH_WDV: begin
|
||||
PCMux = 2'b10;
|
||||
PreCntEn = 1'b1;
|
||||
//InstrReadF = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_MISS_SPILL_MISS_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_MISS_SPILL_MISS_FETCH_WDV;
|
||||
end
|
||||
PCMux = 2'b10;
|
||||
PreCntEn = 1'b1;
|
||||
//InstrReadF = 1'b1;
|
||||
if (FetchCountFlag & InstrAckF) begin
|
||||
NextState = STATE_MISS_SPILL_MISS_FETCH_DONE;
|
||||
end else begin
|
||||
NextState = STATE_MISS_SPILL_MISS_FETCH_WDV;
|
||||
end
|
||||
end
|
||||
STATE_MISS_SPILL_MISS_FETCH_DONE: begin
|
||||
PCMux = 2'b10;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_MERGE;
|
||||
PCMux = 2'b10;
|
||||
ICacheMemWriteEnable = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_MERGE;
|
||||
end
|
||||
STATE_MISS_SPILL_MERGE: begin
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b10;
|
||||
UnalignedSelect = 1'b1;
|
||||
ICacheReadEn = 1'b1;
|
||||
NextState = STATE_MISS_SPILL_FINAL;
|
||||
end
|
||||
STATE_MISS_SPILL_FINAL: begin
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b00;
|
||||
UnalignedSelect = 1'b1;
|
||||
SavePC = 1'b1;
|
||||
ICacheStallF = 1'b0;
|
||||
NextState = STATE_READY;
|
||||
ICacheReadEn = 1'b1;
|
||||
PCMux = 2'b00;
|
||||
UnalignedSelect = 1'b1;
|
||||
SavePC = 1'b1;
|
||||
ICacheStallF = 1'b0;
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
STATE_TLB_MISS: begin
|
||||
if (ITLBWriteF | WalkerInstrPageFaultF) begin
|
||||
NextState = STATE_TLB_MISS_DONE;
|
||||
end else begin
|
||||
NextState = STATE_TLB_MISS;
|
||||
end
|
||||
if (ITLBWriteF | WalkerInstrPageFaultF) begin
|
||||
NextState = STATE_TLB_MISS_DONE;
|
||||
end else begin
|
||||
NextState = STATE_TLB_MISS;
|
||||
end
|
||||
end
|
||||
STATE_TLB_MISS_DONE : begin
|
||||
NextState = STATE_READY;
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
default: begin
|
||||
PCMux = 2'b01;
|
||||
NextState = STATE_READY;
|
||||
PCMux = 2'b01;
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
// *** add in error handling and invalidate/evict
|
||||
endcase
|
||||
|
@ -139,6 +139,7 @@ module ahblite (
|
||||
// (ProposedNextBusState == MMUTRANSLATE);
|
||||
|
||||
// The PMA and PMP checkers can decide to squash the access
|
||||
// *** this probably needs to be controlled by the caches rather than EBU dh 7/2/11
|
||||
assign NextBusState = (DSquashBusAccessM || ISquashBusAccessF) ? IDLE : ProposedNextBusState;
|
||||
|
||||
// stall signals
|
||||
|
@ -2,6 +2,7 @@
|
||||
// It is unsigned and uses Radix-4 Booth encoding.
|
||||
// This file was automatically generated by tdm.pl.
|
||||
|
||||
/*
|
||||
module mult64 (x, y, P);
|
||||
|
||||
input [63:0] x;
|
||||
@ -18,7 +19,8 @@ module mult64 (x, y, P);
|
||||
//assign P = Pt[127:0];
|
||||
ldf128 cpa (cout, P, Sum, Carry, 1'b0);
|
||||
|
||||
endmodule // mult64
|
||||
endmodule // mult64
|
||||
*/
|
||||
|
||||
module multiplier( y, x, Sum, Carry );
|
||||
|
||||
@ -11612,7 +11614,7 @@ module r4be(x0,x1,x2,sing,doub,neg);
|
||||
|
||||
endmodule // r4be
|
||||
|
||||
|
||||
/*
|
||||
// Use maj and two xor2's, with cin being late
|
||||
module fullAdd_xc(cout, s, a, b, cin);
|
||||
|
||||
@ -11629,7 +11631,7 @@ module fullAdd_xc(cout, s, a, b, cin);
|
||||
maj MAJ_0_112(cout,a,b,cin);
|
||||
|
||||
endmodule // fullAdd_xc
|
||||
|
||||
*/
|
||||
|
||||
module maj(y, a, b, c);
|
||||
|
||||
@ -11645,6 +11647,7 @@ module maj(y, a, b, c);
|
||||
|
||||
endmodule // maj
|
||||
|
||||
/*
|
||||
// 4:2 Weinberger compressor
|
||||
module fourtwo_x(t, S, C, X, Y, Z, W, t_1);
|
||||
|
||||
@ -11664,6 +11667,7 @@ module fourtwo_x(t, S, C, X, Y, Z, W, t_1);
|
||||
fullAdd_xc secondCSA_0_160(C,S,W,t_1,intermediate);
|
||||
|
||||
endmodule // fourtwo_x
|
||||
*/
|
||||
|
||||
module inverter(egress, in);
|
||||
|
||||
@ -11767,6 +11771,7 @@ module fullAdd_x(cout,sum,a,b,c);
|
||||
|
||||
endmodule // fullAdd_x
|
||||
|
||||
/*
|
||||
module nand2(egress,in1,in2);
|
||||
|
||||
output egress;
|
||||
@ -11800,7 +11805,7 @@ module and3(y,a,b,c);
|
||||
assign y = a&b&c;
|
||||
|
||||
endmodule // and3
|
||||
|
||||
*/
|
||||
module and2(y,a,b);
|
||||
|
||||
output y;
|
||||
@ -11810,7 +11815,7 @@ module and2(y,a,b);
|
||||
assign y = a&b;
|
||||
|
||||
endmodule // and2
|
||||
|
||||
/*
|
||||
module nor2(egress,in1,in2);
|
||||
|
||||
output egress;
|
||||
@ -11902,6 +11907,7 @@ module oai(egress,in1,in2,in3);
|
||||
assign egress = ~(in3 & (in1|in2));
|
||||
|
||||
endmodule // oai
|
||||
*/
|
||||
|
||||
module aoi(egress,in1,in2,in3);
|
||||
|
||||
@ -11949,7 +11955,7 @@ module fullAdd_i(cout_b,sum_b,a,b,c);
|
||||
sum_b sum_0_32(sum_b,a,b,c,cout_b);
|
||||
|
||||
endmodule // fullAdd_i
|
||||
|
||||
/*
|
||||
module fullAdd(cout,s,a,b,c);
|
||||
|
||||
output cout;
|
||||
@ -11979,7 +11985,7 @@ module blackCell(g_i_j, p_i_j, g_i_k, p_i_k, g_kneg1_j, p_kneg1_j);
|
||||
and2 and_0_48(p_i_j, p_i_k, p_kneg1_j);
|
||||
|
||||
endmodule // blackCell
|
||||
|
||||
*/
|
||||
module grayCell(g_i_j, g_i_k, p_i_k, g_kneg1_j);
|
||||
|
||||
output g_i_j;
|
||||
|
@ -118,6 +118,7 @@ module barrel_shifter_r57 (Z, Sticky, A, Shift);
|
||||
|
||||
endmodule // barrel_shifter_r57
|
||||
|
||||
/*
|
||||
module barrel_shifter_r64 (Z, Sticky, A, Shift);
|
||||
|
||||
input [63:0] A;
|
||||
@ -160,3 +161,4 @@ module barrel_shifter_r64 (Z, Sticky, A, Shift);
|
||||
assign Sticky = (S != sixtythreezeros);
|
||||
|
||||
endmodule // barrel_shifter_r64
|
||||
*/
|
@ -77,7 +77,7 @@ module flopenr #(parameter WIDTH = 8) (
|
||||
output logic [WIDTH-1:0] q);
|
||||
|
||||
always_ff @(posedge clk, posedge reset)
|
||||
if (reset) q <= #1 0;
|
||||
if (reset) q <= #1 0;
|
||||
else if (en) q <= #1 d;
|
||||
endmodule
|
||||
|
||||
|
@ -70,15 +70,16 @@ module ifu (
|
||||
input logic [`XLEN-1:0] PageTableEntryF,
|
||||
input logic [1:0] PageTypeF,
|
||||
input logic [`XLEN-1:0] SATP_REGW,
|
||||
input logic STATUS_MXR, STATUS_SUM,
|
||||
input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
input logic [1:0] STATUS_MPP,
|
||||
input logic ITLBWriteF, ITLBFlushF,
|
||||
input logic WalkerInstrPageFaultF,
|
||||
|
||||
output logic ITLBMissF, ITLBHitF,
|
||||
|
||||
// pmp/pma (inside mmu) signals. *** temporarily from AHB bus but eventually replace with internal versions pre H
|
||||
input var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
input var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
|
||||
input var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
input var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
|
||||
output logic PMPInstrAccessFaultF, PMAInstrAccessFaultF,
|
||||
output logic ISquashBusAccessF
|
||||
@ -127,7 +128,7 @@ module ifu (
|
||||
.TLBMiss(ITLBMissF),
|
||||
.TLBHit(ITLBHitF),
|
||||
.TLBPageFault(ITLBInstrPageFaultF),
|
||||
.ExecuteAccessF(InstrReadF), /// *** Ross Thompson this is definitely wrong. InstrReadF changed to icache read to memory.
|
||||
.ExecuteAccessF(1'b1), // ***dh -- this should eventually change to only true if an instruction fetch is occurring
|
||||
.AtomicAccessM(1'b0),
|
||||
.ReadAccessM(1'b0),
|
||||
.WriteAccessM(1'b0),
|
||||
|
@ -72,7 +72,8 @@ module lsu (
|
||||
|
||||
// page table walker
|
||||
input logic [`XLEN-1:0] SATP_REGW, // from csr
|
||||
input logic STATUS_MXR, STATUS_SUM, // from csr
|
||||
input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
input logic [1:0] STATUS_MPP,
|
||||
|
||||
input logic [`XLEN-1:0] PCF,
|
||||
input logic ITLBMissF,
|
||||
@ -86,14 +87,14 @@ module lsu (
|
||||
output logic DTLBHitM, // not connected
|
||||
|
||||
// PMA/PMP (inside mmu) signals
|
||||
input logic [31:0] HADDR, // *** replace all of these H inputs with physical adress once pma checkers have been edited to use paddr as well.
|
||||
input logic [2:0] HSIZE, HBURST,
|
||||
input logic HWRITE,
|
||||
input var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
input var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0], // *** this one especially has a large note attached to it in pmpchecker.
|
||||
input logic [31:0] HADDR, // *** replace all of these H inputs with physical adress once pma checkers have been edited to use paddr as well.
|
||||
input logic [2:0] HSIZE, HBURST,
|
||||
input logic HWRITE,
|
||||
input var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
input var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW[`PMP_ENTRIES-1:0], // *** this one especially has a large note attached to it in pmpchecker.
|
||||
|
||||
output logic PMALoadAccessFaultM, PMAStoreAccessFaultM,
|
||||
output logic PMPLoadAccessFaultM, PMPStoreAccessFaultM, // *** can these be parameterized? we dont need the m stage ones for the immu and vice versa.
|
||||
output logic PMALoadAccessFaultM, PMAStoreAccessFaultM,
|
||||
output logic PMPLoadAccessFaultM, PMPStoreAccessFaultM, // *** can these be parameterized? we dont need the m stage ones for the immu and vice versa.
|
||||
|
||||
output logic DSquashBusAccessM
|
||||
// output logic [5:0] DHSELRegionsM
|
||||
|
@ -24,12 +24,13 @@
|
||||
///////////////////////////////////////////
|
||||
|
||||
`include "wally-config.vh"
|
||||
// verilator lint_off UNOPTFLAT
|
||||
|
||||
module adrdecs (
|
||||
input logic [`PA_BITS-1:0] PhysicalAddress,
|
||||
input logic AccessRW, AccessRX, AccessRWX,
|
||||
input logic [1:0] Size,
|
||||
output logic [5:0] SelRegions
|
||||
output logic [6:0] SelRegions
|
||||
);
|
||||
|
||||
// Determine which region of physical memory (if any) is being accessed
|
||||
@ -41,5 +42,8 @@ module adrdecs (
|
||||
adrdec uartdec(PhysicalAddress, `UART_BASE, `UART_RANGE, `UART_SUPPORTED, AccessRW, Size, 4'b0001, SelRegions[1]);
|
||||
adrdec plicdec(PhysicalAddress, `PLIC_BASE, `PLIC_RANGE, `PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[0]);
|
||||
|
||||
assign SelRegions[6] = ~|(SelRegions[5:0]);
|
||||
|
||||
endmodule
|
||||
|
||||
// verilator lint_on UNOPTFLAT
|
||||
|
@ -34,7 +34,8 @@ module mmu #(parameter ENTRY_BITS = 3,
|
||||
input logic clk, reset,
|
||||
// Current value of satp CSR (from privileged unit)
|
||||
input logic [`XLEN-1:0] SATP_REGW,
|
||||
input logic STATUS_MXR, STATUS_SUM,
|
||||
input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
input logic [1:0] STATUS_MPP,
|
||||
|
||||
// Current privilege level of the processeor
|
||||
input logic [1:0] PrivilegeModeW,
|
||||
@ -68,7 +69,7 @@ module mmu #(parameter ENTRY_BITS = 3,
|
||||
|
||||
// PMA checker signals
|
||||
input logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM,
|
||||
input var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
input var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
input var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
|
||||
|
||||
output logic SquashBusAccess, // *** send to privileged unit
|
||||
|
@ -32,9 +32,6 @@ module pmachecker (
|
||||
|
||||
input logic [`PA_BITS-1:0] PhysicalAddress,
|
||||
input logic [1:0] Size,
|
||||
// input logic [31:0] HADDR,
|
||||
// input logic [2:0] HSIZE,
|
||||
// input logic [2:0] HBURST, // *** in AHBlite, HBURST is hardwired to zero for single bursts only allowed. consider removing from this module if unused.
|
||||
|
||||
input logic AtomicAccessM, ExecuteAccessF, WriteAccessM, ReadAccessM, // *** atomicaccessM is unused but might want to stay in for future use.
|
||||
|
||||
@ -46,10 +43,9 @@ module pmachecker (
|
||||
output logic PMAStoreAccessFaultM
|
||||
);
|
||||
|
||||
// logic BootTim, Tim, CLINT, GPIO, UART, PLIC;
|
||||
logic PMAAccessFault;
|
||||
logic AccessRW, AccessRWX, AccessRX;
|
||||
logic [5:0] SelRegions;
|
||||
logic [6:0] SelRegions;
|
||||
|
||||
// Determine what type of access is being made
|
||||
assign AccessRW = ReadAccessM | WriteAccessM;
|
||||
|
@ -31,35 +31,42 @@
|
||||
|
||||
module pmpadrdec (
|
||||
input logic [`PA_BITS-1:0] PhysicalAddress,
|
||||
// input logic [31:0] HADDR, // *** replace with PAdr
|
||||
input logic [1:0] AdrMode,
|
||||
input logic [`XLEN-1:0] CurrentPMPAdr,
|
||||
input logic AdrAtLeastPreviousPMP,
|
||||
output logic AdrAtLeastCurrentPMP,
|
||||
output logic Match
|
||||
input logic [7:0] PMPCfg,
|
||||
input logic [`XLEN-1:0] PMPAdr,
|
||||
input logic PAgePMPAdrIn,
|
||||
input logic NoLowerMatchIn,
|
||||
output logic PAgePMPAdrOut,
|
||||
output logic NoLowerMatchOut,
|
||||
output logic Match, Active,
|
||||
output logic L, X, W, R
|
||||
);
|
||||
|
||||
|
||||
localparam TOR = 2'b01;
|
||||
localparam NA4 = 2'b10;
|
||||
localparam NAPOT = 2'b11;
|
||||
|
||||
logic TORMatch, NAMatch;
|
||||
logic AdrBelowCurrentPMP;
|
||||
logic PAltPMPAdr;
|
||||
logic FirstMatch;
|
||||
logic [`PA_BITS-1:0] CurrentAdrFull;
|
||||
// logic [`PA_BITS-1:0] FakePhysAdr;
|
||||
logic [1:0] AdrMode;
|
||||
|
||||
// ***replace this when the true physical address from MMU is available
|
||||
// assign FakePhysAdr = {{(`PA_BITS-32){1'b0}}, HADDR};
|
||||
|
||||
assign AdrMode = PMPCfg[4:3];
|
||||
|
||||
// The two lsb of the physical address don't matter for this checking.
|
||||
// The following code includes them, but hardwires the PMP checker lsbs to 00
|
||||
// and masks them later. Logic synthesis should optimize away these bottom bits.
|
||||
|
||||
// Top-of-range (TOR)
|
||||
// Append two implicit trailing 0's to PMPAdr value
|
||||
assign CurrentAdrFull = {CurrentPMPAdr[`PA_BITS-3:0], 2'b00};
|
||||
assign AdrBelowCurrentPMP = PhysicalAddress < CurrentAdrFull; // *** make sure unsigned comparison works correctly
|
||||
assign AdrAtLeastCurrentPMP = ~AdrBelowCurrentPMP;
|
||||
assign TORMatch = AdrAtLeastPreviousPMP && AdrBelowCurrentPMP;
|
||||
assign CurrentAdrFull = {PMPAdr[`PA_BITS-3:0], 2'b00};
|
||||
assign PAltPMPAdr = {1'b0, PhysicalAddress} < {1'b0, CurrentAdrFull}; // unsigned comparison
|
||||
assign PAgePMPAdrOut = ~PAltPMPAdr;
|
||||
assign TORMatch = PAgePMPAdrIn && PAltPMPAdr;
|
||||
|
||||
// Naturally aligned regions
|
||||
// *** should be able to optimize away bottom 2 bits
|
||||
|
||||
// verilator lint_off UNOPTFLAT
|
||||
logic [`PA_BITS-1:0] Mask;
|
||||
@ -70,69 +77,22 @@ module pmpadrdec (
|
||||
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)
|
||||
assign Mask[i] = Mask[i-1] & CurrentPMPAdr[i-3]; // NAPOT mask: 1's indicate bits to ignore
|
||||
assign Mask[i] = Mask[i-1] & PMPAdr[i-3]; // NAPOT mask: 1's indicate bits to ignore
|
||||
endgenerate
|
||||
// verilator lint_on UNOPTFLAT
|
||||
|
||||
assign NAMatch = &((PhysicalAddress ~^ CurrentAdrFull) | Mask);
|
||||
|
||||
/* generate
|
||||
if (`XLEN == 32 || `XLEN == 64) begin // ***redo for various sizes
|
||||
// priority encoder to translate address to range
|
||||
// *** We'd like to replace this with a better priority encoder
|
||||
// *** We should not be truncating 64 bit physical addresses to 32 bits...
|
||||
// *** there is an easy combinatinoal way to do this with a cascade of AND gates O(32) rather than O(32^2) dh
|
||||
always_comb
|
||||
if (AdrMode == NA4) Range = (2**2) - 1;
|
||||
else casez (CurrentPMPAdr[31:0]) // NAPOT regions
|
||||
32'b???????????????????????????????0: Range = (2**3) - 1;
|
||||
32'b??????????????????????????????01: Range = (2**4) - 1;
|
||||
32'b?????????????????????????????011: Range = (2**5) - 1;
|
||||
32'b????????????????????????????0111: Range = (2**6) - 1;
|
||||
32'b???????????????????????????01111: Range = (2**7) - 1;
|
||||
32'b??????????????????????????011111: Range = (2**8) - 1;
|
||||
32'b?????????????????????????0111111: Range = (2**9) - 1;
|
||||
32'b????????????????????????01111111: Range = (2**10) - 1;
|
||||
32'b???????????????????????011111111: Range = (2**11) - 1;
|
||||
32'b??????????????????????0111111111: Range = (2**12) - 1;
|
||||
32'b?????????????????????01111111111: Range = (2**13) - 1;
|
||||
32'b????????????????????011111111111: Range = (2**14) - 1;
|
||||
32'b???????????????????0111111111111: Range = (2**15) - 1;
|
||||
32'b??????????????????01111111111111: Range = (2**16) - 1;
|
||||
32'b?????????????????011111111111111: Range = (2**17) - 1;
|
||||
32'b????????????????0111111111111111: Range = (2**18) - 1;
|
||||
32'b???????????????01111111111111111: Range = (2**19) - 1;
|
||||
32'b??????????????011111111111111111: Range = (2**20) - 1;
|
||||
32'b?????????????0111111111111111111: Range = (2**21) - 1;
|
||||
32'b????????????01111111111111111111: Range = (2**22) - 1;
|
||||
32'b???????????011111111111111111111: Range = (2**23) - 1;
|
||||
32'b??????????0111111111111111111111: Range = (2**24) - 1;
|
||||
32'b?????????01111111111111111111111: Range = (2**25) - 1;
|
||||
32'b????????011111111111111111111111: Range = (2**26) - 1;
|
||||
32'b???????0111111111111111111111111: Range = (2**27) - 1;
|
||||
32'b??????01111111111111111111111111: Range = (2**28) - 1;
|
||||
32'b?????011111111111111111111111111: Range = (2**29) - 1;
|
||||
32'b????0111111111111111111111111111: Range = (2**30) - 1;
|
||||
32'b???01111111111111111111111111111: Range = (2**31) - 1;
|
||||
32'b??011111111111111111111111111111: Range = (2**32) - 1;
|
||||
32'b?0111111111111111111111111111111: Range = (2**33) - 1;
|
||||
32'b01111111111111111111111111111111: Range = (2**34) - 1;
|
||||
32'b11111111111111111111111111111111: Range = (2**35) - 1;
|
||||
default: Range = '0;
|
||||
endcase
|
||||
end else begin
|
||||
assign Range = '0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// *** Range should not be truncated... but our physical address space is
|
||||
// currently only 32 bits wide.
|
||||
// with a bit of combining of range selection, this could be shared with NA4Match ***
|
||||
assign NAMatch = &((HADDR ~^ CurrentAdrFull) | Range[31:0]);*/
|
||||
|
||||
assign Match = (AdrMode == TOR) ? TORMatch :
|
||||
(AdrMode == NA4 || AdrMode == NAPOT) ? NAMatch :
|
||||
0;
|
||||
|
||||
endmodule
|
||||
assign FirstMatch = NoLowerMatchIn & Match;
|
||||
assign NoLowerMatchOut = NoLowerMatchIn & ~Match;
|
||||
assign L = PMPCfg[7] & FirstMatch;
|
||||
assign X = PMPCfg[2] & FirstMatch;
|
||||
assign W = PMPCfg[1] & FirstMatch;
|
||||
assign R = PMPCfg[0] & FirstMatch;
|
||||
assign Active = |PMPCfg[4:3];
|
||||
endmodule
|
||||
|
||||
|
@ -29,12 +29,8 @@
|
||||
`include "wally-config.vh"
|
||||
|
||||
module pmpchecker (
|
||||
// input logic clk, reset, //*** it seems like clk, reset is also not needed here?
|
||||
input logic [`PA_BITS-1:0] PhysicalAddress,
|
||||
// input logic [31:0] HADDR,
|
||||
|
||||
input logic [1:0] PrivilegeModeW,
|
||||
|
||||
input logic [1:0] PrivilegeModeW,
|
||||
|
||||
// *** ModelSim has a switch -svinputport which controls whether input ports
|
||||
// are nets (wires) or vars by default. The default setting of this switch is
|
||||
@ -43,11 +39,7 @@ module pmpchecker (
|
||||
// this will be understood as a var. However, if we don't supply the `var`
|
||||
// keyword, the compiler warns us that it's interpreting the signal as a var,
|
||||
// which we might not intend.
|
||||
// However, it's still bad form to pass 512 or 1024 signals across a module
|
||||
// boundary. It would be better to store the PMP address registers in a module
|
||||
// somewhere in the CSR hierarchy and do PMP checking _within_ that module, so
|
||||
// we don't have to pass around 16 whole registers.
|
||||
input var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
input var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
input var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
|
||||
|
||||
input logic ExecuteAccessF, WriteAccessM, ReadAccessM,
|
||||
@ -59,111 +51,42 @@ module pmpchecker (
|
||||
output logic PMPStoreAccessFaultM
|
||||
);
|
||||
|
||||
|
||||
// Bit i is high when the address falls in PMP region i
|
||||
logic [`PMP_ENTRIES-1:0] Regions, FirstMatch;
|
||||
//logic [3:0] MatchedRegion;
|
||||
logic EnforcePMP;
|
||||
|
||||
logic [7:0] PMPCFG [`PMP_ENTRIES-1:0];
|
||||
|
||||
// Bit i is high when the address is greater than or equal to PMPADR[i]
|
||||
// Used for determining whether TOR PMP regions match
|
||||
logic [`PMP_ENTRIES-1:0] AboveRegion;
|
||||
|
||||
// Bit i is high if PMP register i is non-null
|
||||
logic [`PMP_ENTRIES-1:0] ActiveRegion;
|
||||
|
||||
logic [`PMP_ENTRIES-1:0] L_Bits, X_Bits, W_Bits, R_Bits;
|
||||
//logic InvalidExecute, InvalidWrite, InvalidRead;
|
||||
|
||||
genvar i,j;
|
||||
|
||||
pmpadrdec pmpadrdec(.PhysicalAddress(PhysicalAddress),
|
||||
.AdrMode(PMPCFG[0][4:3]),
|
||||
.CurrentPMPAdr(PMPADDR_ARRAY_REGW[0]),
|
||||
.AdrAtLeastPreviousPMP(1'b1),
|
||||
.AdrAtLeastCurrentPMP(AboveRegion[0]),
|
||||
.Match(Regions[0]));
|
||||
|
||||
assign ActiveRegion[0] = |PMPCFG[0][4:3];
|
||||
|
||||
generate // *** only for PMP_ENTRIES > 0
|
||||
for (i = 1; i < `PMP_ENTRIES; i++) begin
|
||||
pmpadrdec pmpadrdec(.PhysicalAddress(PhysicalAddress),
|
||||
.AdrMode(PMPCFG[i][4:3]),
|
||||
.CurrentPMPAdr(PMPADDR_ARRAY_REGW[i]),
|
||||
.AdrAtLeastPreviousPMP(AboveRegion[i-1]),
|
||||
.AdrAtLeastCurrentPMP(AboveRegion[i]),
|
||||
.Match(Regions[i]));
|
||||
|
||||
assign ActiveRegion[i] = |PMPCFG[i][4:3];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//assign Match = |Regions;
|
||||
|
||||
logic EnforcePMP;
|
||||
logic [7:0] PMPCfg[`PMP_ENTRIES-1:0];
|
||||
logic [`PMP_ENTRIES-1:0] Match; // 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;
|
||||
// assign NoLowerMatch[0] = 1;
|
||||
generate
|
||||
// verilator lint_off WIDTH
|
||||
for (j=0; j<`PMP_ENTRIES; j = j+8) begin
|
||||
assign {PMPCFG[j+7], PMPCFG[j+6], PMPCFG[j+5], PMPCFG[j+4],
|
||||
PMPCFG[j+3], PMPCFG[j+2], PMPCFG[j+1], PMPCFG[j]} = PMPCFG_ARRAY_REGW[j/8];
|
||||
end
|
||||
// verilator lint_on WIDTH
|
||||
for (i=0; i<`PMP_ENTRIES; i++) begin
|
||||
if (i==0) begin
|
||||
assign FirstMatch[i] = Regions[i];
|
||||
assign NoLowerMatch[i] = ~Regions[i];
|
||||
end else begin
|
||||
assign FirstMatch[i] = Regions[i] & NoLowerMatch[i];
|
||||
assign NoLowerMatch[i] = NoLowerMatch[i-1] & ~Regions[i];
|
||||
end
|
||||
assign L_Bits[i] = PMPCFG[i][7] & FirstMatch[i];
|
||||
assign X_Bits[i] = PMPCFG[i][2] & FirstMatch[i];
|
||||
assign W_Bits[i] = PMPCFG[i][1] & FirstMatch[i];
|
||||
assign R_Bits[i] = PMPCFG[i][0] & FirstMatch[i];
|
||||
end
|
||||
// verilator lint_on UNOPTFLAT
|
||||
endgenerate
|
||||
/* // *** extend to up to 64, fold bit extraction to avoid need for binary encoding of region
|
||||
always_comb
|
||||
casez (Regions)
|
||||
16'b???????????????1: MatchedRegion = 0;
|
||||
16'b??????????????10: MatchedRegion = 1;
|
||||
16'b?????????????100: MatchedRegion = 2;
|
||||
16'b????????????1000: MatchedRegion = 3;
|
||||
16'b???????????10000: MatchedRegion = 4;
|
||||
16'b??????????100000: MatchedRegion = 5;
|
||||
16'b?????????1000000: MatchedRegion = 6;
|
||||
16'b????????10000000: MatchedRegion = 7;
|
||||
16'b???????100000000: MatchedRegion = 8;
|
||||
16'b??????1000000000: MatchedRegion = 9;
|
||||
16'b?????10000000000: MatchedRegion = 10;
|
||||
16'b????100000000000: MatchedRegion = 11;
|
||||
16'b???1000000000000: MatchedRegion = 12;
|
||||
16'b??10000000000000: MatchedRegion = 13;
|
||||
16'b?100000000000000: MatchedRegion = 14;
|
||||
16'b1000000000000000: MatchedRegion = 15;
|
||||
default: MatchedRegion = 0; // Should only occur if there is no match
|
||||
endcase
|
||||
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;
|
||||
/*
|
||||
generate // extract 8-bit chunks from PMPCFG array
|
||||
for (j=0; j<`PMP_ENTRIES; j = j+8)
|
||||
assign {PMPCfg[j+7], PMPCfg[j+6], PMPCfg[j+5], PMPCfg[j+4],
|
||||
PMPCfg[j+3], PMPCfg[j+2], PMPCfg[j+1], PMPCfg[j]} = PMPCFG_ARRAY_REGW[j/8];
|
||||
endgenerate */
|
||||
|
||||
assign L_Bit = PMPCFG[MatchedRegion][7] && Match;
|
||||
assign X_Bit = PMPCFG[MatchedRegion][2] && Match;
|
||||
assign W_Bit = PMPCFG[MatchedRegion][1] && Match;
|
||||
assign R_Bit = PMPCFG[MatchedRegion][0] && Match;
|
||||
pmpadrdec pmpadrdecs[`PMP_ENTRIES-1:0](
|
||||
.PhysicalAddress,
|
||||
.PMPCfg(PMPCFG_ARRAY_REGW),
|
||||
.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);
|
||||
|
||||
assign InvalidExecute = ExecuteAccessF && ~X_Bit;
|
||||
assign InvalidWrite = WriteAccessM && ~W_Bit;
|
||||
assign InvalidRead = ReadAccessM && ~R_Bit;*/
|
||||
|
||||
// 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_Bits : |ActiveRegion;
|
||||
assign EnforcePMP = (PrivilegeModeW == `M_MODE) ? |L : |Active;
|
||||
|
||||
assign PMPInstrAccessFaultF = EnforcePMP && ExecuteAccessF && ~|X_Bits;
|
||||
assign PMPStoreAccessFaultM = EnforcePMP && WriteAccessM && ~|W_Bits;
|
||||
assign PMPLoadAccessFaultM = EnforcePMP && ReadAccessM && ~|R_Bits;
|
||||
assign PMPInstrAccessFaultF = EnforcePMP && ExecuteAccessF && ~|X;
|
||||
assign PMPStoreAccessFaultM = EnforcePMP && WriteAccessM && ~|W;
|
||||
assign PMPLoadAccessFaultM = EnforcePMP && ReadAccessM && ~|R;
|
||||
|
||||
assign PMPSquashBusAccess = PMPInstrAccessFaultF | PMPLoadAccessFaultM | PMPStoreAccessFaultM;
|
||||
|
||||
|
@ -55,7 +55,8 @@ module tlb #(parameter ENTRY_BITS = 3,
|
||||
|
||||
// Current value of satp CSR (from privileged unit)
|
||||
input logic [`XLEN-1:0] SATP_REGW,
|
||||
input logic STATUS_MXR, STATUS_SUM,
|
||||
input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
input logic [1:0] STATUS_MPP,
|
||||
|
||||
// Current privilege level of the processeor
|
||||
input logic [1:0] PrivilegeModeW,
|
||||
@ -87,20 +88,23 @@ module tlb #(parameter ENTRY_BITS = 3,
|
||||
output logic TLBPageFault
|
||||
);
|
||||
|
||||
localparam NENTRIES = 2**ENTRY_BITS;
|
||||
|
||||
logic Translate;
|
||||
logic TLBAccess, ReadAccess, WriteAccess;
|
||||
|
||||
// Store current virtual memory mode (SV32, SV39, SV48, ect...)
|
||||
logic [`SVMODE_BITS-1:0] SvMode;
|
||||
logic [1:0] EffectivePrivilegeMode; // privilege mode, possibly modified by MPRV
|
||||
|
||||
// Index (currently random) to write the next TLB entry
|
||||
logic [ENTRY_BITS-1:0] WriteIndex;
|
||||
logic [(2**ENTRY_BITS)-1:0] WriteLines; // used as the one-hot encoding of WriteIndex
|
||||
//logic [ENTRY_BITS-1:0] WriteIndex;
|
||||
logic [NENTRIES-1:0] ReadLines, WriteLines, WriteEnables; // used as the one-hot encoding of WriteIndex
|
||||
|
||||
// Sections of the virtual and physical addresses
|
||||
logic [`VPN_BITS-1:0] VirtualPageNumber;
|
||||
logic [`PPN_BITS-1:0] PhysicalPageNumber, PhysicalPageNumberMixed;
|
||||
logic [`PA_BITS-1:0] PhysicalAddressFull;
|
||||
logic [`XLEN+1:0] VAExt;
|
||||
|
||||
// Sections of the page table entry
|
||||
logic [7:0] PTEAccessBits;
|
||||
@ -110,17 +114,20 @@ module tlb #(parameter ENTRY_BITS = 3,
|
||||
logic PTE_U, PTE_X, PTE_W, PTE_R;
|
||||
|
||||
// Pattern location in the CAM and type of page hit
|
||||
logic [ENTRY_BITS-1:0] VPNIndex;
|
||||
//ogic [ENTRY_BITS-1:0] VPNIndex;
|
||||
logic [1:0] HitPageType;
|
||||
|
||||
// Whether the virtual address has a match in the CAM
|
||||
logic CAMHit;
|
||||
|
||||
// Grab the sv mode from SATP
|
||||
// Grab the sv mode from SATP and determine whether translation should occur
|
||||
assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS];
|
||||
assign EffectivePrivilegeMode = (ITLB == 1) ? PrivilegeModeW : (STATUS_MPRV ? STATUS_MPP : PrivilegeModeW); // DTLB uses MPP mode when MPRV is 1
|
||||
assign Translate = (SvMode != `NO_TRANSLATE) & (EffectivePrivilegeMode != `M_MODE) & ~ DisableTranslation;
|
||||
|
||||
// Decode the integer encoded WriteIndex into the one-hot encoded WriteLines
|
||||
decoder #(ENTRY_BITS) writedecoder(WriteIndex, WriteLines);
|
||||
//decoder #(ENTRY_BITS) writedecoder(WriteIndex, WriteLines);
|
||||
assign WriteEnables = WriteLines & {(2**ENTRY_BITS){TLBWrite}};
|
||||
|
||||
// The bus width is always the largest it could be for that XLEN. For example, vpn will be 36 bits wide in rv64
|
||||
// this, even though it could be 27 bits (SV39) or 36 bits (SV48) wide. When the value of VPN is narrower,
|
||||
@ -135,79 +142,64 @@ module tlb #(parameter ENTRY_BITS = 3,
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Whether translation should occur
|
||||
assign Translate = (SvMode != `NO_TRANSLATE) & (PrivilegeModeW != `M_MODE) & ~ DisableTranslation;
|
||||
|
||||
|
||||
// Determine how the TLB is currently being used
|
||||
// Note that we use ReadAccess for both loads and instruction fetches
|
||||
assign ReadAccess = TLBAccessType[1];
|
||||
assign WriteAccess = TLBAccessType[0];
|
||||
assign TLBAccess = ReadAccess || WriteAccess;
|
||||
|
||||
|
||||
assign PageOffset = VirtualAddress[11:0];
|
||||
|
||||
// TLB entries are evicted according to the LRU algorithm
|
||||
tlblru #(ENTRY_BITS) lru(.*);
|
||||
|
||||
// TLB memory
|
||||
tlbram #(ENTRY_BITS) tlbram(.*);
|
||||
tlbcam #(ENTRY_BITS, `VPN_BITS, `VPN_SEGMENT_BITS) tlbcam(.*);
|
||||
|
||||
// unswizzle useful PTE bits
|
||||
assign PTE_U = PTEAccessBits[4];
|
||||
assign PTE_X = PTEAccessBits[3];
|
||||
assign PTE_W = PTEAccessBits[2];
|
||||
assign PTE_R = PTEAccessBits[1];
|
||||
// Replace segments of the virtual page number with segments of the physical
|
||||
// page number. For 4 KB pages, the entire virtual page number is replaced.
|
||||
// For superpages, some segments are considered offsets into a larger page.
|
||||
tlbphysicalpagemask PageMask(VirtualPageNumber, PhysicalPageNumber, HitPageType, PhysicalPageNumberMixed);
|
||||
|
||||
// unswizzle useful PTE bits
|
||||
assign {PTE_U, PTE_X, PTE_W, PTE_R} = PTEAccessBits[4:1];
|
||||
|
||||
// Check whether the access is allowed, page faulting if not.
|
||||
// *** We might not have S mode.
|
||||
generate
|
||||
if (ITLB == 1) begin
|
||||
logic ImproperPrivilege;
|
||||
|
||||
// User mode may only execute user mode pages, and supervisor mode may
|
||||
// only execute non-user mode pages.
|
||||
assign ImproperPrivilege = ((PrivilegeModeW == `U_MODE) && ~PTE_U) ||
|
||||
((PrivilegeModeW == `S_MODE) && PTE_U);
|
||||
assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) && ~PTE_U) ||
|
||||
((EffectivePrivilegeMode == `S_MODE) && PTE_U);
|
||||
assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || ~PTE_X);
|
||||
end else begin
|
||||
logic ImproperPrivilege, InvalidRead, InvalidWrite;
|
||||
|
||||
// User mode may only load/store from user mode pages, and supervisor mode
|
||||
// may only access user mode pages when STATUS_SUM is low.
|
||||
assign ImproperPrivilege = ((PrivilegeModeW == `U_MODE) && ~PTE_U) ||
|
||||
((PrivilegeModeW == `S_MODE) && PTE_U && ~STATUS_SUM);
|
||||
assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) && ~PTE_U) ||
|
||||
((EffectivePrivilegeMode == `S_MODE) && PTE_U && ~STATUS_SUM);
|
||||
// Check for read error. Reads are invalid when the page is not readable
|
||||
// (and executable pages are not readable) or when the page is neither
|
||||
// readable nor executable (and executable pages are readable).
|
||||
assign InvalidRead = ReadAccess &&
|
||||
((~STATUS_MXR && ~PTE_R) || (STATUS_MXR && ~PTE_R && PTE_X));
|
||||
assign InvalidRead = ReadAccess && ~PTE_R && (~STATUS_MXR | ~PTE_X);
|
||||
// Check for write error. Writes are invalid when the page's write bit is
|
||||
// low.
|
||||
assign InvalidWrite = WriteAccess && ~PTE_W;
|
||||
assign TLBPageFault = Translate && TLBHit &&
|
||||
(ImproperPrivilege || InvalidRead || InvalidWrite);
|
||||
assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || InvalidRead || InvalidWrite);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Replace segments of the virtual page number with segments of the physical
|
||||
// page number. For 4 KB pages, the entire virtual page number is replaced.
|
||||
// For superpages, some segments are considered offsets into a larger page.
|
||||
physicalpagemask PageNumberMixer(VirtualPageNumber, PhysicalPageNumber, HitPageType, PhysicalPageNumberMixed);
|
||||
|
||||
// Provide physical address only on TLBHits to cause catastrophic errors if
|
||||
// garbage address is used.
|
||||
assign PhysicalAddressFull = (TLBHit) ?
|
||||
{PhysicalPageNumberMixed, PageOffset} : '0;
|
||||
|
||||
// Output the hit physical address if translation is currently on.
|
||||
generate
|
||||
if (`XLEN == 32) begin
|
||||
mux2 #(`PA_BITS) addressmux({2'b0, VirtualAddress}, PhysicalAddressFull, Translate, PhysicalAddress);
|
||||
end else begin
|
||||
mux2 #(`PA_BITS) addressmux(VirtualAddress[`PA_BITS-1:0], PhysicalAddressFull, Translate, PhysicalAddress);
|
||||
end
|
||||
endgenerate
|
||||
// Provide physical address of zero if not TLBHits, to cause segmentation error if miss somehow percolated through signal
|
||||
assign VAExt = {2'b00, VirtualAddress}; // extend length of virtual address if necessary for RV32
|
||||
assign PageOffset = VirtualAddress[11:0];
|
||||
assign PhysicalAddressFull = TLBHit ? {PhysicalPageNumberMixed, PageOffset} : '0;
|
||||
mux2 #(`PA_BITS) addressmux(VAExt[`PA_BITS-1:0], PhysicalAddressFull, Translate, PhysicalAddress);
|
||||
|
||||
assign TLBHit = CAMHit & TLBAccess;
|
||||
assign TLBMiss = ~TLBHit & ~TLBFlush & Translate & TLBAccess;
|
||||
|
@ -34,20 +34,18 @@ module tlbcam #(parameter ENTRY_BITS = 3,
|
||||
input logic clk, reset,
|
||||
input logic [KEY_BITS-1:0] VirtualPageNumber,
|
||||
input logic [1:0] PageTypeWriteVal,
|
||||
// input logic [`SVMODE_BITS-1:0] SvMode, // *** may not need to be used.
|
||||
input logic TLBWrite,
|
||||
input logic TLBFlush,
|
||||
input logic [2**ENTRY_BITS-1:0] WriteLines,
|
||||
input logic [2**ENTRY_BITS-1:0] WriteEnables,
|
||||
|
||||
output logic [ENTRY_BITS-1:0] VPNIndex,
|
||||
//output logic [ENTRY_BITS-1:0] VPNIndex,
|
||||
output logic [2**ENTRY_BITS-1:0] ReadLines,
|
||||
output logic [1:0] HitPageType,
|
||||
output logic CAMHit
|
||||
);
|
||||
|
||||
localparam NENTRIES = 2**ENTRY_BITS;
|
||||
|
||||
|
||||
logic [1:0] PageTypeList [NENTRIES-1:0];
|
||||
logic [1:0] PageTypeRead [NENTRIES-1:0];
|
||||
logic [NENTRIES-1:0] Matches;
|
||||
|
||||
// Create NENTRIES CAM lines, each of which will independently consider
|
||||
@ -55,23 +53,19 @@ module tlbcam #(parameter ENTRY_BITS = 3,
|
||||
// original virtual page number from when the address was written, regardless
|
||||
// of page type. However, matches are determined based on a subset of the
|
||||
// page number segments.
|
||||
generate
|
||||
genvar i;
|
||||
for (i = 0; i < NENTRIES; i++) begin
|
||||
camline #(KEY_BITS, SEGMENT_BITS) camline(
|
||||
.CAMLineWrite(WriteLines[i] && TLBWrite),
|
||||
.PageType(PageTypeList[i]),
|
||||
.Match(Matches[i]),
|
||||
.*);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
tlbcamline #(KEY_BITS, SEGMENT_BITS) camlines[NENTRIES-1:0](
|
||||
.WriteEnable(WriteEnables),
|
||||
.PageTypeRead, // *** change name to agree
|
||||
.Match(ReadLines), // *** change name to agree
|
||||
.*);
|
||||
|
||||
// In case there are multiple matches in the CAM, select only one
|
||||
// *** it might be guaranteed that the CAM will never have multiple matches.
|
||||
// If so, this is just an encoder
|
||||
priorityencoder #(ENTRY_BITS) matchencoder(Matches, VPNIndex);
|
||||
//priorityencoder #(ENTRY_BITS) matchencoder(Matches, VPNIndex);
|
||||
|
||||
assign CAMHit = |Matches & ~TLBFlush;
|
||||
assign HitPageType = PageTypeList[VPNIndex];
|
||||
assign CAMHit = |ReadLines & ~TLBFlush;
|
||||
assign HitPageType = PageTypeRead.or; // applies OR to elements of the (NENTRIES x 2) array to get 2-bit result
|
||||
|
||||
endmodule
|
||||
|
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////
|
||||
// camline.sv
|
||||
// tlbcamline.sv
|
||||
//
|
||||
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 6 April 2021
|
||||
// Modified: kmacsaigoren@hmc.edu 1 June 2021
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module camline #(parameter KEY_BITS = 20,
|
||||
module tlbcamline #(parameter KEY_BITS = 20,
|
||||
parameter SEGMENT_BITS = 10) (
|
||||
input logic clk, reset,
|
||||
|
||||
@ -39,7 +39,7 @@ module camline #(parameter KEY_BITS = 20,
|
||||
input logic [KEY_BITS-1:0] VirtualPageNumber,
|
||||
|
||||
// Signals to write a new entry to this line
|
||||
input logic CAMLineWrite,
|
||||
input logic WriteEnable,
|
||||
input logic [1:0] PageTypeWriteVal,
|
||||
|
||||
// Flush this line (set valid to 0)
|
||||
@ -50,19 +50,21 @@ module camline #(parameter KEY_BITS = 20,
|
||||
// PageType == 2'b01 --> megapage
|
||||
// PageType == 2'b10 --> gigapage
|
||||
// PageType == 2'b11 --> terapage
|
||||
output logic [1:0] PageType, // *** should this be the stored version or the always updated one?
|
||||
output logic [1:0] PageTypeRead, // *** should this be the stored version or the always updated one?
|
||||
output logic Match
|
||||
);
|
||||
|
||||
// This entry has KEY_BITS for the key plus one valid bit.
|
||||
logic Valid;
|
||||
logic [KEY_BITS-1:0] Key;
|
||||
logic [1:0] PageType;
|
||||
|
||||
|
||||
// Split up key and query into sections for each page table level.
|
||||
logic [SEGMENT_BITS-1:0] Key0, Key1, Query0, Query1;
|
||||
logic Match0, Match1;
|
||||
|
||||
// *** need to add ASID and G bit support
|
||||
|
||||
generate
|
||||
if (`XLEN == 32) begin
|
||||
|
||||
@ -85,26 +87,26 @@ module camline #(parameter KEY_BITS = 20,
|
||||
assign {Key3, Key2, Key1, Key0} = Key;
|
||||
|
||||
// Calculate the actual match value based on the input vpn and the page type.
|
||||
// For example, a gigapage in SV only cares about VPN[2], so VPN[0] and VPN[1]
|
||||
// For example, a gigapage in SV39 only cares about VPN[2], so VPN[0] and VPN[1]
|
||||
// should automatically match.
|
||||
assign Match0 = (Query0 == Key0) || (PageType > 2'd0); // least signifcant section
|
||||
assign Match1 = (Query1 == Key1) || (PageType > 2'd1);
|
||||
assign Match2 = (Query2 == Key2) || (PageType > 2'd2);
|
||||
assign Match3 = (Query3 == Key3); // *** this should always match in sv39 since both vPN3 and key3 are zeroed by the pagetable walker before getting to the cam
|
||||
assign Match3 = (Query3 == Key3); // this should always match in sv39 since both vPN3 and key3 are zeroed by the pagetable walker before getting to the cam
|
||||
|
||||
assign Match = Match0 & Match1 & Match2 & Match3 & Valid;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// On a write, update the type of the page referred to by this line.
|
||||
flopenr #(2) pagetypeflop(clk, reset, CAMLineWrite, PageTypeWriteVal, PageType);
|
||||
//mux2 #(2) pagetypemux(StoredPageType, PageTypeWrite, CAMLineWrite, PageType);
|
||||
flopenr #(2) pagetypeflop(clk, reset, WriteEnable, PageTypeWriteVal, PageType);
|
||||
assign PageTypeRead = PageType & {2{Match}};
|
||||
|
||||
// On a write, set the valid bit high and update the stored key.
|
||||
// On a flush, zero the valid bit and leave the key unchanged.
|
||||
// *** Might we want to update stored key right away to output match on the
|
||||
// write cycle? (using a mux)
|
||||
flopenrc #(1) validbitflop(clk, reset, TLBFlush, CAMLineWrite, 1'b1, Valid);
|
||||
flopenr #(KEY_BITS) keyflop(clk, reset, CAMLineWrite, VirtualPageNumber, Key);
|
||||
flopenrc #(1) validbitflop(clk, reset, TLBFlush, WriteEnable, 1'b1, Valid);
|
||||
flopenr #(KEY_BITS) keyflop(clk, reset, WriteEnable, VirtualPageNumber, Key);
|
||||
|
||||
endmodule
|
@ -28,11 +28,9 @@ module tlblru #(parameter ENTRY_BITS = 3) (
|
||||
input logic clk, reset,
|
||||
input logic TLBWrite,
|
||||
input logic TLBFlush,
|
||||
input logic [ENTRY_BITS-1:0] VPNIndex,
|
||||
input logic [2**ENTRY_BITS-1:0] ReadLines,
|
||||
input logic CAMHit,
|
||||
input logic [2**ENTRY_BITS-1:0] WriteLines,
|
||||
|
||||
output logic [ENTRY_BITS-1:0] WriteIndex
|
||||
output logic [2**ENTRY_BITS-1:0] WriteLines
|
||||
);
|
||||
|
||||
localparam NENTRIES = 2**ENTRY_BITS;
|
||||
@ -41,29 +39,19 @@ module tlblru #(parameter ENTRY_BITS = 3) (
|
||||
logic [NENTRIES-1:0] RUBits, RUBitsNext, RUBitsAccessed;
|
||||
|
||||
// One-hot encodings of which line is being accessed
|
||||
logic [NENTRIES-1:0] ReadLineOneHot, AccessLineOneHot;
|
||||
logic [NENTRIES-1:0] AccessLines;
|
||||
|
||||
// High if the next access causes all RU bits to be 1
|
||||
logic AllUsed;
|
||||
|
||||
// Convert indices to one-hot encodings
|
||||
decoder #(ENTRY_BITS) readdecoder(VPNIndex, ReadLineOneHot);
|
||||
|
||||
// Find the first line not recently used
|
||||
priorityencoder #(ENTRY_BITS) firstnru(~RUBits, WriteIndex);
|
||||
tlbpriority #(NENTRIES) nru(~RUBits, WriteLines);
|
||||
|
||||
// Access either the hit line or written line
|
||||
assign AccessLineOneHot = (TLBWrite) ? WriteLines : ReadLineOneHot;
|
||||
|
||||
// Raise the bit of the recently accessed line
|
||||
assign RUBitsAccessed = AccessLineOneHot | RUBits;
|
||||
|
||||
// Determine whether we need to reset the RU bits to all zeroes
|
||||
assign AllUsed = &(RUBitsAccessed);
|
||||
assign RUBitsNext = (AllUsed) ? AccessLineOneHot : RUBitsAccessed;
|
||||
|
||||
// Update LRU state on any TLB hit or write
|
||||
flopenrc #(NENTRIES) lrustate(clk, reset, TLBFlush, (CAMHit || TLBWrite),
|
||||
RUBitsNext, RUBits);
|
||||
// Track recently used lines, updating on a CAM Hit or TLB write
|
||||
assign AccessLines = TLBWrite ? WriteLines : ReadLines;
|
||||
assign RUBitsAccessed = AccessLines | RUBits;
|
||||
assign AllUsed = &RUBitsAccessed; // if all recently used, then clear to none
|
||||
assign RUBitsNext = AllUsed ? 0 : RUBitsAccessed;
|
||||
flopenrc #(NENTRIES) lrustate(clk, reset, TLBFlush, (CAMHit || TLBWrite), RUBitsNext, RUBits);
|
||||
|
||||
endmodule
|
||||
|
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////
|
||||
// physicalpagemask.sv
|
||||
// tlbphysicalpagemask.sv
|
||||
//
|
||||
// Written: David Harris and kmacsaigoren@hmc.edu 7 June 2021
|
||||
// Modified:
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module physicalpagemask (
|
||||
module tlbphysicalpagemask (
|
||||
input logic [`VPN_BITS-1:0] VPN,
|
||||
input logic [`PPN_BITS-1:0] PPN,
|
||||
input logic [1:0] PageType,
|
||||
@ -40,13 +40,11 @@ module physicalpagemask (
|
||||
logic [`PPN_BITS-1:0] ZeroExtendedVPN;
|
||||
logic [`PPN_BITS-1:0] PageNumberMask;
|
||||
|
||||
assign ZeroExtendedVPN = {{EXTRA_BITS{1'b0}}, VPN}; // forces the VPN to be the same width as PPN.
|
||||
|
||||
generate
|
||||
if (`XLEN == 32) begin
|
||||
always_comb
|
||||
case (PageType[0])
|
||||
// *** the widths of these constansts are hardocded here to match `PPN_BITS in the wally-constants file.
|
||||
// the widths of these constansts are hardocded here to match `PPN_BITS in the wally-constants file.
|
||||
0: PageNumberMask = 22'h3FFFFF; // kilopage: 22 bits of PPN, 0 bits of VPN
|
||||
1: PageNumberMask = 22'h3FFC00; // megapage: 12 bits of PPN, 10 bits of VPN
|
||||
endcase
|
||||
@ -57,7 +55,7 @@ module physicalpagemask (
|
||||
1: PageNumberMask = 44'hFFFFFFFFE00; // megapage: 35 bits of PPN, 9 bits of VPN
|
||||
2: PageNumberMask = 44'hFFFFFFC0000; // gigapage: 26 bits of PPN, 18 bits of VPN
|
||||
3: PageNumberMask = 44'hFFFF8000000; // terapage: 17 bits of PPN, 27 bits of VPN
|
||||
// *** make sure that this doesnt break when using sv39. In that case, all of these
|
||||
// Bus widths accomodate SV48. In SV39, all of these
|
||||
// busses are the widths for sv48, but extra bits should be zeroed out by the mux
|
||||
// in the tlb when it generates VPN from the full virtualadress.
|
||||
endcase
|
||||
@ -65,6 +63,7 @@ module physicalpagemask (
|
||||
endgenerate
|
||||
|
||||
// merge low segments of VPN with high segments of PPN decided by the pagetype.
|
||||
assign ZeroExtendedVPN = {{EXTRA_BITS{1'b0}}, VPN}; // forces the VPN to be the same width as PPN.
|
||||
assign MixedPageNumber = (ZeroExtendedVPN & ~PageNumberMask) | (PPN & PageNumberMask);
|
||||
|
||||
endmodule
|
@ -1,16 +1,15 @@
|
||||
///////////////////////////////////////////
|
||||
// priorityencoder.sv
|
||||
// tlbpriority.sv
|
||||
//
|
||||
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 7 April 2021
|
||||
// Based on implementation from https://www.allaboutcircuits.com/ip-cores/communication-controller/priority-encoder/
|
||||
// *** Give proper LGPL attribution for above source
|
||||
// Modified: Teo Ene 15 Apr 2021:
|
||||
// Temporarily removed paramterized priority encoder for non-parameterized one
|
||||
// To get synthesis working quickly
|
||||
// Kmacsaigoren@hmc.edu 28 May 2021:
|
||||
// Added working version of parameterized priority encoder.
|
||||
// David_Harris@Hmc.edu switched to one-hot output
|
||||
//
|
||||
// Purpose: One-hot encoding to binary encoder
|
||||
// Purpose: Priority circuit to choose most significant one-hot output
|
||||
//
|
||||
// A component of the Wally configurable RISC-V project.
|
||||
//
|
||||
@ -31,35 +30,20 @@
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module priorityencoder #(parameter BINARY_BITS = 3) (
|
||||
input logic [2**BINARY_BITS - 1:0] onehot,
|
||||
output logic [BINARY_BITS - 1:0] binary
|
||||
module tlbpriority #(parameter ENTRIES = 8) (
|
||||
input logic [ENTRIES-1:0] a,
|
||||
output logic [ENTRIES-1:0] y
|
||||
);
|
||||
// verilator lint_off UNOPTFLAT
|
||||
logic [ENTRIES-1:0] nolower;
|
||||
|
||||
integer i;
|
||||
always_comb begin
|
||||
binary = 0;
|
||||
for (i = 0; i < 2**BINARY_BITS; i++) begin
|
||||
// verilator lint_off WIDTH
|
||||
if (onehot[i]) binary = i; // prioritizes the most significant bit
|
||||
// verilator lint_on WIDTH
|
||||
end
|
||||
end
|
||||
// *** triple check synthesizability here
|
||||
|
||||
// Ideally this mimics the following:
|
||||
/*
|
||||
always_comb begin
|
||||
casex (one_hot)
|
||||
1xx ... x: binary = BINARY_BITS - 1;
|
||||
01x ... x: binary = BINARY_BITS - 2;
|
||||
001 ... x: binary = BINARY_BITS - 3;
|
||||
|
||||
{...}
|
||||
|
||||
00 ... 1xx: binary = 2;
|
||||
00 ... 01x: binary = 1;
|
||||
00 ... 001: binary = 0;
|
||||
end
|
||||
*/
|
||||
// generate thermometer code mask
|
||||
genvar i;
|
||||
generate
|
||||
assign nolower[0] = 1;
|
||||
for (i=1; i<ENTRIES; i++)
|
||||
assign nolower[i] = nolower[i-1] & ~a[i-1];
|
||||
endgenerate
|
||||
// verilator lint_on UNOPTFLAT
|
||||
assign y = a & nolower;
|
||||
endmodule
|
@ -29,11 +29,11 @@
|
||||
|
||||
module tlbram #(parameter ENTRY_BITS = 3) (
|
||||
input logic clk, reset,
|
||||
input logic [ENTRY_BITS-1:0] VPNIndex, // Index to read from
|
||||
//input logic [ENTRY_BITS-1:0] VPNIndex, // Index to read from
|
||||
// input logic [ENTRY_BITS-1:0] WriteIndex, // *** unused?
|
||||
input logic [`XLEN-1:0] PTEWriteVal,
|
||||
input logic TLBWrite,
|
||||
input logic [2**ENTRY_BITS-1:0] WriteLines,
|
||||
// input logic TLBWrite,
|
||||
input logic [2**ENTRY_BITS-1:0] ReadLines, WriteEnables,
|
||||
|
||||
output logic [`PPN_BITS-1:0] PhysicalPageNumber,
|
||||
output logic [7:0] PTEAccessBits
|
||||
@ -41,20 +41,13 @@ module tlbram #(parameter ENTRY_BITS = 3) (
|
||||
|
||||
localparam NENTRIES = 2**ENTRY_BITS;
|
||||
|
||||
logic [`XLEN-1:0] ram [NENTRIES-1:0];
|
||||
logic [`XLEN-1:0] RamRead[NENTRIES-1:0];
|
||||
logic [`XLEN-1:0] PageTableEntry;
|
||||
|
||||
// Generate a flop for every entry in the RAM
|
||||
generate
|
||||
genvar i;
|
||||
for (i = 0; i < NENTRIES; i++) begin: tlb_ram_flops
|
||||
flopenr #(`XLEN) pteflop(clk, reset, WriteLines[i] & TLBWrite,
|
||||
PTEWriteVal, ram[i]);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign PageTableEntry = ram[VPNIndex];
|
||||
tlbramline #(`XLEN) tlblineram[NENTRIES-1:0](clk, reset, ReadLines, WriteEnables, PTEWriteVal, RamRead);
|
||||
|
||||
assign PageTableEntry = RamRead.or; // OR each column of RAM read to read PTE
|
||||
assign PTEAccessBits = PageTableEntry[7:0];
|
||||
assign PhysicalPageNumber = PageTableEntry[`PPN_BITS+9:10];
|
||||
|
||||
endmodule
|
||||
|
38
wally-pipelined/src/mmu/tlbramline.sv
Normal file
38
wally-pipelined/src/mmu/tlbramline.sv
Normal file
@ -0,0 +1,38 @@
|
||||
///////////////////////////////////////////
|
||||
// tlbramline.sv
|
||||
//
|
||||
// Written: David_Harris@hmc.edu 4 July 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose: One line of the RAM, with enabled flip-flop and logic for reading into distributed OR
|
||||
//
|
||||
// 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 "wally-config.vh"
|
||||
|
||||
module tlbramline #(parameter WIDTH)
|
||||
(input logic clk, reset,
|
||||
input logic re, we,
|
||||
input logic [WIDTH-1:0] d,
|
||||
output logic [WIDTH-1:0] q);
|
||||
|
||||
logic [WIDTH-1:0] line;
|
||||
|
||||
flopenr #(`XLEN) pteflop(clk, reset, we, d, line);
|
||||
assign q = re ? line : 0;
|
||||
endmodule
|
@ -307,7 +307,7 @@ module csa #(parameter WIDTH=8) (input logic [WIDTH-1:0] a, b, c,
|
||||
assign carry = {carry_temp[WIDTH-1:1], 1'b0};
|
||||
|
||||
endmodule // csa
|
||||
|
||||
/*
|
||||
module eqcmp #(parameter WIDTH = 8)
|
||||
(input logic [WIDTH-1:0] a, b,
|
||||
output logic y);
|
||||
@ -315,6 +315,7 @@ module eqcmp #(parameter WIDTH = 8)
|
||||
assign y = (a == b);
|
||||
|
||||
endmodule // eqcmp
|
||||
*/
|
||||
|
||||
// QST for r=4
|
||||
module qst4 (input logic [6:0] s, input logic [2:0] d,
|
||||
|
@ -58,9 +58,8 @@ module csr #(parameter
|
||||
output logic [`XLEN-1:0] SATP_REGW,
|
||||
output logic [11:0] MIP_REGW, MIE_REGW, SIP_REGW, SIE_REGW,
|
||||
output logic STATUS_MIE, STATUS_SIE,
|
||||
output logic STATUS_MXR, STATUS_SUM,
|
||||
output logic STATUS_MPRV,
|
||||
output var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
output logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
output var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
|
||||
input logic [4:0] SetFflagsM,
|
||||
output logic [2:0] FRM_REGW,
|
||||
|
@ -74,7 +74,8 @@ module csrm #(parameter
|
||||
output logic [31:0] MCOUNTEREN_REGW, MCOUNTINHIBIT_REGW,
|
||||
output logic [`XLEN-1:0] MEDELEG_REGW, MIDELEG_REGW,
|
||||
// 64-bit registers in RV64, or two 32-bit registers in RV32
|
||||
output var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
//output var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
output var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
|
||||
input logic [11:0] MIP_REGW, MIE_REGW,
|
||||
output logic WriteMSTATUSM,
|
||||
@ -87,8 +88,9 @@ module csrm #(parameter
|
||||
logic WriteMTVECM, WriteMEDELEGM, WriteMIDELEGM;
|
||||
logic WriteMSCRATCHM, WriteMEPCM, WriteMCAUSEM, WriteMTVALM;
|
||||
logic WriteMCOUNTERENM, WriteMCOUNTINHIBITM;
|
||||
logic [`PMP_ENTRIES/8-1:0] WritePMPCFGM, WritePMPCFGHM ;
|
||||
logic [`PMP_ENTRIES-1:0] WritePMPADDRM ;
|
||||
logic [`PMP_ENTRIES-1:0] WritePMPCFGM;
|
||||
logic [`PMP_ENTRIES-1:0] WritePMPADDRM ;
|
||||
logic [`PMP_ENTRIES-1:0] ADDRLocked, CFGLocked;
|
||||
|
||||
localparam MISA_26 = (`MISA) & 32'h03ffffff;
|
||||
|
||||
@ -104,30 +106,9 @@ module csrm #(parameter
|
||||
assign WriteMEPCM = MTrapM | (CSRMWriteM && (CSRAdrM == MEPC)) && ~StallW;
|
||||
assign WriteMCAUSEM = MTrapM | (CSRMWriteM && (CSRAdrM == MCAUSE)) && ~StallW;
|
||||
assign WriteMTVALM = MTrapM | (CSRMWriteM && (CSRAdrM == MTVAL)) && ~StallW;
|
||||
/* assign WritePMPCFG0M = (CSRMWriteM && (CSRAdrM == PMPCFG0)) && ~StallW;
|
||||
assign WritePMPCFG2M = (CSRMWriteM && (CSRAdrM == PMPCFG2)) && ~StallW;
|
||||
assign WritePMPADDRM[0] = (CSRMWriteM && (CSRAdrM == PMPADDR0)) && ~StallW;
|
||||
assign WritePMPADDRM[1] = (CSRMWriteM && (CSRAdrM == PMPADDR1)) && ~StallW;
|
||||
assign WritePMPADDRM[2] = (CSRMWriteM && (CSRAdrM == PMPADDR2)) && ~StallW;
|
||||
assign WritePMPADDRM[3] = (CSRMWriteM && (CSRAdrM == PMPADDR3)) && ~StallW;
|
||||
assign WritePMPADDRM[4] = (CSRMWriteM && (CSRAdrM == PMPADDR4)) && ~StallW;
|
||||
assign WritePMPADDRM[5] = (CSRMWriteM && (CSRAdrM == PMPADDR5)) && ~StallW;
|
||||
assign WritePMPADDRM[6] = (CSRMWriteM && (CSRAdrM == PMPADDR6)) && ~StallW;
|
||||
assign WritePMPADDRM[7] = (CSRMWriteM && (CSRAdrM == PMPADDR7)) && ~StallW;
|
||||
assign WritePMPADDRM[8] = (CSRMWriteM && (CSRAdrM == PMPADDR8)) && ~StallW;
|
||||
assign WritePMPADDRM[9] = (CSRMWriteM && (CSRAdrM == PMPADDR9)) && ~StallW;
|
||||
assign WritePMPADDRM[10] = (CSRMWriteM && (CSRAdrM == PMPADDR10)) && ~StallW;
|
||||
assign WritePMPADDRM[11] = (CSRMWriteM && (CSRAdrM == PMPADDR11)) && ~StallW;
|
||||
assign WritePMPADDRM[12] = (CSRMWriteM && (CSRAdrM == PMPADDR12)) && ~StallW;
|
||||
assign WritePMPADDRM[13] = (CSRMWriteM && (CSRAdrM == PMPADDR13)) && ~StallW;
|
||||
assign WritePMPADDRM[14] = (CSRMWriteM && (CSRAdrM == PMPADDR14)) && ~StallW;
|
||||
assign WritePMPADDRM[15] = (CSRMWriteM && (CSRAdrM == PMPADDR15)) && ~StallW; */
|
||||
assign WriteMCOUNTERENM = CSRMWriteM && (CSRAdrM == MCOUNTEREN) && ~StallW;
|
||||
assign WriteMCOUNTINHIBITM = CSRMWriteM && (CSRAdrM == MCOUNTINHIBIT) && ~StallW;
|
||||
|
||||
|
||||
|
||||
|
||||
assign IllegalCSRMWriteReadonlyM = CSRMWriteM && (CSRAdrM == MVENDORID || CSRAdrM == MARCHID || CSRAdrM == MIMPID || CSRAdrM == MHARTID);
|
||||
|
||||
// CSRs
|
||||
@ -164,32 +145,49 @@ module csrm #(parameter
|
||||
genvar i;
|
||||
generate
|
||||
for(i=0; i<`PMP_ENTRIES; i++) begin
|
||||
assign WritePMPADDRM[i] = (CSRMWriteM && (CSRAdrM == PMPADDR0+i)) && ~StallW;
|
||||
// when the lock bit is set, don't allow writes to the PMPCFG or PMPADDR
|
||||
// also, when the lock bit of the next entry is set and the next entry is TOR, don't allow writes to this entry PMPADDR
|
||||
assign CFGLocked[i] = PMPCFG_ARRAY_REGW[i][7];
|
||||
if (i == `PMP_ENTRIES-1)
|
||||
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7];
|
||||
else
|
||||
assign ADDRLocked[i] = PMPCFG_ARRAY_REGW[i][7] | (PMPCFG_ARRAY_REGW[i+1][7] & PMPCFG_ARRAY_REGW[i+1][4:3] == 2'b01);
|
||||
|
||||
assign WritePMPADDRM[i] = (CSRMWriteM & (CSRAdrM == (PMPADDR0+i))) & ~StallW & ~ADDRLocked[i];
|
||||
flopenr #(`XLEN) PMPADDRreg(clk, reset, WritePMPADDRM[i], CSRWriteValM, PMPADDR_ARRAY_REGW[i]);
|
||||
end
|
||||
for (i=0; i<`PMP_ENTRIES/8; i++) begin
|
||||
if (`XLEN==64) begin
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM && (CSRAdrM == PMPCFG0+2*i)) && ~StallW;
|
||||
flopenr #(`XLEN) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM, PMPCFG_ARRAY_REGW[i]);
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+2*(i/8)))) & ~StallW & ~CFGLocked[i];
|
||||
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%8)*8+7:(i%8)*8], PMPCFG_ARRAY_REGW[i]);
|
||||
end else begin
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM && (CSRAdrM == PMPCFG0+2*i)) && ~StallW;
|
||||
assign WritePMPCFGHM[i] = (CSRMWriteM && (CSRAdrM == PMPCFG0+2*i+1)) && ~StallW;
|
||||
flopenr #(`XLEN) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM, PMPCFG_ARRAY_REGW[i][31:0]);
|
||||
flopenr #(`XLEN) PMPCFGHreg(clk, reset, WritePMPCFGHM[i], CSRWriteValM, PMPCFG_ARRAY_REGW[i][63:32]);
|
||||
assign WritePMPCFGM[i] = (CSRMWriteM & (CSRAdrM == (PMPCFG0+i/4))) & ~StallW & ~CFGLocked[i];
|
||||
// assign WritePMPCFGHM[i] = (CSRMWriteM && (CSRAdrM == PMPCFG0+2*i+1)) && ~StallW;
|
||||
flopenr #(8) PMPCFGreg(clk, reset, WritePMPCFGM[i], CSRWriteValM[(i%4)*8+7:(i%4)*8], PMPCFG_ARRAY_REGW[i]);
|
||||
// flopenr #(`XLEN) PMPCFGHreg(clk, reset, WritePMPCFGHM[i], CSRWriteValM, PMPCFG_ARRAY_REGW[i][63:32]);
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Read machine mode CSRs
|
||||
// verilator lint_off WIDTH
|
||||
logic [5:0] entry;
|
||||
always_comb begin
|
||||
IllegalCSRMAccessM = !(`S_SUPPORTED | `U_SUPPORTED & `N_SUPPORTED) &&
|
||||
(CSRAdrM == MEDELEG || CSRAdrM == MIDELEG); // trap on DELEG register access when no S or N-mode
|
||||
if (CSRAdrM >= PMPADDR0 && CSRAdrM < PMPADDR0 + `PMP_ENTRIES) // reading a PMP entry
|
||||
CSRMReadValM = PMPADDR_ARRAY_REGW[CSRAdrM - PMPADDR0];
|
||||
else if (CSRAdrM >= PMPCFG0 && CSRAdrM < PMPCFG0 + `PMP_ENTRIES/8) begin
|
||||
if (~CSRAdrM[0]) CSRMReadValM = PMPCFG_ARRAY_REGW[CSRAdrM - PMPCFG0][`XLEN-1:0];
|
||||
else CSRMReadValM = {{(`XLEN-32){1'b0}}, PMPCFG_ARRAY_REGW[CSRAdrM - PMPCFG0][63:32]};
|
||||
else if (CSRAdrM >= PMPCFG0 && CSRAdrM < PMPCFG0 + `PMP_ENTRIES/4) begin
|
||||
if (`XLEN==64) begin
|
||||
entry = ({CSRAdrM[11:1], 1'b0} - PMPCFG0)*4; // disregard odd entries in RV64
|
||||
CSRMReadValM = {PMPCFG_ARRAY_REGW[entry+7],PMPCFG_ARRAY_REGW[entry+6],PMPCFG_ARRAY_REGW[entry+5],PMPCFG_ARRAY_REGW[entry+4],
|
||||
PMPCFG_ARRAY_REGW[entry+3],PMPCFG_ARRAY_REGW[entry+2],PMPCFG_ARRAY_REGW[entry+1],PMPCFG_ARRAY_REGW[entry]};
|
||||
end else begin
|
||||
entry = (CSRAdrM - PMPCFG0)*4;
|
||||
CSRMReadValM = {PMPCFG_ARRAY_REGW[entry+3],PMPCFG_ARRAY_REGW[entry+2],PMPCFG_ARRAY_REGW[entry+1],PMPCFG_ARRAY_REGW[entry]};
|
||||
end
|
||||
|
||||
/*
|
||||
if (~CSRAdrM[0]) CSRMReadValM = {PMPCFG_ARRAY_REGW[]};
|
||||
else CSRMReadValM = {{(`XLEN-32){1'b0}}, PMPCFG_ARRAY_REGW[(CSRAdrM - PMPCFG0-1)/2][63:32]};*/
|
||||
end
|
||||
else case (CSRAdrM)
|
||||
MISA_ADR: CSRMReadValM = MISA_REGW;
|
||||
@ -212,26 +210,7 @@ module csrm #(parameter
|
||||
MTVAL: CSRMReadValM = MTVAL_REGW;
|
||||
MCOUNTEREN:CSRMReadValM = {{(`XLEN-32){1'b0}}, MCOUNTEREN_REGW};
|
||||
MCOUNTINHIBIT:CSRMReadValM = {{(`XLEN-32){1'b0}}, MCOUNTINHIBIT_REGW};
|
||||
/* PMPCFG0: CSRMReadValM = PMPCFG01_REGW[`XLEN-1:0];
|
||||
PMPCFG1: CSRMReadValM = {{(`XLEN-32){1'b0}}, PMPCFG01_REGW[63:32]};
|
||||
PMPCFG2: CSRMReadValM = PMPCFG23_REGW[`XLEN-1:0];
|
||||
PMPCFG3: CSRMReadValM = {{(`XLEN-32){1'b0}}, PMPCFG23_REGW[63:32]};
|
||||
PMPADDR0: CSRMReadValM = PMPADDR_ARRAY_REGW[0]; // *** make configurable
|
||||
PMPADDR1: CSRMReadValM = PMPADDR_ARRAY_REGW[1];
|
||||
PMPADDR2: CSRMReadValM = PMPADDR_ARRAY_REGW[2];
|
||||
PMPADDR3: CSRMReadValM = PMPADDR_ARRAY_REGW[3];
|
||||
PMPADDR4: CSRMReadValM = PMPADDR_ARRAY_REGW[4];
|
||||
PMPADDR5: CSRMReadValM = PMPADDR_ARRAY_REGW[5];
|
||||
PMPADDR6: CSRMReadValM = PMPADDR_ARRAY_REGW[6];
|
||||
PMPADDR7: CSRMReadValM = PMPADDR_ARRAY_REGW[7];
|
||||
PMPADDR8: CSRMReadValM = PMPADDR_ARRAY_REGW[8];
|
||||
PMPADDR9: CSRMReadValM = PMPADDR_ARRAY_REGW[9];
|
||||
PMPADDR10: CSRMReadValM = PMPADDR_ARRAY_REGW[10];
|
||||
PMPADDR11: CSRMReadValM = PMPADDR_ARRAY_REGW[11];
|
||||
PMPADDR12: CSRMReadValM = PMPADDR_ARRAY_REGW[12];
|
||||
PMPADDR13: CSRMReadValM = PMPADDR_ARRAY_REGW[13];
|
||||
PMPADDR14: CSRMReadValM = PMPADDR_ARRAY_REGW[14];
|
||||
PMPADDR15: CSRMReadValM = PMPADDR_ARRAY_REGW[15]; */
|
||||
|
||||
default: begin
|
||||
CSRMReadValM = 0;
|
||||
IllegalCSRMAccessM = 1;
|
||||
|
@ -38,9 +38,9 @@ module privdec (
|
||||
|
||||
// xRET defined in Privileged Spect 3.2.2
|
||||
assign uretM = PrivilegedM & (InstrM[31:20] == 12'b000000000010) & `N_SUPPORTED;
|
||||
assign sretM = PrivilegedM & (InstrM[31:20] == 12'b000100000010) & `S_SUPPORTED &&
|
||||
assign sretM = PrivilegedM & (InstrM[31:20] == 12'b000100000010) & `S_SUPPORTED &
|
||||
PrivilegeModeW[0] & ~STATUS_TSR;
|
||||
assign mretM = PrivilegedM & (InstrM[31:20] == 12'b001100000010) && (PrivilegeModeW == `M_MODE);
|
||||
assign mretM = PrivilegedM & (InstrM[31:20] == 12'b001100000010) & (PrivilegeModeW == `M_MODE);
|
||||
|
||||
assign ecallM = PrivilegedM & (InstrM[31:20] == 12'b000000000000);
|
||||
assign ebreakM = PrivilegedM & (InstrM[31:20] == 12'b000000000001);
|
||||
|
@ -64,11 +64,12 @@ module privileged (
|
||||
input logic PMALoadAccessFaultM, PMPLoadAccessFaultM,
|
||||
input logic PMAStoreAccessFaultM, PMPStoreAccessFaultM,
|
||||
|
||||
output logic IllegalFPUInstrE,
|
||||
output logic IllegalFPUInstrE,
|
||||
output logic [1:0] PrivilegeModeW,
|
||||
output logic [`XLEN-1:0] SATP_REGW,
|
||||
output logic STATUS_MXR, STATUS_SUM,
|
||||
output var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0],
|
||||
output logic STATUS_MXR, STATUS_SUM, STATUS_MPRV,
|
||||
output logic [1:0] STATUS_MPP,
|
||||
output var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0],
|
||||
output var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0],
|
||||
output logic [2:0] FRM_REGW
|
||||
);
|
||||
@ -94,8 +95,7 @@ module privileged (
|
||||
logic MTrapM, STrapM, UTrapM;
|
||||
logic InterruptM;
|
||||
|
||||
logic [1:0] STATUS_MPP;
|
||||
logic STATUS_SPP, STATUS_TSR, STATUS_MPRV; // **** status mprv is unused outside of the csr module as of 4 June 2021. should it be deleted alltogether from the module, or should I leav the pin here in case someone needs it?
|
||||
logic STATUS_SPP, STATUS_TSR;
|
||||
logic STATUS_MIE, STATUS_SIE;
|
||||
logic [11:0] MIP_REGW, MIE_REGW, SIP_REGW, SIE_REGW;
|
||||
logic md, sd;
|
||||
|
@ -94,7 +94,7 @@ module clint (
|
||||
if (~HRESETn) begin
|
||||
MTIME <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite && entryd == 16'hBFF8) begin
|
||||
end else if (memwrite & entryd == 16'hBFF8) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
MTIME <= HWDATA;
|
||||
end else MTIME <= MTIME + 1;
|
||||
@ -125,9 +125,9 @@ module clint (
|
||||
if (~HRESETn) begin
|
||||
MTIME <= 0;
|
||||
// MTIMECMP is not reset
|
||||
end else if (memwrite && (entryd == 16'hBFF8)) begin
|
||||
end else if (memwrite & (entryd == 16'hBFF8)) begin
|
||||
MTIME[31:0] <= HWDATA;
|
||||
end else if (memwrite && (entryd == 16'hBFFC)) begin
|
||||
end else if (memwrite & (entryd == 16'hBFFC)) begin
|
||||
// MTIME Counter. Eventually change this to run off separate clock. Synchronization then needed
|
||||
MTIME[63:32]<= HWDATA;
|
||||
end else MTIME <= MTIME + 1;
|
||||
|
@ -102,13 +102,13 @@ module dtim #(parameter BASE=0, RANGE = 65535) (
|
||||
always_ff @(posedge HCLK) begin
|
||||
HWADDR <= #1 A;
|
||||
HREADTim0 <= #1 RAM[A[31:3]];
|
||||
if (memwrite && risingHREADYTim) RAM[HWADDR[31:3]] <= #1 HWDATA;
|
||||
if (memwrite & risingHREADYTim) RAM[HWADDR[31:3]] <= #1 HWDATA;
|
||||
end
|
||||
end else begin
|
||||
always_ff @(posedge HCLK) begin
|
||||
HWADDR <= #1 A;
|
||||
HREADTim0 <= #1 RAM[A[31:2]];
|
||||
if (memwrite && risingHREADYTim) RAM[HWADDR[31:2]] <= #1 HWDATA;
|
||||
if (memwrite & risingHREADYTim) RAM[HWADDR[31:2]] <= #1 HWDATA;
|
||||
end
|
||||
end
|
||||
endgenerate
|
||||
|
@ -131,19 +131,19 @@ module gpio (
|
||||
default: Dout <= #1 0;
|
||||
endcase
|
||||
// interrupts
|
||||
if (memwrite && (entryd == 8'h1C))
|
||||
if (memwrite & (entryd == 8'h1C))
|
||||
rise_ip <= rise_ip & ~Din | (input2d & ~input3d);
|
||||
else
|
||||
rise_ip <= rise_ip | (input2d & ~input3d);
|
||||
if (memwrite && (entryd == 8'h24))
|
||||
if (memwrite & (entryd == 8'h24))
|
||||
fall_ip <= fall_ip & ~Din | (~input2d & input3d);
|
||||
else
|
||||
fall_ip <= fall_ip | (~input2d & input3d);
|
||||
if (memwrite && (entryd == 8'h2C))
|
||||
if (memwrite & (entryd == 8'h2C))
|
||||
high_ip <= high_ip & ~Din | input3d;
|
||||
else
|
||||
high_ip <= high_ip | input3d;
|
||||
if (memwrite && (entryd == 8'h34))
|
||||
if (memwrite & (entryd == 8'h34))
|
||||
low_ip <= low_ip & ~Din | ~input3d;
|
||||
else
|
||||
low_ip <= low_ip | ~input3d;
|
||||
@ -157,7 +157,6 @@ module gpio (
|
||||
else
|
||||
assign input0d = GPIOPinsIn & input_en;
|
||||
endgenerate
|
||||
// *** this costs lots of flops; I suspect they don't need to be resettable, do they?
|
||||
flop #(32) sync1(HCLK,input0d,input1d);
|
||||
flop #(32) sync2(HCLK,input1d,input2d);
|
||||
flop #(32) sync3(HCLK,input2d,input3d);
|
||||
|
@ -1,71 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// imem.sv
|
||||
//
|
||||
// Written: David_Harris@hmc.edu 9 January 2021
|
||||
// Modified:
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// 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 "wally-config.vh"
|
||||
|
||||
module imem (
|
||||
input logic [`XLEN-1:1] AdrF,
|
||||
output logic [31:0] InstrF,
|
||||
output logic [15:0] rd2, // bogus, delete when real multicycle fetch works
|
||||
output logic InstrAccessFaultF);
|
||||
|
||||
/* verilator lint_off UNDRIVEN */
|
||||
logic [`XLEN-1:0] RAM[`TIM_BASE>>(1+`XLEN/32):(`TIM_RANGE+`TIM_BASE)>>(1+`XLEN/32)];
|
||||
logic [`XLEN-1:0] bootram[`BOOTTIM_BASE>>(1+`XLEN/32):(`BOOTTIM_RANGE+`BOOTTIM_BASE)>>(1+`XLEN/32)];
|
||||
/* verilator lint_on UNDRIVEN */
|
||||
logic [31:0] adrbits; // needs to be 32 bits to index RAM
|
||||
logic [`XLEN-1:0] rd;
|
||||
// logic [15:0] rd2;
|
||||
|
||||
generate
|
||||
if (`XLEN==32) assign adrbits = AdrF[31:2];
|
||||
else assign adrbits = AdrF[31:3];
|
||||
endgenerate
|
||||
|
||||
assign #2 rd = (AdrF < (`TIM_BASE >> 1)) ? bootram[adrbits] : RAM[adrbits]; // busybear: 2 memory options
|
||||
|
||||
// hack right now for unaligned 32-bit instructions
|
||||
// eventually this will need to cause a stall like a cache miss
|
||||
// when the instruction wraps around a cache line
|
||||
// could be optimized to only stall when the instruction wrapping is 32 bits
|
||||
assign #2 rd2 = (AdrF < (`TIM_BASE >> 1)) ? bootram[adrbits+1][15:0] : RAM[adrbits+1][15:0]; //busybear: 2 memory options
|
||||
generate
|
||||
if (`XLEN==32) begin
|
||||
assign InstrF = AdrF[1] ? {rd2[15:0], rd[31:16]} : rd;
|
||||
// First, AdrF needs to get its last bit appended back onto it
|
||||
// Then not-XORing it with TIM_BASE checks if it matches TIM_BASE exactly
|
||||
// Then ORing it with TIM_RANGE introduces some leeway into the previous check, by allowing the lower bits to be either high or low
|
||||
|
||||
assign InstrAccessFaultF = (~&(({AdrF,1'b0} ~^ `TIM_BASE) | `TIM_RANGE)) & (~&(({AdrF,1'b0} ~^ `BOOTTIM_BASE) | `BOOTTIM_RANGE));
|
||||
|
||||
end else begin
|
||||
assign InstrF = AdrF[2] ? (AdrF[1] ? {rd2[15:0], rd[63:48]} : rd[63:32])
|
||||
: (AdrF[1] ? rd[47:16] : rd[31:0]);
|
||||
//
|
||||
assign InstrAccessFaultF = (|AdrF[`XLEN-1:32] | ~&({AdrF[31:1],1'b0} ~^ `TIM_BASE | `TIM_RANGE)) & (|AdrF[`XLEN-1:32] | ~&({AdrF[31:1],1'b0} ~^ `BOOTTIM_BASE | `BOOTTIM_RANGE));
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
|
@ -224,11 +224,11 @@ module uartPC16550D(
|
||||
else rxstate <= #1 UART_IDLE;
|
||||
end
|
||||
// timeout counting
|
||||
if (~MEMRb && A == 3'b000 && ~DLAB) rxtimeoutcnt <= #1 0; // reset timeout on read
|
||||
if (~MEMRb & A == 3'b000 & ~DLAB) rxtimeoutcnt <= #1 0; // reset timeout on read
|
||||
else if (fifoenabled & ~rxfifoempty & rxbaudpulse & ~rxfifotimeout) rxtimeoutcnt <= #1 rxtimeoutcnt+1; // *** not right
|
||||
end
|
||||
|
||||
assign rxcentered = rxbaudpulse && (rxoversampledcnt == 4'b1000); // implies rxstate = UART_ACTIVE
|
||||
assign rxcentered = rxbaudpulse & (rxoversampledcnt == 4'b1000); // implies rxstate = UART_ACTIVE
|
||||
assign rxbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1; // start bit + data bits + (parity bit) + stop bit
|
||||
|
||||
///////////////////////////////////////////
|
||||
@ -267,12 +267,12 @@ module uartPC16550D(
|
||||
rxfifohead <= #1 rxfifohead + 1;
|
||||
end
|
||||
rxdataready <= #1 1;
|
||||
end else if (~MEMRb && A == 3'b000 && ~DLAB) begin // reading RBR updates ready / pops fifo
|
||||
end else if (~MEMRb & A == 3'b000 & ~DLAB) begin // reading RBR updates ready / pops fifo
|
||||
if (fifoenabled) begin
|
||||
rxfifotail <= #1 rxfifotail + 1;
|
||||
if (rxfifohead == rxfifotail +1) rxdataready <= #1 0;
|
||||
end else rxdataready <= #1 0;
|
||||
end else if (~MEMWb && A == 3'b010) // writes to FIFO Control Register
|
||||
end else if (~MEMWb & A == 3'b010) // writes to FIFO Control Register
|
||||
if (Din[1] | ~Din[0]) begin // rx FIFO reset or FIFO disable clears FIFO contents
|
||||
rxfifohead <= #1 0; rxfifotail <= #1 0;
|
||||
end
|
||||
@ -326,7 +326,7 @@ module uartPC16550D(
|
||||
txoversampledcnt <= #1 0;
|
||||
txstate <= #1 UART_IDLE;
|
||||
txbitssent <= #1 0;
|
||||
end else if ((txstate == UART_IDLE) && txsrfull) begin // start transmitting
|
||||
end else if ((txstate == UART_IDLE) & txsrfull) begin // start transmitting
|
||||
txstate <= #1 UART_ACTIVE;
|
||||
txoversampledcnt <= #1 1;
|
||||
txbitssent <= #1 0;
|
||||
@ -341,7 +341,7 @@ module uartPC16550D(
|
||||
end
|
||||
|
||||
assign txbitsexpected = 4'd1 + (4'd5 + {2'b00, LCR[1:0]}) + {3'b000, LCR[3]} + 4'd1 + {3'b000, LCR[2]} - 4'd1; // start bit + data bits + (parity bit) + stop bit(s)
|
||||
assign txnextbit = txbaudpulse && (txoversampledcnt == 4'b0000); // implies txstate = UART_ACTIVE
|
||||
assign txnextbit = txbaudpulse & (txoversampledcnt == 4'b0000); // implies txstate = UART_ACTIVE
|
||||
|
||||
///////////////////////////////////////////
|
||||
// transmit holding register, shift register, FIFO
|
||||
@ -372,7 +372,7 @@ module uartPC16550D(
|
||||
if (~HRESETn) begin
|
||||
txfifohead <= #1 0; txfifotail <= #1 0; txhrfull <= #1 0; txsrfull <= #1 0; TXHR <= #1 0; txsr <= #1 12'hfff;
|
||||
end else begin
|
||||
if (~MEMWb && A == 3'b000 && ~DLAB) begin // writing transmit holding register or fifo
|
||||
if (~MEMWb & A == 3'b000 & ~DLAB) begin // writing transmit holding register or fifo
|
||||
if (fifoenabled) begin
|
||||
txfifo[txfifohead] <= #1 Din;
|
||||
txfifohead <= #1 txfifohead + 1;
|
||||
@ -395,8 +395,8 @@ module uartPC16550D(
|
||||
txsrfull <= #1 1;
|
||||
end
|
||||
end else if (txstate == UART_DONE) txsrfull <= #1 0; // done transmitting shift register
|
||||
else if (txstate == UART_ACTIVE && txnextbit) txsr <= #1 {txsr[10:0], 1'b1}; // shift txhr
|
||||
if (!MEMWb && A == 3'b010) // writes to FIFO control register
|
||||
else if (txstate == UART_ACTIVE & txnextbit) txsr <= #1 {txsr[10:0], 1'b1}; // shift txhr
|
||||
if (!MEMWb & A == 3'b010) // writes to FIFO control register
|
||||
if (Din[2] | ~Din[0]) begin // tx FIFO reste or FIFO disable clears FIFO contents
|
||||
txfifohead <= #1 0; txfifotail <= #1 0;
|
||||
end
|
||||
|
@ -62,22 +62,24 @@ module uncore (
|
||||
logic [`XLEN-1:0] HWDATA;
|
||||
logic [`XLEN-1:0] HREADTim, HREADCLINT, HREADPLIC, HREADGPIO, HREADUART;
|
||||
|
||||
logic [5:0] HSELRegions;
|
||||
logic [6:0] HSELRegions;
|
||||
logic HSELTim, HSELCLINT, HSELPLIC, HSELGPIO, PreHSELUART, HSELUART;
|
||||
logic HSELTimD, HSELCLINTD, HSELPLICD, HSELGPIOD, HSELUARTD;
|
||||
logic HRESPTim, HRESPCLINT, HRESPPLIC, HRESPGPIO, HRESPUART;
|
||||
logic HREADYTim, HREADYCLINT, HREADYPLIC, HREADYGPIO, HREADYUART;
|
||||
logic [`XLEN-1:0] HREADBootTim;
|
||||
logic HSELBootTim, HSELBootTimD, HRESPBootTim, HREADYBootTim;
|
||||
logic HSELNoneD;
|
||||
logic [1:0] MemRWboottim;
|
||||
logic UARTIntr,GPIOIntr;
|
||||
|
||||
// Determine which region of physical memory (if any) is being accessed
|
||||
// Use a trimmed down portion of the PMA checker - only the address decoders
|
||||
// Set access types to all 1 as don't cares because the MMU has already done access checking
|
||||
adrdecs adrdecs({{(`PA_BITS-32){1'b0}}, HADDR}, 1'b1, 1'b1, 1'b1, HSIZE[1:0], HSELRegions);
|
||||
|
||||
// unswizzle HSEL signals
|
||||
assign {HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC} = HSELRegions;
|
||||
assign {HSELBootTim, HSELTim, HSELCLINT, HSELGPIO, HSELUART, HSELPLIC} = HSELRegions[5:0];
|
||||
|
||||
// subword accesses: converts HWDATAIN to HWDATA
|
||||
subwordwrite sww(.*);
|
||||
@ -133,19 +135,10 @@ module uncore (
|
||||
HSELPLICD & HREADYPLIC |
|
||||
HSELGPIOD & HREADYGPIO |
|
||||
HSELBootTimD & HREADYBootTim |
|
||||
HSELUARTD & HREADYUART;
|
||||
|
||||
/* PMA checker now handles access faults. *** This can be deleted
|
||||
// Faults
|
||||
assign DataAccessFaultM = ~(HSELTimD | HSELCLINTD | HSELPLICD | HSELGPIOD | HSELBootTimD | HSELUARTD);
|
||||
*/
|
||||
HSELUARTD & HREADYUART |
|
||||
HSELNoneD; // don't lock up the bus if no region is being accessed
|
||||
|
||||
// Address Decoder Delay (figure 4-2 in spec)
|
||||
flopr #(1) hseltimreg(HCLK, ~HRESETn, HSELTim, HSELTimD);
|
||||
flopr #(1) hselclintreg(HCLK, ~HRESETn, HSELCLINT, HSELCLINTD);
|
||||
flopr #(1) hselplicreg(HCLK, ~HRESETn, HSELPLIC, HSELPLICD);
|
||||
flopr #(1) hselgpioreg(HCLK, ~HRESETn, HSELGPIO, HSELGPIOD);
|
||||
flopr #(1) hseluartreg(HCLK, ~HRESETn, HSELUART, HSELUARTD);
|
||||
flopr #(1) hselboottimreg(HCLK, ~HRESETn, HSELBootTim, HSELBootTimD);
|
||||
flopr #(7) hseldelayreg(HCLK, ~HRESETn, HSELRegions, {HSELNoneD, HSELBootTimD, HSELTimD, HSELCLINTD, HSELGPIOD, HSELUARTD, HSELPLICD});
|
||||
endmodule
|
||||
|
||||
|
@ -112,7 +112,8 @@ module wallypipelinedhart
|
||||
logic ITLBMissF, ITLBHitF;
|
||||
logic DTLBMissM, DTLBHitM;
|
||||
logic [`XLEN-1:0] SATP_REGW;
|
||||
logic STATUS_MXR, STATUS_SUM;
|
||||
logic STATUS_MXR, STATUS_SUM, STATUS_MPRV;
|
||||
logic [1:0] STATUS_MPP;
|
||||
logic [1:0] PrivilegeModeW;
|
||||
logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM;
|
||||
logic [1:0] PageTypeF, PageTypeM;
|
||||
@ -122,8 +123,8 @@ module wallypipelinedhart
|
||||
logic PMPInstrAccessFaultF, PMPLoadAccessFaultM, PMPStoreAccessFaultM;
|
||||
logic PMAInstrAccessFaultF, PMALoadAccessFaultM, PMAStoreAccessFaultM;
|
||||
logic DSquashBusAccessM, ISquashBusAccessF;
|
||||
var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0];
|
||||
var logic [63:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES/8-1:0];
|
||||
var logic [`XLEN-1:0] PMPADDR_ARRAY_REGW [`PMP_ENTRIES-1:0];
|
||||
var logic [7:0] PMPCFG_ARRAY_REGW[`PMP_ENTRIES-1:0];
|
||||
|
||||
// IMem stalls
|
||||
logic ICacheStallF;
|
||||
@ -223,6 +224,8 @@ module wallypipelinedhart
|
||||
.SATP_REGW(SATP_REGW), // from csr
|
||||
.STATUS_MXR(STATUS_MXR), // from csr
|
||||
.STATUS_SUM(STATUS_SUM), // from csr
|
||||
.STATUS_MPRV(STATUS_MPRV), // from csr
|
||||
.STATUS_MPP(STATUS_MPP), // from csr
|
||||
|
||||
.DTLBFlushM(DTLBFlushM), // connects to privilege
|
||||
.NonBusTrapM(NonBusTrapM), // connects to privilege
|
||||
|
@ -520,6 +520,7 @@ string tests32f[] = '{
|
||||
|
||||
// check assertions for a legal configuration
|
||||
riscvassertions riscvassertions();
|
||||
logging logging(clk, reset, dut.uncore.HADDR, dut.uncore.HTRANS);
|
||||
|
||||
// pick tests based on modes supported
|
||||
initial begin
|
||||
@ -722,6 +723,7 @@ 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 (`F_SUPPORTED || ~`D_SUPPORTED) else $error("Can't support double without supporting float");
|
||||
end
|
||||
endmodule
|
||||
|
||||
@ -949,3 +951,13 @@ module instrNameDecTB(
|
||||
default: name = "ILLEGAL";
|
||||
endcase
|
||||
endmodule
|
||||
|
||||
module logging(
|
||||
input logic clk, reset,
|
||||
input logic [31:0] HADDR,
|
||||
input logic [1:0] HTRANS);
|
||||
|
||||
always @(posedge clk)
|
||||
if (HTRANS != 2'b00 && HADDR == 0)
|
||||
$display("Warning: access to memory address 0\n");
|
||||
endmodule
|
||||
|
@ -27,8 +27,8 @@
|
||||
|
||||
module testbench();
|
||||
|
||||
parameter waveOnICount = 2657000; // # of instructions at which to turn on waves in graphical sim
|
||||
|
||||
parameter waveOnICount = `BUSYBEAR*140000 + `BUILDROOT*2400000; // # 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)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////// DUT /////////////////////////////////////
|
||||
@ -248,6 +248,9 @@ module testbench();
|
||||
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
|
||||
@ -331,6 +334,8 @@ module testbench();
|
||||
`SCAN_PC(data_file_PCM, scan_file_PCM, trashString, trashString, InstrMExpected, PCMexpected);
|
||||
end
|
||||
|
||||
logging logging(clk, reset, dut.uncore.HADDR, dut.uncore.HTRANS);
|
||||
|
||||
// -------------------
|
||||
// Additional Hardware
|
||||
// -------------------
|
||||
@ -715,6 +720,16 @@ module testbench();
|
||||
endfunction
|
||||
endmodule
|
||||
|
||||
module logging(
|
||||
input logic clk, reset,
|
||||
input logic [31:0] HADDR,
|
||||
input logic [1:0] HTRANS);
|
||||
|
||||
always @(posedge clk)
|
||||
if (HTRANS != 2'b00 && HADDR == 0)
|
||||
$display("Warning: access to memory address 0\n");
|
||||
endmodule
|
||||
|
||||
|
||||
module instrTrackerTB(
|
||||
input logic clk, reset,
|
||||
|
Loading…
Reference in New Issue
Block a user