├── .gitignore ├── COPYING ├── Makefile ├── NERV.png ├── README.md ├── cexdata.sh ├── checks.cfg ├── disasm.py ├── examples └── icebreaker │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── firmware.c │ ├── firmware.s │ ├── icebreaker.pcf │ ├── icebreaker_soc.png │ ├── sections.lds │ ├── testbench.gtkw │ ├── testbench.sv │ └── top.v ├── firmware.c ├── firmware.s ├── nerv.sv ├── nervsoc.sv ├── sections.lds ├── testbench.gtkw ├── testbench.sv ├── trace.gtkw └── wrapper.sv /.gitignore: -------------------------------------------------------------------------------- 1 | /checks/ 2 | /cexdata/ 3 | /testbench.vcd 4 | /firmware.elf 5 | /firmware.hex 6 | /disasm.o 7 | /disasm.s 8 | /testbench 9 | /gtkwave.log 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | NERV -- Naive Educational RISC-V Processor 2 | 3 | Copyright (C) 2020 Claire Xenia Wolf 4 | Copyright (C) 2020 N. Engelhardt 5 | 6 | Permission to use, copy, modify, and/or distribute this software for any 7 | purpose with or without fee is hereby granted, provided that the above 8 | copyright notice and this permission notice appear in all copies. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # NERV -- Naive Educational RISC-V Processor 2 | # 3 | # Copyright (C) 2020 N. Engelhardt 4 | # Copyright (C) 2020 Claire Xenia Wolf 5 | # 6 | # Permission to use, copy, modify, and/or distribute this software for any 7 | # purpose with or without fee is hereby granted, provided that the above 8 | # copyright notice and this permission notice appear in all copies. 9 | # 10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | 18 | TOOLCHAIN_PREFIX?=riscv64-unknown-elf- 19 | 20 | test: firmware.hex testbench 21 | vvp -N testbench +vcd 22 | 23 | firmware.elf: firmware.s firmware.c 24 | $(TOOLCHAIN_PREFIX)gcc -march=rv32i -mabi=ilp32 -Os -Wall -Wextra -Wl,-Bstatic,-T,sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $^ 25 | 26 | firmware.hex: firmware.elf 27 | $(TOOLCHAIN_PREFIX)objcopy -O verilog $< $@ 28 | 29 | testbench: testbench.sv nerv.sv 30 | iverilog -o testbench -D STALL -D NERV_DBGREGS testbench.sv nerv.sv 31 | 32 | check: 33 | python3 ../../checks/genchecks.py 34 | $(MAKE) -C checks 35 | bash cexdata.sh 36 | cat cexdata/status.txt 37 | 38 | show: 39 | gtkwave testbench.vcd testbench.gtkw >> gtkwave.log 2>&1 & 40 | 41 | clean: 42 | rm -rf firmware.elf firmware.hex testbench testbench.vcd gtkwave.log 43 | rm -rf disasm.o disasm.s checks/ cexdata/ 44 | -------------------------------------------------------------------------------- /NERV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SymbioticEDA/nerv/dc5cff53f5f5666409025d94803da080500c3d7e/NERV.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NERV - Naive Educational RISC-V Processor 2 | ========================================= 3 | 4 | NERV is a very simple single-stage RV32I processor. 5 | It is equipped with an [RVFI interface](https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md) and is formally verified. 6 | 7 | ![system diagram](NERV.png) 8 | 9 | Running the simulation testbench 10 | -------------------------------- 11 | 12 | ``` 13 | git clone https://github.com/SymbioticEDA/nerv.git 14 | cd nerv 15 | make 16 | ``` 17 | 18 | 19 | Running the riscv-formal testbench 20 | ---------------------------------- 21 | 22 | ``` 23 | git clone https://github.com/SymbioticEDA/riscv-formal.git 24 | cd riscv-formal/cores/ 25 | git clone https://github.com/SymbioticEDA/nerv.git 26 | cd nerv 27 | make -j8 check 28 | ``` 29 | 30 | iCEBreaker SOC example 31 | ---------------------- 32 | 33 | See the [iCEBreaker SOC README](examples/icebreaker/README.md) 34 | -------------------------------------------------------------------------------- /cexdata.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # NERV -- Naive Educational RISC-V Processor 4 | # 5 | # Copyright (C) 2020 Claire Xenia Wolf 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | 19 | set -ex 20 | 21 | rm -rf cexdata 22 | mkdir cexdata 23 | 24 | for x in {checks,testbug[0-9][0-9][0-9]}/*/FAIL; do 25 | test -f $x || continue 26 | x=${x%/FAIL} 27 | y=${x/\//_} 28 | cp $x/logfile.txt cexdata/$y.log 29 | if test -f $x/engine_*/trace.vcd; then 30 | cp $x/engine_*/trace.vcd cexdata/$y.vcd 31 | python3 disasm.py cexdata/$y.vcd > cexdata/$y.asm 32 | fi 33 | done 34 | 35 | for x in {checks,testbug[0-9][0-9][0-9]}/*.sby; do 36 | test -f $x || continue 37 | x=${x%.sby} 38 | if [ -f $x/PASS ]; then 39 | printf "%-30s %s %10s\n" $x " pass " $(sed '/Elapsed process time/ { s/.*\]: //; s/ .*//; p; }; d;' $x/logfile.txt) 40 | elif [ -f $x/FAIL ]; then 41 | printf "%-30s %s %10s\n" $x "**FAIL**" $(sed '/Elapsed process time/ { s/.*\]: //; s/ .*//; p; }; d;' $x/logfile.txt) 42 | else 43 | printf "%-30s %s\n" $x unknown 44 | fi 45 | done | awk '{ print gensub(":", "", "g", $3), $0; }' | sort -n | cut -f2- -d' ' > cexdata/status.txt 46 | -------------------------------------------------------------------------------- /checks.cfg: -------------------------------------------------------------------------------- 1 | # NERV -- Naive Educational RISC-V Processor 2 | # 3 | # Copyright (C) 2020 Claire Xenia Wolf 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | [options] 18 | isa rv32i 19 | 20 | [depth] 21 | insn 10 22 | reg 5 10 23 | pc_fwd 5 10 24 | pc_bwd 5 10 25 | unique 1 5 10 26 | causal 5 10 27 | cover 1 10 28 | 29 | [sort] 30 | reg_ch0 31 | 32 | [defines] 33 | `define NERV_RVFI 34 | `define RISCV_FORMAL_ALIGNED_MEM 35 | 36 | [defines liveness] 37 | `define NERV_FAIRNESS 38 | 39 | [script-sources] 40 | read_verilog -sv @basedir@/cores/@core@/wrapper.sv 41 | read_verilog @basedir@/cores/@core@/@core@.sv 42 | 43 | [cover] 44 | always @* if (!reset) cover (channel[0].cnt_insns == 2); 45 | -------------------------------------------------------------------------------- /disasm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # NERV -- Naive Educational RISC-V Processor 4 | # 5 | # Copyright (C) 2020 Claire Xenia Wolf 6 | # 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | 19 | from Verilog_VCD.Verilog_VCD import parse_vcd 20 | from os import system 21 | from sys import argv 22 | 23 | rvfi_valid = None 24 | rvfi_order = None 25 | rvfi_insn = None 26 | 27 | for netinfo in parse_vcd(argv[1]).values(): 28 | for net in netinfo['nets']: 29 | # print(net["hier"], net["name"]) 30 | if net["hier"] == "rvfi_testbench.wrapper" and net["name"] == "rvfi_valid": 31 | rvfi_valid = netinfo['tv'] 32 | if net["hier"] == "rvfi_testbench.wrapper" and net["name"] == "rvfi_order": 33 | rvfi_order = netinfo['tv'] 34 | if net["hier"] == "rvfi_testbench.wrapper" and net["name"] == "rvfi_insn": 35 | rvfi_insn = netinfo['tv'] 36 | 37 | assert len(rvfi_valid) == len(rvfi_order) 38 | assert len(rvfi_valid) == len(rvfi_insn) 39 | 40 | prog = list() 41 | 42 | for tv_valid, tv_order, tv_insn in zip(rvfi_valid, rvfi_order, rvfi_insn): 43 | if tv_valid[1] == '1': 44 | prog.append((int(tv_order[1], 2), int(tv_insn[1], 2))) 45 | 46 | with open("disasm.s", "w") as f: 47 | for tv_order, tv_insn in sorted(prog): 48 | if tv_insn & 3 != 3 and tv_insn & 0xffff0000 == 0: 49 | print(".hword 0x%04x # %d" % (tv_insn, tv_order), file=f) 50 | else: 51 | print(".word 0x%08x # %d" % (tv_insn, tv_order), file=f) 52 | 53 | system("riscv64-unknown-elf-as -march=rv32i -o disasm.o disasm.s") 54 | system("riscv64-unknown-elf-objdump -d -M numeric,no-aliases disasm.o") 55 | 56 | -------------------------------------------------------------------------------- /examples/icebreaker/.gitignore: -------------------------------------------------------------------------------- 1 | /testbench.vcd 2 | /firmware.elf 3 | /firmware.hex 4 | /testbench 5 | /*.log 6 | /design.* -------------------------------------------------------------------------------- /examples/icebreaker/Makefile: -------------------------------------------------------------------------------- 1 | # NERV -- Naive Educational RISC-V Processor 2 | # 3 | # Copyright (C) 2020 N. Engelhardt 4 | # Copyright (C) 2020 Claire Xenia Wolf 5 | # 6 | # Permission to use, copy, modify, and/or distribute this software for any 7 | # purpose with or without fee is hereby granted, provided that the above 8 | # copyright notice and this permission notice appear in all copies. 9 | # 10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | 18 | TOOLCHAIN_PREFIX?=riscv64-unknown-elf- 19 | 20 | test: firmware.hex testbench 21 | vvp -N testbench +vcd 22 | 23 | firmware.elf: firmware.s firmware.c 24 | $(TOOLCHAIN_PREFIX)gcc -march=rv32i -mabi=ilp32 -Os -Wall -Wextra -Wl,-Bstatic,-T,sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $^ 25 | 26 | firmware.hex: firmware.elf 27 | $(TOOLCHAIN_PREFIX)objcopy -O verilog $< /dev/stdout | sed -r 's,(..) (..) (..) (..),\4\3\2\1,g' > $@ 28 | 29 | testbench: testbench.sv ../../nerv.sv ../../nervsoc.sv top.v firmware.hex 30 | iverilog -o testbench -D STALL -D NERV_DBGREGS testbench.sv ../../nerv.sv ../../nervsoc.sv top.v 31 | 32 | design.json: ../../nerv.sv ../../nervsoc.sv top.v firmware.hex 33 | yosys -l design_ys.log -p 'synth_ice40 -top top -json $@' ../../nerv.sv ../../nervsoc.sv top.v 34 | 35 | design.asc: design.json icebreaker.pcf 36 | nextpnr-ice40 -l design_pnr.log --up5k --package sg48 --asc design.asc --pcf icebreaker.pcf --json design.json --placer heap 37 | 38 | design.bin: design.asc 39 | icepack $< $@ 40 | 41 | prog: design.bin 42 | iceprog $< 43 | 44 | show: 45 | gtkwave testbench.vcd testbench.gtkw >> gtkwave.log 2>&1 & 46 | 47 | clean: 48 | rm -rf firmware.elf firmware.hex testbench testbench.vcd gtkwave.log 49 | rm -rf design.json design.asc design.bin design_ys.log design_pnr.log 50 | -------------------------------------------------------------------------------- /examples/icebreaker/README.md: -------------------------------------------------------------------------------- 1 | # SOC example for iCEBreaker 2 | 3 | ![iCEBreaker SOC](icebreaker_soc.png) 4 | 5 | # Demo 6 | 7 | Counts on the 8 LEDs. 8 | 9 | ``` 10 | make prog 11 | ``` 12 | 13 | # SOC 14 | 15 | The SOC instantiates [nervsoc](../../nervsoc.sv). 16 | 17 | * [top.v](top.v) Connects clock input and 8 LEDs on the iCEBreaker and provides power on reset 18 | * [sections.lds](sections.lds) sets flash and ram to 4k each. 19 | * [firmware.s](firmware.s) initialises registers, copies data section, initialises bss and starts main 20 | * [firmware.c](firmware.c) flashes the LEDs. 21 | -------------------------------------------------------------------------------- /examples/icebreaker/firmware.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Miodrag Milanovic 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | #include 21 | 22 | void delay(uint32_t count) 23 | { 24 | while(count-->0) { 25 | __asm__ volatile ("nop"); 26 | } 27 | } 28 | 29 | int main() 30 | { 31 | volatile uint32_t *leds = (void*)0x01000000; 32 | *leds = 0; 33 | uint32_t cnt = 0; 34 | while(1) 35 | { 36 | delay(100000); 37 | *leds = cnt++; 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /examples/icebreaker/firmware.s: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | .section .text 21 | .global main 22 | .global _start 23 | _start: 24 | addi x1, zero, 0 25 | addi x2, zero, 0 26 | addi x3, zero, 0 27 | addi x4, zero, 0 28 | addi x5, zero, 0 29 | addi x6, zero, 0 30 | addi x7, zero, 0 31 | addi x8, zero, 0 32 | addi x9, zero, 0 33 | addi x10, zero, 0 34 | addi x11, zero, 0 35 | addi x12, zero, 0 36 | addi x13, zero, 0 37 | addi x14, zero, 0 38 | addi x15, zero, 0 39 | addi x16, zero, 0 40 | addi x17, zero, 0 41 | addi x18, zero, 0 42 | addi x19, zero, 0 43 | addi x20, zero, 0 44 | addi x21, zero, 0 45 | addi x22, zero, 0 46 | addi x23, zero, 0 47 | addi x24, zero, 0 48 | addi x25, zero, 0 49 | addi x26, zero, 0 50 | addi x27, zero, 0 51 | addi x28, zero, 0 52 | addi x29, zero, 0 53 | addi x30, zero, 0 54 | addi x31, zero, 0 55 | 56 | # copy data section 57 | la a0, _sidata 58 | la a1, _sdata 59 | la a2, _edata 60 | bge a1, a2, end_init_data 61 | loop_init_data: 62 | lw a3, 0(a0) 63 | sw a3, 0(a1) 64 | addi a0, a0, 4 65 | addi a1, a1, 4 66 | blt a1, a2, loop_init_data 67 | end_init_data: 68 | 69 | # zero-init bss section 70 | la a0, _sbss 71 | la a1, _ebss 72 | bge a0, a1, end_init_bss 73 | loop_init_bss: 74 | sw zero, 0(a0) 75 | addi a0, a0, 4 76 | blt a0, a1, loop_init_bss 77 | end_init_bss: 78 | 79 | # place SP at the end of RAM 80 | li sp, 0x00001000 81 | 82 | # call main 83 | call main 84 | 85 | # halt 86 | ebreak 87 | -------------------------------------------------------------------------------- /examples/icebreaker/icebreaker.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn CLK 35 3 | 4 | # RS232 5 | set_io -nowarn RX 6 6 | set_io -nowarn TX 9 7 | 8 | # LEDs and Button 9 | set_io -nowarn BTN_N 10 10 | set_io -nowarn LEDR_N 11 11 | set_io -nowarn LEDG_N 37 12 | 13 | # RGB LED Driver 14 | set_io -nowarn LED_RED_N 39 15 | set_io -nowarn LED_GRN_N 40 16 | set_io -nowarn LED_BLU_N 41 17 | 18 | # SPI Flash 19 | set_io -nowarn FLASH_SCK 15 20 | set_io -nowarn FLASH_SSB 16 21 | set_io -nowarn FLASH_IO0 14 22 | set_io -nowarn FLASH_IO1 17 23 | set_io -nowarn FLASH_IO2 12 24 | set_io -nowarn FLASH_IO3 13 25 | 26 | # PMOD 1A 27 | set_io -nowarn P1A1 4 28 | set_io -nowarn P1A2 2 29 | set_io -nowarn P1A3 47 30 | set_io -nowarn P1A4 45 31 | set_io -nowarn P1A7 3 32 | set_io -nowarn P1A8 48 33 | set_io -nowarn P1A9 46 34 | set_io -nowarn P1A10 44 35 | 36 | # PMOD 1B 37 | set_io -nowarn P1B1 43 38 | set_io -nowarn P1B2 38 39 | set_io -nowarn P1B3 34 40 | set_io -nowarn P1B4 31 41 | set_io -nowarn P1B7 42 42 | set_io -nowarn P1B8 36 43 | set_io -nowarn P1B9 32 44 | set_io -nowarn P1B10 28 45 | 46 | # PMOD 2 47 | set_io -nowarn P2_1 27 48 | set_io -nowarn P2_2 25 49 | set_io -nowarn P2_3 21 50 | set_io -nowarn P2_4 19 51 | set_io -nowarn P2_7 26 52 | set_io -nowarn P2_8 23 53 | set_io -nowarn P2_9 20 54 | set_io -nowarn P2_10 18 55 | 56 | # LEDs and Buttons (PMOD 2) 57 | set_io -nowarn LED1 27 58 | set_io -nowarn LED2 25 59 | set_io -nowarn LED3 21 60 | set_io -nowarn BTN2 19 61 | set_io -nowarn LED5 26 62 | set_io -nowarn LED4 23 63 | set_io -nowarn BTN1 20 64 | set_io -nowarn BTN3 18 65 | -------------------------------------------------------------------------------- /examples/icebreaker/icebreaker_soc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SymbioticEDA/nerv/dc5cff53f5f5666409025d94803da080500c3d7e/examples/icebreaker/icebreaker_soc.png -------------------------------------------------------------------------------- /examples/icebreaker/sections.lds: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH(xr) : ORIGIN = 0x00000000, LENGTH = 0x001000 4 | RAM (rw) : ORIGIN = 0x00000000, LENGTH = 0x001000 5 | } 6 | 7 | SECTIONS { 8 | /* The program code and other data goes into FLASH */ 9 | .text : 10 | { 11 | . = ALIGN(4); 12 | *(.text) /* .text sections (code) */ 13 | *(.text*) /* .text* sections (code) */ 14 | *(.rodata) /* .rodata sections (constants, strings, etc.) */ 15 | *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ 16 | *(.srodata) /* .rodata sections (constants, strings, etc.) */ 17 | *(.srodata*) /* .rodata* sections (constants, strings, etc.) */ 18 | . = ALIGN(4); 19 | _etext = .; /* define a global symbol at end of code */ 20 | _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */ 21 | } >FLASH 22 | 23 | 24 | /* This is the initialized data section 25 | The program executes knowing that the data is in the RAM 26 | but the loader puts the initial values in the FLASH (inidata). 27 | It is one task of the startup to copy the initial values from FLASH to RAM. */ 28 | .data : AT ( _sidata ) 29 | { 30 | . = ALIGN(4); 31 | _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ 32 | _ram_start = .; /* create a global symbol at ram start for garbage collector */ 33 | . = ALIGN(4); 34 | *(.data) /* .data sections */ 35 | *(.data*) /* .data* sections */ 36 | *(.sdata) /* .sdata sections */ 37 | *(.sdata*) /* .sdata* sections */ 38 | . = ALIGN(4); 39 | _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ 40 | } >RAM 41 | 42 | /* Uninitialized data section */ 43 | .bss : 44 | { 45 | . = ALIGN(4); 46 | _sbss = .; /* define a global symbol at bss start; used by startup code */ 47 | *(.bss) 48 | *(.bss*) 49 | *(.sbss) 50 | *(.sbss*) 51 | *(COMMON) 52 | 53 | . = ALIGN(4); 54 | _ebss = .; /* define a global symbol at bss end; used by startup code */ 55 | } >RAM 56 | 57 | /* this is to define the start of the heap, and make sure we have a minimum size */ 58 | .heap : 59 | { 60 | . = ALIGN(4); 61 | _heap_start = .; /* define a global symbol at heap start */ 62 | } >RAM 63 | } 64 | -------------------------------------------------------------------------------- /examples/icebreaker/testbench.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.108 (w)1999-2020 BSI 3 | [*] Tue Nov 3 15:34:10 2020 4 | [*] 5 | [dumpfile] "/home/matt/work/symbiotic/riscv-formal/cores/nerv/examples/icebreaker/testbench.vcd" 6 | [dumpfile_mtime] "Tue Nov 3 15:33:50 2020" 7 | [dumpfile_size] 472777 8 | [savefile] "/home/matt/work/symbiotic/riscv-formal/cores/nerv/examples/icebreaker/testbench.gtkw" 9 | [timestart] 0 10 | [size] 1920 1015 11 | [pos] -1 -1 12 | *-11.000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] testbench. 14 | [treeopen] testbench.dut. 15 | [treeopen] testbench.dut.soc. 16 | [sst_width] 240 17 | [signals_width] 286 18 | [sst_expanded] 1 19 | [sst_vpaned_height] 289 20 | @28 21 | testbench.LEDR_N 22 | testbench.LEDG_N 23 | testbench.LED1 24 | testbench.LED2 25 | testbench.LED3 26 | testbench.LED4 27 | testbench.LED5 28 | @201 29 | - 30 | @28 31 | testbench.clock 32 | @22 33 | testbench.cycles[31:0] 34 | @200 35 | - 36 | @28 37 | testbench.dut.soc.clock 38 | @22 39 | testbench.dut.soc.dmem_addr[31:0] 40 | testbench.dut.soc.dmem_rdata[31:0] 41 | @28 42 | testbench.dut.soc.dmem_valid 43 | @22 44 | testbench.dut.soc.dmem_wdata[31:0] 45 | testbench.dut.soc.dmem_wstrb[3:0] 46 | testbench.dut.soc.imem_addr[31:0] 47 | testbench.dut.soc.imem_data[31:0] 48 | testbench.dut.soc.leds[31:0] 49 | @28 50 | testbench.dut.soc.reset 51 | testbench.dut.soc.stall 52 | testbench.dut.soc.trap 53 | [pattern_trace] 1 54 | [pattern_trace] 0 55 | -------------------------------------------------------------------------------- /examples/icebreaker/testbench.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 N. Engelhardt 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module testbench; 21 | 22 | localparam TIMEOUT = (1<<10); 23 | reg clock; 24 | 25 | wire LEDR_N, LEDG_N, LED1, LED2, LED3, LED4, LED5; 26 | 27 | always #5 clock = clock === 1'b0; 28 | 29 | top dut ( 30 | .CLK(clock), 31 | .LEDR_N(LEDR_N), 32 | .LEDG_N(LEDG_N), 33 | .LED1(LED1), 34 | .LED2(LED2), 35 | .LED3(LED3), 36 | .LED4(LED4), 37 | .LED5(LED5) 38 | ); 39 | 40 | initial begin 41 | if ($test$plusargs("vcd")) begin 42 | $dumpfile("testbench.vcd"); 43 | $dumpvars(0, testbench); 44 | end 45 | end 46 | 47 | reg [31:0] cycles = 0; 48 | 49 | always @(posedge clock) begin 50 | cycles <= cycles + 32'h1; 51 | if (cycles >= TIMEOUT) begin 52 | $display("Simulated %0d cycles", cycles); 53 | $finish; 54 | end 55 | end 56 | 57 | endmodule 58 | -------------------------------------------------------------------------------- /examples/icebreaker/top.v: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Miodrag Milanovic 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module top( 21 | input CLK, 22 | output LEDR_N, 23 | output LEDG_N, 24 | output LED1, 25 | output LED2, 26 | output LED3, 27 | output LED4, 28 | output LED5 29 | ); 30 | 31 | // Create reset signal 16 clocks long 32 | reg reset = 1'b1; 33 | reg [3:0] reset_cnt = 0; 34 | always @(posedge CLK) 35 | begin 36 | reset <= (reset_cnt != 15); 37 | reset_cnt <= reset_cnt + (reset_cnt != 15); 38 | end 39 | 40 | // Map 7 LEDs that exists on icebreaker board 41 | wire [31:0] leds; 42 | assign { LEDR_N, LEDG_N, LED1, LED2, LED3, LED4, LED5 } = {~leds[6:5], leds[4:0]}; 43 | 44 | nervsoc soc ( 45 | .clock(CLK), 46 | .reset(reset), 47 | .leds(leds) 48 | ); 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /firmware.c: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | void putc(int c) 21 | { 22 | volatile char *p = (void*)0x02000000; 23 | *p = c; 24 | } 25 | 26 | void puts(char *s) 27 | { 28 | while (*s) putc(*(s++)); 29 | } 30 | 31 | int main() 32 | { 33 | puts("Hello World!\n"); 34 | putc(0); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /firmware.s: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | .section .text 21 | .global main 22 | .global _start 23 | _start: 24 | addi x1, zero, 0 25 | addi x2, zero, 0 26 | addi x3, zero, 0 27 | addi x4, zero, 0 28 | addi x5, zero, 0 29 | addi x6, zero, 0 30 | addi x7, zero, 0 31 | addi x8, zero, 0 32 | addi x9, zero, 0 33 | addi x10, zero, 0 34 | addi x11, zero, 0 35 | addi x12, zero, 0 36 | addi x13, zero, 0 37 | addi x14, zero, 0 38 | addi x15, zero, 0 39 | addi x16, zero, 0 40 | addi x17, zero, 0 41 | addi x18, zero, 0 42 | addi x19, zero, 0 43 | addi x20, zero, 0 44 | addi x21, zero, 0 45 | addi x22, zero, 0 46 | addi x23, zero, 0 47 | addi x24, zero, 0 48 | addi x25, zero, 0 49 | addi x26, zero, 0 50 | addi x27, zero, 0 51 | addi x28, zero, 0 52 | addi x29, zero, 0 53 | addi x30, zero, 0 54 | addi x31, zero, 0 55 | 56 | # place SP at the end of RAM 57 | li sp, 0x00010000 58 | 59 | # copy data section 60 | la a0, _sidata 61 | la a1, _sdata 62 | la a2, _edata 63 | bge a1, a2, end_init_data 64 | loop_init_data: 65 | lw a3, 0(a0) 66 | sw a3, 0(a1) 67 | addi a0, a0, 4 68 | addi a1, a1, 4 69 | blt a1, a2, loop_init_data 70 | end_init_data: 71 | 72 | # zero-init bss section 73 | la a0, _sbss 74 | la a1, _ebss 75 | bge a0, a1, end_init_bss 76 | loop_init_bss: 77 | sw zero, 0(a0) 78 | addi a0, a0, 4 79 | blt a0, a1, loop_init_bss 80 | end_init_bss: 81 | 82 | # call main 83 | call main 84 | 85 | # halt 86 | ebreak 87 | -------------------------------------------------------------------------------- /nerv.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module nerv #( 21 | parameter [31:0] RESET_ADDR = 32'h 0000_0000, 22 | parameter integer NUMREGS = 32 23 | ) ( 24 | input clock, 25 | input reset, 26 | input stall, 27 | output trap, 28 | 29 | `ifdef NERV_RVFI 30 | output reg rvfi_valid, 31 | output reg [63:0] rvfi_order, 32 | output reg [31:0] rvfi_insn, 33 | output reg rvfi_trap, 34 | output reg rvfi_halt, 35 | output reg rvfi_intr, 36 | output reg [ 1:0] rvfi_mode, 37 | output reg [ 1:0] rvfi_ixl, 38 | output reg [ 4:0] rvfi_rs1_addr, 39 | output reg [ 4:0] rvfi_rs2_addr, 40 | output reg [31:0] rvfi_rs1_rdata, 41 | output reg [31:0] rvfi_rs2_rdata, 42 | output reg [ 4:0] rvfi_rd_addr, 43 | output reg [31:0] rvfi_rd_wdata, 44 | output reg [31:0] rvfi_pc_rdata, 45 | output reg [31:0] rvfi_pc_wdata, 46 | output reg [31:0] rvfi_mem_addr, 47 | output reg [ 3:0] rvfi_mem_rmask, 48 | output reg [ 3:0] rvfi_mem_wmask, 49 | output reg [31:0] rvfi_mem_rdata, 50 | output reg [31:0] rvfi_mem_wdata, 51 | `endif 52 | 53 | // we have 2 external memories 54 | // one is instruction memory 55 | output [31:0] imem_addr, 56 | input [31:0] imem_data, 57 | 58 | // the other is data memory 59 | output dmem_valid, 60 | output [31:0] dmem_addr, 61 | output [ 3:0] dmem_wstrb, 62 | output [31:0] dmem_wdata, 63 | input [31:0] dmem_rdata 64 | ); 65 | reg mem_wr_enable; 66 | reg [31:0] mem_wr_addr; 67 | reg [31:0] mem_wr_data; 68 | reg [3:0] mem_wr_strb; 69 | 70 | reg mem_rd_enable; 71 | reg [31:0] mem_rd_addr; 72 | reg [4:0] mem_rd_reg; 73 | reg [4:0] mem_rd_func; 74 | 75 | reg mem_rd_enable_q; 76 | reg [4:0] mem_rd_reg_q; 77 | reg [4:0] mem_rd_func_q; 78 | 79 | // delayed copies of mem_rd 80 | always @(posedge clock) begin 81 | if (!stall) begin 82 | mem_rd_enable_q <= mem_rd_enable; 83 | mem_rd_reg_q <= mem_rd_reg; 84 | mem_rd_func_q <= mem_rd_func; 85 | end 86 | if (reset) begin 87 | mem_rd_enable_q <= 0; 88 | end 89 | end 90 | 91 | // memory signals 92 | assign dmem_valid = mem_wr_enable || mem_rd_enable; 93 | assign dmem_addr = mem_wr_enable ? mem_wr_addr : mem_rd_enable ? mem_rd_addr : 32'h x; 94 | assign dmem_wstrb = mem_wr_enable ? mem_wr_strb : mem_rd_enable ? 4'h 0 : 4'h x; 95 | assign dmem_wdata = mem_wr_enable ? mem_wr_data : 32'h x; 96 | 97 | // registers, instruction reg, program counter, next pc 98 | reg [31:0] regfile [0:NUMREGS-1]; 99 | wire [31:0] insn; 100 | reg [31:0] npc; 101 | reg [31:0] pc; 102 | 103 | reg [31:0] imem_addr_q; 104 | 105 | always @(posedge clock) begin 106 | imem_addr_q <= imem_addr; 107 | end 108 | 109 | // instruction memory pointer 110 | assign imem_addr = (stall || trap || mem_rd_enable_q) ? imem_addr_q : npc; 111 | assign insn = imem_data; 112 | 113 | // rs1 and rs2 are source for the instruction 114 | wire [31:0] rs1_value = !insn_rs1 ? 0 : regfile[insn_rs1]; 115 | wire [31:0] rs2_value = !insn_rs2 ? 0 : regfile[insn_rs2]; 116 | 117 | // components of the instruction 118 | wire [6:0] insn_funct7; 119 | wire [4:0] insn_rs2; 120 | wire [4:0] insn_rs1; 121 | wire [2:0] insn_funct3; 122 | wire [4:0] insn_rd; 123 | wire [6:0] insn_opcode; 124 | 125 | // split R-type instruction - see section 2.2 of RiscV spec 126 | assign {insn_funct7, insn_rs2, insn_rs1, insn_funct3, insn_rd, insn_opcode} = insn; 127 | 128 | // setup for I, S, B & J type instructions 129 | // I - short immediates and loads 130 | wire [11:0] imm_i; 131 | assign imm_i = insn[31:20]; 132 | 133 | // S - stores 134 | wire [11:0] imm_s; 135 | assign imm_s[11:5] = insn_funct7, imm_s[4:0] = insn_rd; 136 | 137 | // B - conditionals 138 | wire [12:0] imm_b; 139 | assign {imm_b[12], imm_b[10:5]} = insn_funct7, {imm_b[4:1], imm_b[11]} = insn_rd, imm_b[0] = 1'b0; 140 | 141 | // J - unconditional jumps 142 | wire [20:0] imm_j; 143 | assign {imm_j[20], imm_j[10:1], imm_j[11], imm_j[19:12], imm_j[0]} = {insn[31:12], 1'b0}; 144 | 145 | wire [31:0] imm_i_sext = $signed(imm_i); 146 | wire [31:0] imm_s_sext = $signed(imm_s); 147 | wire [31:0] imm_b_sext = $signed(imm_b); 148 | wire [31:0] imm_j_sext = $signed(imm_j); 149 | 150 | // opcodes - see section 19 of RiscV spec 151 | localparam OPCODE_LOAD = 7'b 00_000_11; 152 | localparam OPCODE_STORE = 7'b 01_000_11; 153 | localparam OPCODE_MADD = 7'b 10_000_11; 154 | localparam OPCODE_BRANCH = 7'b 11_000_11; 155 | 156 | localparam OPCODE_LOAD_FP = 7'b 00_001_11; 157 | localparam OPCODE_STORE_FP = 7'b 01_001_11; 158 | localparam OPCODE_MSUB = 7'b 10_001_11; 159 | localparam OPCODE_JALR = 7'b 11_001_11; 160 | 161 | localparam OPCODE_CUSTOM_0 = 7'b 00_010_11; 162 | localparam OPCODE_CUSTOM_1 = 7'b 01_010_11; 163 | localparam OPCODE_NMSUB = 7'b 10_010_11; 164 | localparam OPCODE_RESERVED_0 = 7'b 11_010_11; 165 | 166 | localparam OPCODE_MISC_MEM = 7'b 00_011_11; 167 | localparam OPCODE_AMO = 7'b 01_011_11; 168 | localparam OPCODE_NMADD = 7'b 10_011_11; 169 | localparam OPCODE_JAL = 7'b 11_011_11; 170 | 171 | localparam OPCODE_OP_IMM = 7'b 00_100_11; 172 | localparam OPCODE_OP = 7'b 01_100_11; 173 | localparam OPCODE_OP_FP = 7'b 10_100_11; 174 | localparam OPCODE_SYSTEM = 7'b 11_100_11; 175 | 176 | localparam OPCODE_AUIPC = 7'b 00_101_11; 177 | localparam OPCODE_LUI = 7'b 01_101_11; 178 | localparam OPCODE_RESERVED_1 = 7'b 10_101_11; 179 | localparam OPCODE_RESERVED_2 = 7'b 11_101_11; 180 | 181 | localparam OPCODE_OP_IMM_32 = 7'b 00_110_11; 182 | localparam OPCODE_OP_32 = 7'b 01_110_11; 183 | localparam OPCODE_CUSTOM_2 = 7'b 10_110_11; 184 | localparam OPCODE_CUSTOM_3 = 7'b 11_110_11; 185 | 186 | // next write, next destination (rd), illegal instruction registers 187 | reg next_wr; 188 | reg [31:0] next_rd; 189 | reg illinsn; 190 | 191 | reg trapped; 192 | reg trapped_q; 193 | assign trap = trapped; 194 | 195 | always @* begin 196 | // advance pc 197 | npc = pc + 4; 198 | 199 | // defaults for read, write 200 | next_wr = 0; 201 | next_rd = 0; 202 | illinsn = 0; 203 | 204 | mem_wr_enable = 0; 205 | mem_wr_addr = 'hx; 206 | mem_wr_data = 'hx; 207 | mem_wr_strb = 'hx; 208 | 209 | mem_rd_enable = 0; 210 | mem_rd_addr = 'hx; 211 | mem_rd_reg = 'hx; 212 | mem_rd_func = 'hx; 213 | 214 | // act on opcodes 215 | case (insn_opcode) 216 | // Load Upper Immediate 217 | OPCODE_LUI: begin 218 | next_wr = 1; 219 | next_rd = insn[31:12] << 12; 220 | end 221 | // Add Upper Immediate to Program Counter 222 | OPCODE_AUIPC: begin 223 | next_wr = 1; 224 | next_rd = (insn[31:12] << 12) + pc; 225 | end 226 | // Jump And Link (unconditional jump) 227 | OPCODE_JAL: begin 228 | next_wr = 1; 229 | next_rd = npc; 230 | npc = pc + imm_j_sext; 231 | if (npc & 32'b 11) begin 232 | illinsn = 1; 233 | npc = npc & ~32'b 11; 234 | end 235 | end 236 | // Jump And Link Register (indirect jump) 237 | OPCODE_JALR: begin 238 | case (insn_funct3) 239 | 3'b 000 /* JALR */: begin 240 | next_wr = 1; 241 | next_rd = npc; 242 | npc = (rs1_value + imm_i_sext) & ~32'b 1; 243 | end 244 | default: illinsn = 1; 245 | endcase 246 | if (npc & 32'b 11) begin 247 | illinsn = 1; 248 | npc = npc & ~32'b 11; 249 | end 250 | end 251 | // branch instructions: Branch If Equal, Branch Not Equal, Branch Less Than, Branch Greater Than, Branch Less Than Unsigned, Branch Greater Than Unsigned 252 | OPCODE_BRANCH: begin 253 | case (insn_funct3) 254 | 3'b 000 /* BEQ */: begin if (rs1_value == rs2_value) npc = pc + imm_b_sext; end 255 | 3'b 001 /* BNE */: begin if (rs1_value != rs2_value) npc = pc + imm_b_sext; end 256 | 3'b 100 /* BLT */: begin if ($signed(rs1_value) < $signed(rs2_value)) npc = pc + imm_b_sext; end 257 | 3'b 101 /* BGE */: begin if ($signed(rs1_value) >= $signed(rs2_value)) npc = pc + imm_b_sext; end 258 | 3'b 110 /* BLTU */: begin if (rs1_value < rs2_value) npc = pc + imm_b_sext; end 259 | 3'b 111 /* BGEU */: begin if (rs1_value >= rs2_value) npc = pc + imm_b_sext; end 260 | default: illinsn = 1; 261 | endcase 262 | if (npc & 32'b 11) begin 263 | illinsn = 1; 264 | npc = npc & ~32'b 11; 265 | end 266 | end 267 | // load from memory into rd: Load Byte, Load Halfword, Load Word, Load Byte Unsigned, Load Halfword Unsigned 268 | OPCODE_LOAD: begin 269 | mem_rd_addr = rs1_value + imm_i_sext; 270 | casez ({insn_funct3, mem_rd_addr[1:0]}) 271 | 5'b 000_zz /* LB */, 272 | 5'b 001_z0 /* LH */, 273 | 5'b 010_00 /* LW */, 274 | 5'b 100_zz /* LBU */, 275 | 5'b 101_z0 /* LHU */: begin 276 | mem_rd_enable = 1; 277 | mem_rd_reg = insn_rd; 278 | mem_rd_func = {mem_rd_addr[1:0], insn_funct3}; 279 | mem_rd_addr = {mem_rd_addr[31:2], 2'b 00}; 280 | end 281 | default: illinsn = 1; 282 | endcase 283 | end 284 | // store to memory instructions: Store Byte, Store Halfword, Store Word 285 | OPCODE_STORE: begin 286 | mem_wr_addr = rs1_value + imm_s_sext; 287 | casez ({insn_funct3, mem_wr_addr[1:0]}) 288 | 5'b 000_zz /* SB */, 289 | 5'b 001_z0 /* SH */, 290 | 5'b 010_00 /* SW */: begin 291 | mem_wr_enable = 1; 292 | mem_wr_data = rs2_value; 293 | mem_wr_strb = 4'b 1111; 294 | case (insn_funct3) 295 | 3'b 000 /* SB */: begin mem_wr_strb = 4'b 0001; end 296 | 3'b 001 /* SH */: begin mem_wr_strb = 4'b 0011; end 297 | 3'b 010 /* SW */: begin mem_wr_strb = 4'b 1111; end 298 | endcase 299 | mem_wr_data = mem_wr_data << (8*mem_wr_addr[1:0]); 300 | mem_wr_strb = mem_wr_strb << mem_wr_addr[1:0]; 301 | mem_wr_addr = {mem_wr_addr[31:2], 2'b 00}; 302 | end 303 | default: illinsn = 1; 304 | endcase 305 | end 306 | // immediate ALU instructions: Add Immediate, Set Less Than Immediate, Set Less Than Immediate Unsigned, XOR Immediate, 307 | // OR Immediate, And Immediate, Shift Left Logical Immediate, Shift Right Logical Immediate, Shift Right Arithmetic Immediate 308 | OPCODE_OP_IMM: begin 309 | casez ({insn_funct7, insn_funct3}) 310 | 10'b zzzzzzz_000 /* ADDI */: begin next_wr = 1; next_rd = rs1_value + imm_i_sext; end 311 | 10'b zzzzzzz_010 /* SLTI */: begin next_wr = 1; next_rd = $signed(rs1_value) < $signed(imm_i_sext); end 312 | 10'b zzzzzzz_011 /* SLTIU */: begin next_wr = 1; next_rd = rs1_value < imm_i_sext; end 313 | 10'b zzzzzzz_100 /* XORI */: begin next_wr = 1; next_rd = rs1_value ^ imm_i_sext; end 314 | 10'b zzzzzzz_110 /* ORI */: begin next_wr = 1; next_rd = rs1_value | imm_i_sext; end 315 | 10'b zzzzzzz_111 /* ANDI */: begin next_wr = 1; next_rd = rs1_value & imm_i_sext; end 316 | 10'b 0000000_001 /* SLLI */: begin next_wr = 1; next_rd = rs1_value << insn[24:20]; end 317 | 10'b 0000000_101 /* SRLI */: begin next_wr = 1; next_rd = rs1_value >> insn[24:20]; end 318 | 10'b 0100000_101 /* SRAI */: begin next_wr = 1; next_rd = $signed(rs1_value) >>> insn[24:20]; end 319 | default: illinsn = 1; 320 | endcase 321 | end 322 | OPCODE_OP: begin 323 | // ALU instructions: Add, Subtract, Shift Left Logical, Set Left Than, Set Less Than Unsigned, XOR, Shift Right Logical, 324 | // Shift Right Arithmetic, OR, AND 325 | case ({insn_funct7, insn_funct3}) 326 | 10'b 0000000_000 /* ADD */: begin next_wr = 1; next_rd = rs1_value + rs2_value; end 327 | 10'b 0100000_000 /* SUB */: begin next_wr = 1; next_rd = rs1_value - rs2_value; end 328 | 10'b 0000000_001 /* SLL */: begin next_wr = 1; next_rd = rs1_value << rs2_value[4:0]; end 329 | 10'b 0000000_010 /* SLT */: begin next_wr = 1; next_rd = $signed(rs1_value) < $signed(rs2_value); end 330 | 10'b 0000000_011 /* SLTU */: begin next_wr = 1; next_rd = rs1_value < rs2_value; end 331 | 10'b 0000000_100 /* XOR */: begin next_wr = 1; next_rd = rs1_value ^ rs2_value; end 332 | 10'b 0000000_101 /* SRL */: begin next_wr = 1; next_rd = rs1_value >> rs2_value[4:0]; end 333 | 10'b 0100000_101 /* SRA */: begin next_wr = 1; next_rd = $signed(rs1_value) >>> rs2_value[4:0]; end 334 | 10'b 0000000_110 /* OR */: begin next_wr = 1; next_rd = rs1_value | rs2_value; end 335 | 10'b 0000000_111 /* AND */: begin next_wr = 1; next_rd = rs1_value & rs2_value; end 336 | default: illinsn = 1; 337 | endcase 338 | end 339 | default: illinsn = 1; 340 | endcase 341 | 342 | // if last cycle was a memory read, then this cycle is the 2nd part of it and imem_data will not be a valid instruction 343 | if (mem_rd_enable_q) begin 344 | npc = pc; 345 | next_wr = 0; 346 | illinsn = 0; 347 | mem_rd_enable = 0; 348 | mem_wr_enable = 0; 349 | end 350 | 351 | // reset 352 | if (reset || reset_q) begin 353 | npc = RESET_ADDR; 354 | next_wr = 0; 355 | illinsn = 0; 356 | mem_rd_enable = 0; 357 | mem_wr_enable = 0; 358 | end 359 | end 360 | 361 | reg reset_q; 362 | reg [31:0] mem_rdata; 363 | `ifdef NERV_RVFI 364 | reg rvfi_pre_valid; 365 | reg [ 4:0] rvfi_pre_rd_addr; 366 | reg [31:0] rvfi_pre_rd_wdata; 367 | `endif 368 | 369 | // mem read functions: Lower and Upper Bytes, signed and unsigned 370 | always @* begin 371 | mem_rdata = dmem_rdata >> (8*mem_rd_func_q[4:3]); 372 | case (mem_rd_func_q[2:0]) 373 | 3'b 000 /* LB */: begin mem_rdata = $signed(mem_rdata[7:0]); end 374 | 3'b 001 /* LH */: begin mem_rdata = $signed(mem_rdata[15:0]); end 375 | 3'b 100 /* LBU */: begin mem_rdata = mem_rdata[7:0]; end 376 | 3'b 101 /* LHU */: begin mem_rdata = mem_rdata[15:0]; end 377 | endcase 378 | end 379 | 380 | // every cycle 381 | always @(posedge clock) begin 382 | reset_q <= reset; 383 | trapped_q <= trapped; 384 | 385 | // increment pc if possible 386 | if (!trapped && !stall && !reset && !reset_q) begin 387 | if (illinsn) 388 | trapped <= 1; 389 | pc <= npc; 390 | `ifdef NERV_RVFI 391 | rvfi_pre_valid <= !mem_rd_enable_q; 392 | rvfi_order <= rvfi_order + 1; 393 | rvfi_insn <= insn; 394 | rvfi_trap <= illinsn; 395 | rvfi_halt <= illinsn; 396 | rvfi_intr <= 0; 397 | rvfi_mode <= 3; 398 | rvfi_ixl <= 1; 399 | rvfi_rs1_addr <= insn_rs1; 400 | rvfi_rs2_addr <= insn_rs2; 401 | rvfi_rs1_rdata <= rs1_value; 402 | rvfi_rs2_rdata <= rs2_value; 403 | rvfi_pre_rd_addr <= next_wr ? insn_rd : 0; 404 | rvfi_pre_rd_wdata <= next_wr && insn_rd ? next_rd : 0; 405 | rvfi_pc_rdata <= pc; 406 | rvfi_pc_wdata <= npc; 407 | if (dmem_valid) begin 408 | rvfi_mem_addr <= dmem_addr; 409 | case ({mem_rd_enable, insn_funct3}) 410 | 4'b 1_000 /* LB */: begin rvfi_mem_rmask <= 4'b 0001 << mem_rd_func[4:3]; end 411 | 4'b 1_001 /* LH */: begin rvfi_mem_rmask <= 4'b 0011 << mem_rd_func[4:3]; end 412 | 4'b 1_010 /* LW */: begin rvfi_mem_rmask <= 4'b 1111 << mem_rd_func[4:3]; end 413 | 4'b 1_100 /* LBU */: begin rvfi_mem_rmask <= 4'b 0001 << mem_rd_func[4:3]; end 414 | 4'b 1_101 /* LHU */: begin rvfi_mem_rmask <= 4'b 0011 << mem_rd_func[4:3]; end 415 | default: rvfi_mem_rmask <= 0; 416 | endcase 417 | rvfi_mem_wmask <= dmem_wstrb; 418 | rvfi_mem_wdata <= dmem_wdata; 419 | end else begin 420 | rvfi_mem_addr <= 0; 421 | rvfi_mem_rmask <= 0; 422 | rvfi_mem_wmask <= 0; 423 | rvfi_mem_wdata <= 0; 424 | end 425 | `endif 426 | // update registers from memory or rd (destination) 427 | if (mem_rd_enable_q || next_wr) 428 | regfile[mem_rd_enable_q ? mem_rd_reg_q : insn_rd] <= mem_rd_enable_q ? mem_rdata : next_rd; 429 | end 430 | 431 | // reset 432 | if (reset || reset_q) begin 433 | pc <= RESET_ADDR - (reset ? 4 : 0); 434 | trapped <= 0; 435 | `ifdef NERV_RVFI 436 | rvfi_pre_valid <= 0; 437 | rvfi_order <= 0; 438 | `endif 439 | end 440 | end 441 | 442 | `ifdef NERV_RVFI 443 | always @* begin 444 | if (mem_rd_enable_q) begin 445 | rvfi_rd_addr = mem_rd_reg_q; 446 | rvfi_rd_wdata = mem_rd_reg_q ? mem_rdata : 0; 447 | end else begin 448 | rvfi_rd_addr = rvfi_pre_rd_addr; 449 | rvfi_rd_wdata = rvfi_pre_rd_wdata; 450 | end 451 | rvfi_valid = rvfi_pre_valid && !stall && !reset && !reset_q && !trapped_q; 452 | rvfi_mem_rdata = dmem_rdata; 453 | end 454 | `endif 455 | 456 | `ifdef NERV_DBGREGS 457 | wire [31:0] dbg_reg_x0 = 0; 458 | wire [31:0] dbg_reg_x1 = regfile[1]; 459 | wire [31:0] dbg_reg_x2 = regfile[2]; 460 | wire [31:0] dbg_reg_x3 = regfile[3]; 461 | wire [31:0] dbg_reg_x4 = regfile[4]; 462 | wire [31:0] dbg_reg_x5 = regfile[5]; 463 | wire [31:0] dbg_reg_x6 = regfile[6]; 464 | wire [31:0] dbg_reg_x7 = regfile[7]; 465 | wire [31:0] dbg_reg_x8 = regfile[8]; 466 | wire [31:0] dbg_reg_x9 = regfile[9]; 467 | wire [31:0] dbg_reg_x10 = regfile[10]; 468 | wire [31:0] dbg_reg_x11 = regfile[11]; 469 | wire [31:0] dbg_reg_x12 = regfile[12]; 470 | wire [31:0] dbg_reg_x13 = regfile[13]; 471 | wire [31:0] dbg_reg_x14 = regfile[14]; 472 | wire [31:0] dbg_reg_x15 = regfile[15]; 473 | wire [31:0] dbg_reg_x16 = regfile[16]; 474 | wire [31:0] dbg_reg_x17 = regfile[17]; 475 | wire [31:0] dbg_reg_x18 = regfile[18]; 476 | wire [31:0] dbg_reg_x19 = regfile[19]; 477 | wire [31:0] dbg_reg_x20 = regfile[20]; 478 | wire [31:0] dbg_reg_x21 = regfile[21]; 479 | wire [31:0] dbg_reg_x22 = regfile[22]; 480 | wire [31:0] dbg_reg_x23 = regfile[23]; 481 | wire [31:0] dbg_reg_x24 = regfile[24]; 482 | wire [31:0] dbg_reg_x25 = regfile[25]; 483 | wire [31:0] dbg_reg_x26 = regfile[26]; 484 | wire [31:0] dbg_reg_x27 = regfile[27]; 485 | wire [31:0] dbg_reg_x28 = regfile[28]; 486 | wire [31:0] dbg_reg_x29 = regfile[29]; 487 | wire [31:0] dbg_reg_x30 = regfile[30]; 488 | wire [31:0] dbg_reg_x31 = regfile[31]; 489 | `endif 490 | endmodule 491 | -------------------------------------------------------------------------------- /nervsoc.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module nervsoc ( 21 | input clock, 22 | input reset, 23 | output reg [31:0] leds 24 | ); 25 | reg [31:0] imem [0:1023]; 26 | reg [31:0] dmem [0:1023]; 27 | 28 | wire stall = 0; 29 | wire trap; 30 | 31 | wire [31:0] imem_addr; 32 | reg [31:0] imem_data; 33 | 34 | wire dmem_valid; 35 | wire [31:0] dmem_addr; 36 | wire [3:0] dmem_wstrb; 37 | wire [31:0] dmem_wdata; 38 | reg [31:0] dmem_rdata; 39 | 40 | initial begin 41 | $readmemh("firmware.hex", imem); 42 | end 43 | 44 | always @(posedge clock) 45 | imem_data <= imem[imem_addr[31:2]]; 46 | 47 | always @(posedge clock) begin 48 | if (dmem_valid) begin 49 | if (dmem_addr == 32'h 0100_0000) begin 50 | if (dmem_wstrb[0]) leds[ 7: 0] <= dmem_wdata[ 7: 0]; 51 | if (dmem_wstrb[1]) leds[15: 8] <= dmem_wdata[15: 8]; 52 | if (dmem_wstrb[2]) leds[23:16] <= dmem_wdata[23:16]; 53 | if (dmem_wstrb[3]) leds[31:24] <= dmem_wdata[31:24]; 54 | end else begin 55 | if (dmem_wstrb[0]) dmem[dmem_addr[31:2]][ 7: 0] <= dmem_wdata[ 7: 0]; 56 | if (dmem_wstrb[1]) dmem[dmem_addr[31:2]][15: 8] <= dmem_wdata[15: 8]; 57 | if (dmem_wstrb[2]) dmem[dmem_addr[31:2]][23:16] <= dmem_wdata[23:16]; 58 | if (dmem_wstrb[3]) dmem[dmem_addr[31:2]][31:24] <= dmem_wdata[31:24]; 59 | end 60 | dmem_rdata <= dmem[dmem_addr[31:2]]; 61 | end 62 | end 63 | 64 | nerv cpu ( 65 | .clock (clock ), 66 | .reset (reset ), 67 | .stall (stall ), 68 | .trap (trap ), 69 | 70 | .imem_addr (imem_addr ), 71 | .imem_data (imem_data ), 72 | 73 | .dmem_valid(dmem_valid), 74 | .dmem_addr (dmem_addr ), 75 | .dmem_wstrb(dmem_wstrb), 76 | .dmem_wdata(dmem_wdata), 77 | .dmem_rdata(dmem_rdata) 78 | ); 79 | endmodule 80 | -------------------------------------------------------------------------------- /sections.lds: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | /* the memory in the testbench is 64k in size; 4 | * set LENGTH=48k and leave at least 16k for stack */ 5 | RAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0x00c000 6 | } 7 | 8 | SECTIONS { 9 | /* The program code and other data goes into FLASH */ 10 | .text : 11 | { 12 | . = ALIGN(4); 13 | *(.text) /* .text sections (code) */ 14 | *(.text*) /* .text* sections (code) */ 15 | *(.rodata) /* .rodata sections (constants, strings, etc.) */ 16 | *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ 17 | *(.srodata) /* .rodata sections (constants, strings, etc.) */ 18 | *(.srodata*) /* .rodata* sections (constants, strings, etc.) */ 19 | . = ALIGN(4); 20 | _etext = .; /* define a global symbol at end of code */ 21 | _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */ 22 | } >RAM 23 | 24 | 25 | /* This is the initialized data section 26 | The program executes knowing that the data is in the RAM 27 | but the loader puts the initial values in the FLASH (inidata). 28 | It is one task of the startup to copy the initial values from FLASH to RAM. */ 29 | .data : AT ( _sidata ) 30 | { 31 | . = ALIGN(4); 32 | _sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */ 33 | _ram_start = .; /* create a global symbol at ram start for garbage collector */ 34 | . = ALIGN(4); 35 | *(.data) /* .data sections */ 36 | *(.data*) /* .data* sections */ 37 | *(.sdata) /* .sdata sections */ 38 | *(.sdata*) /* .sdata* sections */ 39 | . = ALIGN(4); 40 | _edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */ 41 | } >RAM 42 | 43 | /* Uninitialized data section */ 44 | .bss : 45 | { 46 | . = ALIGN(4); 47 | _sbss = .; /* define a global symbol at bss start; used by startup code */ 48 | *(.bss) 49 | *(.bss*) 50 | *(.sbss) 51 | *(.sbss*) 52 | *(COMMON) 53 | 54 | . = ALIGN(4); 55 | _ebss = .; /* define a global symbol at bss end; used by startup code */ 56 | } >RAM 57 | 58 | /* this is to define the start of the heap, and make sure we have a minimum size */ 59 | .heap : 60 | { 61 | . = ALIGN(4); 62 | _heap_start = .; /* define a global symbol at heap start */ 63 | } >RAM 64 | } 65 | -------------------------------------------------------------------------------- /testbench.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.107 (w)1999-2020 BSI 3 | [*] Tue Oct 20 19:25:31 2020 4 | [*] 5 | [dumpfile] "/home/claire/Work/riscv-formal/cores/nerv/testbench.vcd" 6 | [dumpfile_mtime] "Tue Oct 20 19:24:49 2020" 7 | [dumpfile_size] 76428 8 | [savefile] "/home/claire/Work/riscv-formal/cores/nerv/testbench.gtkw" 9 | [timestart] 305 10 | [size] 1397 995 11 | [pos] -1 -1 12 | *-6.000000 497 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] testbench. 14 | [sst_width] 240 15 | [signals_width] 174 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 289 18 | @28 19 | testbench.dut.clock 20 | testbench.dut.reset 21 | testbench.dut.stall 22 | testbench.dut.trap 23 | @200 24 | - 25 | @22 26 | testbench.dut.imem_addr[31:0] 27 | testbench.dut.imem_data[31:0] 28 | @200 29 | - 30 | @28 31 | testbench.dut.dmem_valid 32 | @22 33 | testbench.dut.dmem_addr[31:0] 34 | testbench.dut.dmem_wstrb[3:0] 35 | testbench.dut.dmem_wdata[31:0] 36 | testbench.dut.dmem_rdata[31:0] 37 | @200 38 | - 39 | @22 40 | testbench.dut.pc[31:0] 41 | testbench.dut.insn[31:0] 42 | @28 43 | testbench.dut.illinsn 44 | @c00200 45 | -insn_decoded 46 | @22 47 | testbench.dut.insn_funct7[6:0] 48 | testbench.dut.insn_rs2[4:0] 49 | testbench.dut.insn_rs1[4:0] 50 | @28 51 | testbench.dut.insn_funct3[2:0] 52 | @22 53 | testbench.dut.insn_rd[4:0] 54 | testbench.dut.insn_opcode[6:0] 55 | @200 56 | - 57 | @22 58 | testbench.dut.imm_b_sext[31:0] 59 | testbench.dut.imm_i_sext[31:0] 60 | testbench.dut.imm_j_sext[31:0] 61 | testbench.dut.imm_s_sext[31:0] 62 | @1401200 63 | -insn_decoded 64 | @22 65 | testbench.dut.rs1_value[31:0] 66 | testbench.dut.rs2_value[31:0] 67 | @28 68 | testbench.dut.next_wr 69 | @22 70 | testbench.dut.next_rd[31:0] 71 | @c00201 72 | -registers 73 | @22 74 | testbench.dut.dbg_reg_x0[31:0] 75 | testbench.dut.dbg_reg_x1[31:0] 76 | testbench.dut.dbg_reg_x2[31:0] 77 | testbench.dut.dbg_reg_x3[31:0] 78 | testbench.dut.dbg_reg_x4[31:0] 79 | testbench.dut.dbg_reg_x5[31:0] 80 | testbench.dut.dbg_reg_x6[31:0] 81 | testbench.dut.dbg_reg_x7[31:0] 82 | testbench.dut.dbg_reg_x8[31:0] 83 | testbench.dut.dbg_reg_x9[31:0] 84 | testbench.dut.dbg_reg_x10[31:0] 85 | testbench.dut.dbg_reg_x11[31:0] 86 | testbench.dut.dbg_reg_x12[31:0] 87 | testbench.dut.dbg_reg_x13[31:0] 88 | testbench.dut.dbg_reg_x14[31:0] 89 | testbench.dut.dbg_reg_x15[31:0] 90 | testbench.dut.dbg_reg_x16[31:0] 91 | testbench.dut.dbg_reg_x17[31:0] 92 | testbench.dut.dbg_reg_x18[31:0] 93 | testbench.dut.dbg_reg_x19[31:0] 94 | testbench.dut.dbg_reg_x20[31:0] 95 | testbench.dut.dbg_reg_x21[31:0] 96 | testbench.dut.dbg_reg_x22[31:0] 97 | testbench.dut.dbg_reg_x23[31:0] 98 | testbench.dut.dbg_reg_x24[31:0] 99 | testbench.dut.dbg_reg_x25[31:0] 100 | testbench.dut.dbg_reg_x26[31:0] 101 | testbench.dut.dbg_reg_x27[31:0] 102 | testbench.dut.dbg_reg_x28[31:0] 103 | testbench.dut.dbg_reg_x29[31:0] 104 | testbench.dut.dbg_reg_x30[31:0] 105 | testbench.dut.dbg_reg_x31[31:0] 106 | @1401201 107 | -registers 108 | @200 109 | - 110 | @28 111 | testbench.dut.mem_rd_enable 112 | @22 113 | testbench.dut.mem_rd_addr[31:0] 114 | testbench.dut.mem_rd_func[4:0] 115 | testbench.dut.mem_rd_reg[4:0] 116 | @200 117 | - 118 | @28 119 | testbench.dut.mem_rd_enable_q 120 | @22 121 | testbench.dut.mem_rd_func_q[4:0] 122 | testbench.dut.mem_rd_reg_q[4:0] 123 | testbench.dut.mem_rdata[31:0] 124 | @200 125 | - 126 | @28 127 | testbench.dut.mem_wr_enable 128 | @22 129 | testbench.dut.mem_wr_addr[31:0] 130 | testbench.dut.mem_wr_data[31:0] 131 | testbench.dut.mem_wr_strb[3:0] 132 | [pattern_trace] 1 133 | [pattern_trace] 0 134 | -------------------------------------------------------------------------------- /testbench.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 N. Engelhardt 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module testbench; 21 | 22 | localparam MEM_ADDR_WIDTH = 16; 23 | localparam TIMEOUT = (1<<10); 24 | 25 | reg clock; 26 | reg reset = 1'b1; 27 | reg stall = 1'b0; 28 | wire trap; 29 | 30 | wire [31:0] imem_addr; 31 | reg [31:0] imem_data; 32 | 33 | wire dmem_valid; 34 | wire [31:0] dmem_addr; 35 | wire [ 3:0] dmem_wstrb; 36 | wire [31:0] dmem_wdata; 37 | reg [31:0] dmem_rdata; 38 | 39 | always #5 clock = clock === 1'b0; 40 | always @(posedge clock) reset <= 0; 41 | 42 | reg [7:0] mem [0:(1<= (1<= TIMEOUT)) begin 139 | $display("Simulated %0d cycles", cycles); 140 | $finish; 141 | end 142 | end 143 | 144 | 145 | 146 | endmodule 147 | -------------------------------------------------------------------------------- /trace.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.107 (w)1999-2020 BSI 3 | [*] Wed Oct 21 17:13:34 2020 4 | [*] 5 | [dumpfile] "(null)" 6 | [savefile] "/home/claire/Work/riscv-formal/cores/nerv/trace.gtkw" 7 | [timestart] 0 8 | [size] 1259 841 9 | [pos] 2135 225 10 | *-5.139064 105 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [treeopen] rvfi_testbench. 12 | [treeopen] rvfi_testbench.checker_inst. 13 | [treeopen] rvfi_testbench.wrapper. 14 | [sst_width] 240 15 | [signals_width] 287 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 235 18 | @24 19 | smt_step 20 | @200 21 | - 22 | -Core 23 | @28 24 | rvfi_testbench.wrapper.uut.clock 25 | rvfi_testbench.wrapper.uut.reset 26 | rvfi_testbench.wrapper.uut.stall 27 | rvfi_testbench.wrapper.uut.trap 28 | @200 29 | - 30 | @23 31 | rvfi_testbench.wrapper.uut.pc[31:0] 32 | @22 33 | rvfi_testbench.wrapper.uut.insn[31:0] 34 | @c00200 35 | -insn_decoded 36 | @22 37 | rvfi_testbench.wrapper.uut.insn_funct7[6:0] 38 | rvfi_testbench.wrapper.uut.insn_rs2[4:0] 39 | rvfi_testbench.wrapper.uut.insn_rs1[4:0] 40 | @28 41 | rvfi_testbench.wrapper.uut.insn_funct3[2:0] 42 | @22 43 | rvfi_testbench.wrapper.uut.insn_rd[4:0] 44 | rvfi_testbench.wrapper.uut.insn_opcode[6:0] 45 | @200 46 | - 47 | @22 48 | rvfi_testbench.wrapper.uut.imm_b_sext[31:0] 49 | rvfi_testbench.wrapper.uut.imm_i_sext[31:0] 50 | rvfi_testbench.wrapper.uut.imm_j_sext[31:0] 51 | rvfi_testbench.wrapper.uut.imm_s_sext[31:0] 52 | @1401200 53 | -insn_decoded 54 | @200 55 | - 56 | -Checker 57 | @24 58 | rvfi_testbench.checker_inst.rvfi_order[63:0] 59 | @28 60 | rvfi_testbench.checker_inst.rvfi_valid 61 | @29 62 | rvfi_testbench.checker_inst.spec_valid 63 | @28 64 | rvfi_testbench.checker_inst.rvfi_trap 65 | @22 66 | rvfi_testbench.checker_inst.rvfi_insn[31:0] 67 | rvfi_testbench.wrapper.uut.rvfi_pc_rdata[31:0] 68 | @c00200 69 | -spec 70 | @28 71 | rvfi_testbench.checker_inst.spec_valid 72 | rvfi_testbench.checker_inst.spec_trap 73 | @200 74 | - 75 | @22 76 | rvfi_testbench.checker_inst.spec_rs1_addr[4:0] 77 | rvfi_testbench.checker_inst.spec_rs2_addr[4:0] 78 | rvfi_testbench.checker_inst.spec_rd_addr[4:0] 79 | rvfi_testbench.checker_inst.spec_rd_wdata[31:0] 80 | rvfi_testbench.checker_inst.spec_pc_wdata[31:0] 81 | @200 82 | - 83 | @22 84 | rvfi_testbench.checker_inst.spec_mem_addr[31:0] 85 | rvfi_testbench.checker_inst.spec_mem_wdata[31:0] 86 | rvfi_testbench.checker_inst.spec_mem_rmask[3:0] 87 | rvfi_testbench.checker_inst.spec_mem_wmask[3:0] 88 | @1401200 89 | -spec 90 | @c00200 91 | -rvfi 92 | @24 93 | rvfi_testbench.checker_inst.rvfi_order[63:0] 94 | @28 95 | rvfi_testbench.checker_inst.rvfi_valid 96 | rvfi_testbench.checker_inst.rvfi_trap 97 | rvfi_testbench.checker_inst.rvfi_halt 98 | rvfi_testbench.checker_inst.rvfi_intr 99 | rvfi_testbench.checker_inst.rvfi_ixl[1:0] 100 | rvfi_testbench.checker_inst.rvfi_mode[1:0] 101 | @22 102 | rvfi_testbench.checker_inst.rvfi_insn[31:0] 103 | @200 104 | - 105 | @22 106 | rvfi_testbench.checker_inst.rvfi_pc_rdata[31:0] 107 | rvfi_testbench.checker_inst.rvfi_pc_wdata[31:0] 108 | @200 109 | - 110 | @22 111 | rvfi_testbench.checker_inst.rvfi_rs1_addr[4:0] 112 | rvfi_testbench.checker_inst.rvfi_rs2_addr[4:0] 113 | rvfi_testbench.checker_inst.rvfi_rd_addr[4:0] 114 | @200 115 | - 116 | @22 117 | rvfi_testbench.checker_inst.rvfi_rs1_rdata[31:0] 118 | rvfi_testbench.checker_inst.rvfi_rs2_rdata[31:0] 119 | rvfi_testbench.checker_inst.rvfi_rd_wdata[31:0] 120 | @200 121 | - 122 | @22 123 | rvfi_testbench.checker_inst.rvfi_mem_addr[31:0] 124 | rvfi_testbench.checker_inst.rvfi_mem_rdata[31:0] 125 | rvfi_testbench.checker_inst.rvfi_mem_rmask[3:0] 126 | rvfi_testbench.checker_inst.rvfi_mem_wdata[31:0] 127 | rvfi_testbench.checker_inst.rvfi_mem_wmask[3:0] 128 | @1401200 129 | -rvfi 130 | [pattern_trace] 1 131 | [pattern_trace] 0 132 | -------------------------------------------------------------------------------- /wrapper.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * NERV -- Naive Educational RISC-V Processor 3 | * 4 | * Copyright (C) 2020 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module rvfi_wrapper ( 21 | input clock, 22 | input reset, 23 | `RVFI_OUTPUTS 24 | ); 25 | (* keep *) `rvformal_rand_reg stall; 26 | (* keep *) `rvformal_rand_reg [31:0] imem_data; 27 | (* keep *) `rvformal_rand_reg [31:0] dmem_rdata; 28 | 29 | (* keep *) wire [31:0] imem_addr; 30 | 31 | (* keep *) wire dmem_valid; 32 | (* keep *) wire [31:0] dmem_addr; 33 | (* keep *) wire [ 3:0] dmem_wstrb; 34 | (* keep *) wire [31:0] dmem_wdata; 35 | 36 | nerv uut ( 37 | .clock (clock ), 38 | .reset (reset ), 39 | .stall (stall ), 40 | 41 | .imem_addr (imem_addr ), 42 | .imem_data (imem_data ), 43 | 44 | .dmem_valid (dmem_valid), 45 | .dmem_addr (dmem_addr ), 46 | .dmem_wstrb (dmem_wstrb), 47 | .dmem_wdata (dmem_wdata), 48 | .dmem_rdata (dmem_rdata), 49 | 50 | `RVFI_CONN 51 | ); 52 | 53 | `ifdef NERV_FAIRNESS 54 | reg [2:0] stalled = 0; 55 | always @(posedge clock) begin 56 | stalled <= {stalled, stall}; 57 | assume (~stalled); 58 | end 59 | `endif 60 | endmodule 61 | --------------------------------------------------------------------------------