Introduction
The following components are used for smooth RISC-V development on a FPGA:
This tutorial use the Quartus II software version 15.0.2 and provides comprehensive information
that will help you understand how to create a RISC-V on your FPGA development board and run
software on it. The system here is based on the NEORV32
processor.
I do not want to write every time "Quartus II" or "Terasic DE0-Nano Development
and Education Board" in this tutorial. Therefore I will use the short form "Quartus"
and "DE0-Nano".
Hardware
For this tutorial a DE0-Nano board was used:
The DE0-Nano provides a lot of functionality. But for this tutorial only the following subset was used:
- Cyclone IV (EP4CE22F17C6)
- Build in USB Blaster
- 32 MByte SDRAM
- 2 Push-button switches
- 8 Green User LEDs
- 50 MHz oscillator
The following options of the NEORV32 was configured:
INT_BOOTLOADER_EN |
true |
ON_CHIP_DEBUGGER_EN |
true |
MEM_INT_IMEM_SIZE |
32KB |
MEM_INT_DMEM_SIZE |
16KB |
ICACHE_EN |
true |
MEM_EXT_EN |
true |
SDRAM |
0x90000000 - 0x91FFFFFF |
At the end of this session, you will find the final projects for the DE0-Nano board.
Btw, here was used the NEORV32 release v1.6.4.4 and the J-Link EDU (HW: v11 SW: v7.58b).
Design Flow
The first step in the FPGA design flow starts with the design entry. The standard design
entry methods are using schematics or a hardware description language (HDL), such as
Verilog or VHDL. The design entry step is where the designer creates the digital circuit
to be implemented inside the FPGA. The flow then proceeds through compilation, simulation,
programming, and verification in the FPGA hardware.
This tutorial describes all of the steps except the simulation. The part of the Design is
a huge part. Therefore it is divided in smaller chunks. I assume that the Quartus software
and the USB-Blaster driver is already installed on your PC. If not, please take this step
before.
At the end of this tutorial you will have created a FPGA design which contains a NEORV32
processor. In the next session, (2) SEGGER Embedded Studio we will create an
application which runs on the NEORV32 cpu. Let's start with the Topfdeckel,
sorry, Top-Level Entity...
Quartus II Project
First of all we must create a new Quartus project. A project is a set of files that maintain
information about your FPGA design. The Quartus Settings File (.qsf) and Quartus Project File
(.qpf) files are the primary files in a Quartus project.
Start the Quartus software and select "File > New Project Wizard". The window
will look like:
(Click inside the picture to expand)
Click "Next"and enter the following information about your project: (Note: File
names, project names, and directories in the Quartus software cannot contain spaces.
In general, do not use spaces in file names or directories.).
What is the working directory for this project? Enter a directory in which you will store your Quartus project
files for this design. Here I will use "C:\my_design\de0n-neorv32-sdram-qsys\hw" What is the name
of this project? Please use "de0n-neorv32-sdram-qsys"
What is the name of the top-level design entity for this project? Please use "de0n-neorv32-sdram-qsys"
here too. The next window should look like:
(Click inside the picture to expand)
Click "Next". Now you will come to page "Project Type", use "Empty project" and
press "Next". The same for "Add Files", press "Next" too. In the next
window you must assign a FPGA device to your design. Change the "Device family" to
"Cyclone IV E" and use "EP4CE22F17C6" for the device. The dialog should look like:
(Click inside the picture to expand)
Click "Next" twice, the summary should look like:
(Click inside the picture to expand)
Click "Finish", now you have created the "de0n-neorv32-sdram-qsys" project. The "Project
Navigator" should look like:
Next we will create the Top-Level Entity.
Top-Level Entity
Btw, what is a "Top-Level Entity"? It is the outer rim of your design which
represent the interconnections to the outer world of the FPGA. Quartus supports the
following options for a Top-Level Entity:
- Block Diagram/Schematic File
- VHDL File
- Verilog File
Here in this tutorial I will use a VHDL File for the Top-Level Entity. Compared to a Block Diagram a
HDL File is not so clearly represented, but more fexible for me. Now we will start to create the Top-Level
Entity and some other files.
Now we will cheat a little bit, here I have prepared the files for you. Please copy the
zip file hw-cheat.zip
to your project folder "C:\my_design\de0n-neorv32-sdram-qsys\hw" and unzip it here.
This will add the following folders and files to your project folder:
Next we will add the Top-Level Entity to the project. To do this, switch to "Files" in the
"Project Navigator", select "Files" and right-click in the window. You then get
the option to add "Files" to the project:
Select "Add/Remove Files in Project...":
(Click inside the picture to expand)
Add files by using "...":
The "Select File" dialog opens. Select the file "top.vhd" in the
"C:\my_design\de0n-neorv32-sdram-qsys\hw\src" folder:
After selecting "top.vhd" press "Open". The "Files" dialog looks like:
Press "Add" and the window looks like:
Next press "OK" to finish the process. The file was now added to the project and
the "Project Navigator" now looks like:
Now only the "top.vhd" file has to be selected as the top-level entity. To do this,
right click on the file and select "set as Top-Level Entity:
In the next step we will create the "engine" of the design. A PLL driven by
the external clock.
System PLL
The PLL will be created with a Wizard, therefore use "Tools > IP Catalog",
the window will look like:
Type "ALTPLL" (1) select "ALTPLL" (2) and press "Add…""
In the next window use "C:/my_design/de0n-neorv32-sdram-qsys/hw/src/pll/pll_sys.vhd"
for the "file name" (1), "VHDL" for the "file type" (2) and press "OK" (3):
Prepared for a long story. The MegaWizard Plug-In Manager (what a long name) appears.
You will see now page 1 of 12 ( not "Seven of Nine" ). For device speed grade choose 6 and set
the frequency of the inclock0 input to 50 MHz. The window should look like:
(Click inside the picture to expand)
Click "Next". Now you are on page 2 of 12, unselect all options first, and select "Create 'locked'
output" and "Enable self-reset on loss lock". The locked output will be used to hold the NEORV32 in
reset while the PLL is not locked. The window should look like:
(Click inside the picture to expand)
Click "Next" four times. Now you are on page 6 of 12, and will setup the output clock for c0. Select
"Enter output clock frequency" and set frequency to 100 Mhz. The window should look like:
(Click inside the picture to expand)
Again, click "Next". Now you are on page 7 of 12. We need c1 for the SDRAM, therefore enable the option
"Use this clock" and select "Enter output clock frequency". The same like before. Set the
frequency to 100 MHz. And set the "Clock phase shift" to -54 deg.
Why -54 deg? Please take a look in the "Using the SDRAM on Altera's DE0-Nano Board with VHDL Designs"
which can be find here. This PDF will explain why you need a phase shift in chapter 7. But in the document 3ns is
used for a clock of 50MHz. 3ns at 50MHz is equivalent to 54 deg. Help, if anyone comes to an other result,
please send me a note. Btw, here we are using 100MHz instead of 50MHz. Therefore I decide to change from ns to deg.
The window look like:
(Click inside the picture to expand)
And now, press "Finish" twice. The MegaWizard Plug-In Manager will be
closed. And the following dialog is shown:
Press "Yes" to add the Quartus IP to your design. A pll_sys IP block
was created and added to your project. The "Files" folder from the
"Project Navigator" should look like:
Timing constraints, what is this? We will create this file in the next section.
Design Constraints File
Select "File > New... > Synopsys Design Constraints File", stop, stop, stop.
We will cheat something here again. The "Synopsys Design Constraints File" exist already
and you can add the file to the project. As with the "top.vhd" file, this is done using
the "Add / Remove Files in Project" function. The file
"C:\my_design\de0n-neorv32-sdram-qsys\hw\de0n-neorv32-sdram-qsys.sdc" is now added here.
The "Files" folder from the "Project Navigator" should look like:
Why we need a SDC File? To give the TimeQuest Timing Analyzer the possibility to
check if the timing of the design will fit in the FPGA, some "parameters"
for the calculation are needed. This "parameters" are stored in the SDC
file. For example you will find the following line in the file:
create_clock -period 50MHz [get_ports CLOCK_50]
This line tells the Analyzer that there exist a port with the name "CLOCK_50".
It will be used as a clock signal with 50 MHz.
Even there will not only timing parameters saved in this file. For more
information please take a look in the documentation. Help, if someone can
explain it better, please send me a note.
In the next section the "Qsys SDRAM" will be designed.
Qsys and SDRAM
To use the SDRAM, it is easier to accommodate it in a Qsys system. Because a SDRAM controller is
available here. Further devices can also be integrated into the Qsys system.
Start Qsys by using "Tools > Qsys", the new windows will look like:
(Click inside the picture to expand)
Select the "clk_0" component and right-click, then select "Rename":
Change the name from "clk_0" to "clk_sys" and press return.
Double click the "clk_sys" name and change the "Clock frequency" (1) from 50MHz to 100MHz,
and "Reset synchronous edges" to "Deassert" (2):
Click "X" (3) to close the dialog.
Now we will add a Wishbone to Avalone Bridge. In the left hand-side IP Catalog, select
"Wishbone to Avalon Bridge (32 bit)", it should look like:
Press the "Add…" button to open the Wishbone to Avalon Bridg wizard. The
wizard will look like:
(Click inside the picture to expand)
Click "Finish" to close the wizard, it now should look like:
(Click inside the picture to expand)
Select the "wb_avm_bridge_0" component and right-click, then select "Rename":
Rename the "wb_avm_bridge_0" to "wb_avm_bridge", it should now look like:
(Click inside the picture to expand)
Don't worry about the Error messages. The errors will be resolved during the tutorial.
The next component is the SDRAM, select "Library > Memory Interfaces and Controllers > SDRAM >
SDRAM Controller" and clicking the "Add…" button.
The SDRAM wizard will be opened. Change the "Data width Bits" to "16",
"Row" to "13" and "Column" to "9". The window of the
wizard should look like:
(Click inside the picture to expand)
Press "Timing" tab, here change:
- "Initialization refresh cycles" to 8
- "Issue one refresh command every" to 7.8125
- "Delay after powerup, before initialization" to 200
The window should look like:
Click "Finish" to return to the main window. Important, rename the "new_sdram_controler_0"
to "sdram", the system should look like:
(Click inside the picture to expand)
Perhaps you are asking, "why every time is it important to rename the components"?
At the beginning we have cheated a little bit. The VHDL source contains references to the name of the
components. Therefore it is important that we now rename the components. Even the source of the
application contains some references.
Now we will start to solve the errors. First we will create a global reset network. Select
"System > Create Global Reset Network":
This should solve some of the errors, and will connect the Reset to each component. The main window
will now look like:
Next the clock network must be connected. Unfortunately this must be done by yourself. Click at the
connection point "clk" from the "clk_sys" component, Qsys will display
possible connections:
Connect the clock to all components. The main window will now look like:
Next the data bus must be connected to the components. Click at the connection point "m0"
from the "wb_avm_bridge" component, Qsys will display possible connections:
Please connect the "m0" bus to all components. The main window will now look like:
The next step is to assign a base address to each component. Select "System >
Assign Base Addresses":
Let's start to solve the warnings. The warning looks like "aaa must be exported, or connected to a matching
conduit." This mean that there exist some "wires" which must be connected to the "outside"
of the cpu. We will start with the SDRAM. Click in the row of the "wire" from the SDRAM at "Click
to export". The main window will look like:
Important, rename the "sdram_wire" to "sdram". It should now looks like:
The same with the "wb_avm_bridge" component. Change the conduit to "avm":
There are no more errors or warnings and the system looks like this:
(Click inside the picture to expand)
We can now create our system, therefore click the "Generate HDL…" button, a
window will pop up. Remove here the checkmark from "Create block symbol file (.bsf)"
(1) and replace the "unsaved" from the "Output Directory" to "qsys_core" (2).
The window should now look like:
(Click inside the picture to expand)
And press "Generate" (3), a window will pop up which will look like:
Click "Save", and use "qsys_core.qsys" for the filename. The dialog should look like:
Press "Save" to close this dialog. Now Qsys will generate the system. This can take a moment:
At the end you should see the Info: "Generate Complete: completed successfukky."
Click "Close" to close the dialog.
Use "File > Exit" to close Qsys and return to the Quartus window. A new window pop
up which will look like:
Press "OK"
Now add "qsys_core.qip" to the files of the project. The project should now look like this:
In the next section we will add the NEORV32 processor.
NEORV32 processor
Here we will add the remaining components that we need:
- NEORV32 processor
- Wishbone Intercon
- Wishbone to Avalon master
For the "NEORV32 processor" add the file "C:\my_design\_de0n-neorv32-sdram-qsys\hw\src\neorv32.qip" to the project.
For the "Wishbone Intercon" use "C:\my_design\_de0n-neorv32-sdram-qsys\hw\src\wb_intercon\wb_intercon.vhd".
And for the "Wishbone to Avalon master" use "C:\my_design\_de0n-neorv32-sdram-qsys\hw\src\wb_av_master\wb_av_master.vhd".
The project should now look like this:
Compile the design
Compile the project, by selecting "Processing > Start Compilation":
This will start the compilation process which can take a while:
(Click inside the picture to expand)
Here we have 43 warnings and 1 "Critical Warning":
No exact pin location assignment(s) for 57 pins of 57 total pins.
Therefore in next section we will assign the pins of the FPGA.
Assign the pins
Now we can assign the input and output pins of the FPGA. But first of all we want to
set all unused pins to input tri-stated. Therefore use "Assignments > Device...".
The device window will be opened:
(Click inside the picture to expand)
Click "Device and Pin Options...". A new window will pop up. Change here the "Unused Pins:"
option to "As input tri-stated with weak pull-up". The window should look like:
(Click inside the picture to expand)
Click "OK" twice to close both windows. Now I will show you how to assign the
pin for CLOCK_50. To open the "Pin Planer", use "Assignments >
Pin Planner". A new window will be opened, it will look like:
(Click inside the picture to expand)
Double-click in the "Location" column for the CLOCK_50 signal to open a
drop-down list. Select here "PIN_R8", you will got the pin information from the data sheet of
the DE0-Nano board. Now double-click in the "I/O Standard" column and select "3.3-V LVTTL".
The window should now look like:
(Click inside the picture to expand)
You must repeat this procedure for all pins of your design. Do you want to cheat here?
Yes, are you sure? OK, close the "Pin Planer" first. After that, Quartus must also be
closed. The Pin information is stored in the "qsf" file. In our case in the file
"de0n-neorv32-sdram-qsys.qsf".
Use this file here and copy it
over the existing "de0n-neorv32-sdram-qsys.qsf".
Hopefully Quartus has accept the input? We will check this and open Quartus and the
"Pin Planer" again. Use "Assignments > Pin Planner" and scroll through the
"All Pins" list. It looks that the cheat was working on my side :o)
(Click inside the picture to expand)
We must compile the design again, this will be done in the next section.
Compile the design again
Like in the section before. Compile the project, by selecting "Processing >
Start Compilation":
This will start the compilation process which can take a while. "Please hold the
line..."
(Click inside the picture to expand)
There should be no, I will repeat it, no "Critical Warning" available.
The SOF file was created and we can program the FPGA in the next section.
Program the FPGA
I assumed that you have connect the DE0-Nano board still with your computer and the USB-Blaster driver
is still installed. For programming the FPGA select "Tools > Programmer":
(Click inside the picture to expand)
Everythink looks ok here. Click the "Start" button to program the FPGA. If you have problems to
program the FPGA, press the "Start" button again. If the LED0 is blinking the first 8 seconds
and the "Progress" indicator looks like:
If a terminal with the settings 19200, 8 N 1, is also connected, then you should see the following output:
After the 8 seconds the LED0 stops flashing and lights up permanently.
Drum roll, congratulations, you have created, compiled, and programmed your design! The
compiled SRAM Object File (.sof) is loaded onto the FPGA on the development board and the
design should be running.
Credits
Credits must be given to the NEORV32
project and their contributors.
JTAG and UART
And here are the pin assignments for JTAG and UART0:
If the FPGA was also programmed, then e.g. with a J-Link in the J-Link Commander after
the connection with the CPU you should see the following output:
(Click inside the picture to expand)
For the test, the connection between the DE0-Nano and the J-Link was made with a simple jumper
wire connection:
Fast Lane Test
For the quick test without having to set up the project, there is here the
de0n-neorv32-sdram-qsys.sof
file which simply has to be loaded into the FPGA with the programmer.
Download
And here the complete Quartus project which was created in the tutorial.
Quartus de0n-neorv32-sdram-qsys_20211203
project, for the DE0-Nano board (5.91 MB)
For other Intel FPGA boards there is my neorv32-examples repository on GitHub available.
|