NEORV32
Introduction
Hardware
Design Flow
Quartus II Project
Top-Level Entitiy
System PLL
Design Constraints File
Qsys and SDRAM
NEORV32 processor
Compile the design
Assign the pins
Compile the design again
Program the FPGA
Credits
JTAG and UART
Fast Lane Test
Download

(1) J-Link EDU
(3) Embedded Studio
 

Introduction

The following components are used for smooth RISC-V development on a FPGA:

1. JTAG interface (J-Link EDU)
2. FPGA Design Software (Intel Quartus Prime Lite)
3. Software development environment (SEGGER Embedded Studio for RISC-V)

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:

  1. NEORV32 processor
  2. Wishbone Intercon
  3. 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.