Project 1 - A RISC-V Core
In this project, you will design a simple multicycle RV32I processor in synthesizable SystemVerilog, verify it, and run it on a real Tang Nano 9K FPGA. This core is the foundation for every later project in the course: the peripherals, the ISA extensions, and ultimately the accelerator will all be attached to it.
Objectives
- Implement a multicycle RV32I processor in synthesizable SystemVerilog.
- Build a Verilator-based testbench to verify instruction-level correctness.
- Synthesize the design for the Tang Nano 9K using the OSS CAD Suite (Yosys + nextpnr-himbaechel) and run it on real hardware.
- Execute simple C programs (compiled to RV32I) on your core.
Specification
Your processor must implement the RV32I base integer instruction set (the M extension is not required here - it is added as an ISA-extension exercise in Project 2).
The implementation must be multicycle: each instruction may take a different number of clock cycles to execute. You may take inspiration from the multicycle datapath in Patterson & Hennessy's Computer Organization and Design, adapted to RISC-V (see Harris & Harris, Digital Design and Computer Architecture, RISC-V Edition).
Your repository's sw/ already has a working C-to-RV32I toolchain (cross-compiler invocation, linker script, startup code, ELF-to-$readmemh-hex conversion) - see "What's already in your repository" below. You are not required to use it - riscv-gnu-toolchain or the online assembler work too - but it saves you from reinventing this plumbing, and it fixes the one piece of memory architecture this project standardizes (see below).
Use the ebreak instruction as your program-termination convention. Your core must expose this as a halted output that goes high once ebreak executes and stays high - see the interface contract below.
Your code must be synthesizable: it must be possible to generate a real circuit from it. Functional verification should use Verilator testbenches; synthesis and place-and-route should use Yosys and nextpnr-himbaechel (Gowin backend) from the OSS CAD Suite, with bitstream upload via openFPGALoader. See Lab 2 for toolchain setup.
You are encouraged - but not required - to demonstrate program execution observably on the board (e.g., via LEDs, a 7-segment display, or UART output if you get ahead on Project 2).
What's already in your repository
Unlike the labs, there is very little scaffolding here on purpose - designing the processor's architecture is the assignment. Three things are provided, and they exist to remove toolchain friction from that work, not to shape the design itself:
-
hw/rtl/core/riscv_core_top.sv- the board-level top-level, with an interface and aTODO. This is the one interface convention the project imposes:- the module is named
riscv_core_top, with exactly the ports/parameters already declared; - your core must drive a
haltedoutput high once it executesebreak, and keep it there; - your core's IMEM/DMEM must load from
IMEM_INIT_FILE/DMEM_INIT_FILEvia$readmemh, sized in 32-bit words perIMEM_BYTES/DMEM_BYTES- matching whatsw/'s toolchain produces.
Everything below that outer shell - your core's own module name(s), how many files it spans, its internal datapath and control - is entirely yours.
haltedis compiled out of real hardware builds (the shared board.csthas no pin for it - see the file's own header comment); driveledfrom it if you want it observable on the board. - the module is named
-
sw/- the C-to-hex toolchain (common/link.ld,common/crt0.S,common/bin2hex.py, aMakefile) plustests/project1_demo.c, a first smoke-test program (loops, branches, loads/stores, a function call) worth getting running before you have covered the whole ISA. See your repository'ssw/README.mdfor the exact memory map it fixes (IMEM at0x0, DMEM at0x1_0000, 16 KB each) and how to add your own test programs. -
hw/sim/core/tb_riscv_core_top.cpp- a testbench base, not a worked example: it resets your core, loads a compiled program, runs untilhalted(or a generous cycle budget expires, so a hung core fails loudly instead of hanging the build), and stops there with aTODO. Checking the actual result needs to look inside your core somehow - a debug port,--publicon a module you want to peek into, a register dump, whatever fits your architecture - which is exactly the kind of design decision this project is about, so the base does not make it for you.
The .cst pin files need no changes for this project - riscv_core_top's ports (sys_clk, sys_rst_n, led[5:0]) are already in the shared board vocabulary from Lab 2 on (see hw/README.md).
Deliverables
- SystemVerilog source for the processor.
- Verilator testbench(es) covering the implemented instructions.
- Build scripts for synthesis/place-and-route/bitstream generation targeting the Tang Nano 9K.
- At least one C program, compiled and executed on real hardware, with evidence of correct execution (e.g., register dump, simulation trace, or on-board observation).
- Documentation of your processor's architecture (datapath diagram, FSM, supported instructions).
Submission
Work in pairs (see Home), in the private repository already created for your pair - there is no separate submission step. Commit and push your work there; grading reads it directly from main. Due: see Calendar.
Evaluation criteria
- Coverage of RV32I instructions.
- Correctness and clarity of the multicycle datapath and control FSM.
- Quality and coverage of the verification testbenches.
- Successful synthesis and execution on the Tang Nano 9K.
- Use of git for tracking and submitting your work.
- Documentation of the implemented processor.
- Extra tests or features beyond the minimum specification.