277 lines
8.9 KiB
Markdown
277 lines
8.9 KiB
Markdown
# [RISC-V Desgin in an Open_Source Design Flow](https://microtec-academy.de/produkt/risc-v-design-in-an-open-source-design-flow/)
|
|
|
|
A RISC-V design course, where you learn about the the RISC-V theory and then use it to build your own RISC-V processor.
|
|
|
|
This project has the full solution for the course exercises. It is able to simulate the Decoder or CPU as DUTs (device under tests). The simulation executes a SW test from a designated Hex file on the DUT.
|
|
|
|
In this README you will learn about ...
|
|
|
|
* what **prerequisites** you need to get this project running
|
|
* how the project is **organised**
|
|
* how to **run simulations**
|
|
|
|
## Background
|
|
|
|
This course is a part of the initiative [*Bavarian Chip Design Center (BCDC)*](https://www.iis.fraunhofer.de/en/ff/sse/bavarian-chip-design-center.html), which aims to develop and improve the IC-Design workforce in Bavaria.
|
|
|
|
This course is an adaptation of the code-base developed at [Lund University](https://www.lth.se/) by Per Andersson as part of the effort to develop and improve education in Digital System Design. You can find the original source-code under [this repository](https://github.com/PalePrime/single_cycle).
|
|
|
|
## Prerequisites
|
|
|
|
Bash Shell Terminal
|
|
|
|
* Windows: you need to install gitbash or use something similar
|
|
* MacOS/Linux: bash is preinstalled
|
|
|
|
GCC Compiler
|
|
|
|
* Installation details [here](https://gcc.gnu.org/install/)
|
|
|
|
Verilator
|
|
|
|
* If not installed, you can find the installation [here](https://verilator.org/guide/latest/install.html). It is highly recommended to install through a package manager for all operating systems.
|
|
* For Linux use apt package manager. Info under [verilator install guide](https://verilator.org/guide/latest/install.html#package-manager-quick-install).
|
|
* For MacOS the package manager is [homebrew](https://brew.sh/).
|
|
* For Windows an package manager option is [pacman](https://gist.github.com/AndreSteenveld/cb6662c93c8323795c5fd347defb8976) (untested).
|
|
* Export the *VERILATOR* environment variable. Make sure to use your Verilator install directory -> `export VERILATOR=</path/to/verilator>/bin/verilator`
|
|
|
|
Surfer Waveform Viewer
|
|
|
|
* If not installed, you can find the installation [here](https://surfer-project.org/)
|
|
* Export the *WAVE_VIEWER* environment variables. Make sure to use your Surfer install directory -> `export WAVE_VIEWER=</path/to/surfer>/surfer`
|
|
|
|
IDE (optional)
|
|
|
|
* Any IDE of your choosing will make it easy to view and manage the files
|
|
|
|
## Project Organisation
|
|
|
|
### Resources
|
|
|
|
Path: `doc`
|
|
|
|
* Module diagrams
|
|
* RISC-V Cards
|
|
* RISC-V ISM
|
|
* RISC-V ASM
|
|
|
|
### RTL source code
|
|
|
|
Path: `hw/rtl`
|
|
|
|
### File lists of SV code
|
|
|
|
Path: `hw/file_lists`
|
|
|
|
* RTL file list
|
|
* Testbench file list
|
|
|
|
### Verification source code
|
|
|
|
#### SV testbenches used in EDA playground
|
|
|
|
Path: `hw/dv/rtl`
|
|
|
|
#### Verilator environment
|
|
|
|
Path: `hw/dv/verilator/`
|
|
|
|
* SV Toplevel harnesses
|
|
* Decoder
|
|
* CPU
|
|
* C++ testbenches
|
|
* Decoder
|
|
* CPU
|
|
* Makefile
|
|
|
|
### Software and Hex programs used for testing
|
|
|
|
Path: `sw/risc-v`
|
|
|
|
* Main Memory: Hex code
|
|
* Decoder:
|
|
* Assembly code
|
|
* Hex code from assembeled assembly code
|
|
* Fibonacci Series/Hello World/Prime Factors:
|
|
* C Code
|
|
* Assembly code from compiled C code
|
|
* Simplified assembly code from assembly code (not available for Fibonacci Series)
|
|
* Hex code from assembeled assembly or simplified assembly code
|
|
|
|
## Running Simulations
|
|
|
|
### Quick start
|
|
|
|
Run the two commands below
|
|
|
|
```
|
|
cd hw/dv/verilator
|
|
```
|
|
|
|
```
|
|
make clean all run wave
|
|
```
|
|
|
|
This will convert the RTL into C++, compile the model, create the simulation binary, run the simulation, and start the waveform viewer. The output of the simulation should be the following:
|
|
|
|
```
|
|
*** Running simulation...
|
|
|
|
Creating model...
|
|
Registered DPI-C functions:
|
|
scopesDump:
|
|
SCOPE 0x55616d28b940: TOP.cpu_harness
|
|
DPI-EXPORT 0x556136cc8f77: enable
|
|
DPI-EXPORT 0x556136cc8f89: getLed
|
|
DPI-EXPORT 0x556136cc8fda: getMem
|
|
DPI-EXPORT 0x556136cc9006: getReg
|
|
DPI-EXPORT 0x556136cc9242: loadRAM
|
|
DPI-EXPORT 0x556136cdcc19: printMem
|
|
DPI-EXPORT 0x556136cdcd88: printReg
|
|
DPI-EXPORT 0x556136cc8fab: setBtn
|
|
DPI-EXPORT 0x556136cc8f68: setClk
|
|
DPI-EXPORT 0x556136cc8f78: setInitial
|
|
DPI-EXPORT 0x556136cc8fea: setMem
|
|
DPI-EXPORT 0x556136cc8fc9: setReset
|
|
|
|
Initializing SRAM memory from ../../../sw/risc-v/hello_world/helloWorld.hex
|
|
program set to helloWorld
|
|
|
|
Starting model...
|
|
|
|
Resetting...
|
|
Starting CPU...
|
|
Running for 500 clock cycles...
|
|
|
|
Printing evaluation for helloWorld program!
|
|
|
|
T=3960: Hex ASCII
|
|
Value at RAM[1024]: 0x68000000 : h
|
|
Value at RAM[1025]: 0x00000000 :
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=6840: Hex ASCII
|
|
Value at RAM[1024]: 0x68650000 : he
|
|
Value at RAM[1025]: 0x00000000 :
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=9720: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c00 : hel
|
|
Value at RAM[1025]: 0x00000000 :
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=12600: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x00000000 :
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=15480: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f000000 : o
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=18360: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f200000 : o
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=21240: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f207700 : o w
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=24120: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f20776f : o wo
|
|
Value at RAM[1026]: 0x00000000 :
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=27000: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f20776f : o wo
|
|
Value at RAM[1026]: 0x72000000 : r
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=29880: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f20776f : o wo
|
|
Value at RAM[1026]: 0x726c0000 : rl
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=32760: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f20776f : o wo
|
|
Value at RAM[1026]: 0x726c6400 : rld
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
T=35640: Hex ASCII
|
|
Value at RAM[1024]: 0x68656c6c : hell
|
|
Value at RAM[1025]: 0x6f20776f : o wo
|
|
Value at RAM[1026]: 0x726c6421 : rld!
|
|
Value at RAM[1027]: 0x00000000 :
|
|
|
|
|
|
Done, closing simulation.
|
|
```
|
|
|
|
**Important:** The makefile reads the file lists `hw/file_lists/rtl_flist.f` and `hw/file_lists/tb_flist.f`. The make process does not recognize RTL or TB file changes, so it is required to run `make clean` after RTL or TB changes, otherwise the changed files will not be compiled.
|
|
|
|
### Makefile details
|
|
|
|
By default, the hex-file `sw/risc-v/hello_world.hex` is loaded into the Main Memory before starting the simulation, and the simulation is run for 500 clock cycles. This behavior can by overriden by specifying *PROG* and *NCYCLES* environment variables, which will load the specified hex file and run for the specified number of clock cycles.
|
|
|
|
```
|
|
make run PROG=/path/to/myprog.hex NCYCLES=2000
|
|
```
|
|
|
|
You can also combine the different make targets.
|
|
|
|
```
|
|
make clean all run wave PROG=/path/to/myprog.hex NCYCLES=2000
|
|
```
|
|
|
|
**Important:** If the simulation is not showing the full expected result, make sure that the number of cycles are sufficient for the CPU to finish executing the program (check if the last instruction executed is the *jump to halt* instruction)
|
|
|
|
Available Make targets (commands)
|
|
|
|
* **make clean** - remove old files
|
|
* **make** - build and compile the RTL simulator using Verilator and GCC (alias for `make all`)
|
|
* **make run** - run the simulation (requires built and compiled RTL)
|
|
* **make wave** - show the waveform in Surfer
|
|
* **make clean all run wave** - runs all the make targets (order is important)
|
|
|
|
It is not necessary to close the Surfer viewer if the simulation is run again. Just reload the Surfer window after the new run.
|
|
|
|
### Things you need/can change
|
|
|
|
* In the *Makefile*
|
|
* **PROG** - variable holding the hex file path of the program to be loaded
|
|
* **NCYCLES** - Variable for the number of cycles the CPU is going to run for
|
|
* **TOPMODULE** - Variable with the module name of the harness
|
|
* Int the *tb_flist.f*
|
|
* Add new harnesses you have created
|
|
|
|
### Things you can do
|
|
|
|
* You can run the exact same tests you ran on EDA Playground and you should get the same results. However, the test here will be using verilator.
|
|
* You can create your own harness and C++ testbenches for modules other than Decoder and CPU to get familiar with verilator testbenches
|
|
* Compare Icarus and Verilator output (uninitialised memory locations are set to 'x' when using Icarus and '0' when using verilator)
|