Skip to content

Commit

Permalink
Merge pull request #140 from IvanVeloz/post199
Browse files Browse the repository at this point in the history
Add setup for Gowin FPGAs - Tang Nano 9K dev board
  • Loading branch information
stnolting committed Feb 9, 2024
2 parents aa396de + fa3fa2e commit 40897cd
Show file tree
Hide file tree
Showing 7 changed files with 317 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ FPGA tools.
| :file_folder: [`nexys-a7-test-setup`](https://github.com/stnolting/neorv32-setups/tree/main/vivado/nexys-a7-test-setup) | Xilinx Vivado | [Digilent Nexys A7](https://reference.digilentinc.com/reference/programmable-logic/nexys-a7/start) | Xilinx Artix-7 `XC7A50TCSG324-1` | [AWenzel83](https://github.com/AWenzel83) |
| :file_folder: [`nexys-a7-test-setup`](https://github.com/stnolting/neorv32-setups/tree/main/vivado/nexys-a7-test-setup) | Xilinx Vivado | [Digilent Nexys 4 DDR](https://reference.digilentinc.com/reference/programmable-logic/nexys-4-ddr/start) | Xilinx Artix-7 `XC7A100TCSG324-1` | [AWenzel83](https://github.com/AWenzel83) |
| :file_folder: [`on-chip-debugger-intel`](https://github.com/stnolting/neorv32-setups/tree/main/quartus/on-chip-debugger-intel) | Intel Quartus Prime | [Gecko4Education](https://gecko-wiki.ti.bfh.ch/gecko4education:start) | Intel Cyclone IV E `EP4CE15F23C8` | [NikLeberg](https://github.com/NikLeberg) |

| :file_folder: [`tang-nano-9k`](https://github.com/stnolting/neorv32-setups/tree/main/gowineda/tang-nano-9k) | Gowin EDA | [Sipeed Tang Nano 9K](https://wiki.sipeed.com/hardware/en/tang/Tang-Nano-9K/Nano-9K.html) | Gowin LittleBee GW1NR-9 `GW1NR-LV9QN88PC6/I5` | [IvanVeloz](https://github.com/IvanVeloz)
[[back to top](#exemplary-neorv32-setups-and-projects)]


Expand Down
42 changes: 42 additions & 0 deletions gowineda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# NEORV32 Gowin EDA Example Setups

## How To Run

The `create_project.tcl` TCL script in the board subdirectories can be used for creating a complete Gowin EDA project and for running the implementation.
If not already available, this script will create a `work` folder in those subdirectories. Assuming that `gw_sh` is on you path, you can run `gw_sh create_project.tcl`. You can also pass arguments like `gw_sh create_project.tcl --project-name myproject --project-path "~/Sources"`.

Arguments do not work if you are already inside the Gowin shell (e.g. `% source create_project.tcl`), at least not as of version 1.9.9. You can set environment variables instead, like `set nrv_project_name myproject` and `set nrv_project_creation_path "~/Sources"`. Check the source code for all the flags.

### Creating from a shell

Execute the Gowin shell `gw_sh create_project.tcl` from the board subdir.
The project will be created. You can then open the project from the Gowin IDE to synthesise and route, and finally program the device with the Gowin Programmer.

### GUI

As of version 1.9.9, trying to create the project from the Gowin IDE GUI will result in the script stopping as soon as the new project is created, so the project will be missing the VHDL and constraint files. A workaround is possible, explained below.

1. start the Gowin IDE
2. click on the TCL Console text box at the bottom, next to the "%" symbol
3. use the console to navigate to the board's folder. For example `cd somewhere/neord32-setups/gowineda/tang-nano-9k`
4. execute `source create_project.tcl` —this will create the actual project in the `work` directory. As of version 1.9.9, this will launch a new instance of the Gowin IDE, with the project open.
5. move over to the TCL console on the new Gowin IDE window that just opened
6. execute `set nrv_skip_creation true`
7. execute `source ../create_project.tcl`
8. execute `unset nrv_skip_creation`
9. at this point you can manually run the synthesis and routing, and program the device.

## Programming the Bitstream

1. open the Programmer by clicking on its icon in the toolbar.
2. select the appropriate cable and click save.
* **note**: under Linux, you must not be running the `ftdi_sio` kernel module for some Gowin programmers to work (e.g. Tang Nano 9K's built-in BL702 microcontroller). To stop this module, run `sudo modprobe -r ftdi_sio`, and "query the cables" again on the programmer software. The port will change from "USB Debugger A/0/0/null" to something like "USB Debugger A/0/4177/null". To restore the board's serial port functionallity, add `ftdi_sio` again: run `sudo modprobe ftdi_sio`. There is no need to unplug the device from the USB port.
3. select the correct FPGA part number.
4. the .fs bitstream file should be automatically loaded, if not, click on the blank cell below the "FS file" header, and click the ellipsis (...). The file is at `work/impl/pnr/work.fs`.
5. adjust any other settings you want and click the "Program/Configue" icon.
6. at this point you should see the board flashing the LED number 1 (at the top) for a few seconds. Congratulations! This means the processor and bootloader are working.
* **note**: under Linux, make sure you add the `ftdi_sio` kernel module again, to allow communication with the board. You should see two new serial ports if you run `ls /dev/ttyUSB*`. Use the highest numbered out of the two.
7. use a serial terminal (like :earth_asia: [Tera Term](https://ttssh2.osdn.jp/index.html.en)) to connect to the USB-UART interface using the following configuration:
19200 Baud, 8 data bits, 1 stop bit, no parity bits, no transmission / flow control protocol (raw bytes only), newline on `\r\n` (carriage return & newline)
8. now you can communicate with the bootloader console and upload a new program. Check out the [example programs](https://github.com/stnolting/neorv32/tree/master/sw/example)
and see section "Let's Get It Started" of the :page_facing_up: [NEORV32 data sheet](https://github.com/raw/stnolting/neorv32/master/docs/NEORV32.pdf) for further resources.
1 change: 1 addition & 0 deletions gowineda/tang-nano-9k/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
work/
26 changes: 26 additions & 0 deletions gowineda/tang-nano-9k/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# NEORV32 Test Setup for the Sipeed Tang Nano 9K FPGA development board

This setup provides a simple script that you can run using the Gowin shell and creates a project with the NEORV32 processor already imported and ready to synthesize in the Gowin FPGA Designer IDE.
It uses the simplified [`neorv32_test_setup_bootloader.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/test_setups/neorv32_test_setup_bootloader.vhd) top entity, which is a wrapper for the actual processor top entity that provides a minimalistic interface (clock, reset, UART and 6 LEDs).

* FPGA Board:
* :books: [Sipeed Tang Nano 9K](https://wiki.sipeed.com/hardware/en/tang/Tang-Nano-9K/Nano-9K.html)
* FPGA:
* Gowin LittleBee GW1NR `GW1NR-LV9QN88PC6/I5`
* Toolchain: Gowin EDA (tested with Gowin EDA 1.9.9 on Linux —not a 1.9.9 beta)

## NEORV32 Configuration

:information_source: See the top entity [`rtl/test_setups/neorv32_test_setup_bootloader.vhd` ](https://github.com/stnolting/neorv32/blob/master/rtl/test_setups/neorv32_test_setup_bootloader.vhd) for
configuration and entity details and [`tang-nano-9k_test_setup_bootloader.cst`](https://github.com/IvanVeloz/neorv32-setups/blob/master/gowineda/tang-nano-9k/tang-nano-9k_test_setup_bootloader.cst)
for the according FPGA pin mapping.

* CPU: `rv32imcu_Zicsr` + 4 `HPM` (hardware performance monitors)
* Memory: 16kB instruction memory (internal IMEM), 8kB data memory (internal DMEM), bootloader ROM
* Peripherals: `GPIO`, `MTIME`, `UART0`, `WDT`
* Tested with version [`1.9.2.5`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md)
* Clock: 27MHz from on-board oscillator
* Reset: Via dedicated on-board "RESET" button
* GPIO output port `gpio_o` bits 0..5 are connected to the orange on-board LEDs (LED1 - LED6); LED6 is the bootloader status LED
* UART0 signals `uart0_txd_o` and `uart0_rxd_i` are connected to the on-board USB-UART chip
* Under Linux, run `sudo modprobe ftdi_sio` for the on-board UART to appear under `/dev/ttyUSB*` (the higher of the two ports that will appear). Run `sudo modprobe -r ftdi_sio` to be able to program the device on the Gowin Programmer. There is no need to unplug the device from the USB port.
177 changes: 177 additions & 0 deletions gowineda/tang-nano-9k/create_project.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#!/usr/bin/env gw_sh
# Must be run on Gowin EDA version 1.9.9 or later (no 1.9.9 betas)

# TODO: implement flag to immediately synthesise using run all (implement
# "batch mode")

# Available flags
# Example usage:
# `gw_sh create_project.tcl --skip-creation`
#
# --skip-creation skips the creation of the project. Useful inside the Gowin IDE
# when you already created a project but haven't imported the NEORV32 files.
# --force-project overwrites the project file if it already exists
# --force-import overwrites any NEORV32 files that already exist in your
# project's src directory. Use with caution.
# --project-name [NAME] lets you specify a name for the project instead of the
# default name of "work".
# --project-path [PATH] lets you specify a path for the project instead of the
# default path of the current working directory.

# Available environment variables
# The flags take precedence over the environment variables. Example usage:
# `set nrv_project_name myproject`
# `set nrv_project_creation_path ~/Sources`
# `source create_project.tcl`
# `unset nrv_project_name`
# `unset nrv_project_creation_path`
# Unsetting the variables is not absolutely necessary, but they will keep their
# values if you don't, and they will affect this and other scripts every time
# you source them.
#
# nrv_skip_creation equivalent to `--skip-creation` if set to `true`.
# nrv_force_project equivalent to `--force-project` if set to `true`.
# nrv_force_import equivalent to `--force-import` if set to `true`.
# nrv_project_name equivalent to `--project-name`. Set to the project name.
# nrv_project_creation_path equivalent to `--project-path`. Set to project path.

# Record some basic directories
set starting_dir [pwd]
set script_dir [file dirname [info script]]

# Force script_dir to be an absolute path
if { ![string match {/*} $script_dir] } {
cd $script_dir
set script_dir [pwd]
cd $starting_dir
}

set neorv32_dir $script_dir/../../neorv32

# Declare flags, use environment variable values if they exist, else defaults
set flags_project ""
set flags_import ""
set flag_skip_creation false
set project_name work
set project_creation_path [pwd]

if {[info exists nrv_skip_creation]} {
set flag_skip_creation $nrv_skip_creation }

if {[info exists nrv_force_project] && ($nrv_force_project == true)} {
lappend flags_project -force }

if {[info exists nrv_force_import] && ($nrv_force_import == true)} {
lappend flags_import -force }

if {[info exists nrv_project_name]} {
set project_name $nrv_project_name }

if {[info exists nrv_project_creation_path]} {
set project_creation_path $nrv_project_creation_path }

# Parse arguments passed.
if {[info exists argc] && ($argc>0)} {
for {set i 0} {$i < $argc} {incr i} {
set current_arg [lindex $argv $i]
switch $current_arg {
"--skip-creation" { set flag_skip_creation true }
"--force-project" { lappend flags_project -force }
"--force-import" { lappend flags_import -force }
"--project-name" { incr i; set project_name [lindex $argv $i] }
"--project-path" { incr i; set project_creation_path [lindex $argv $i] }
}
}
}

# Force project_creation_path to be an absolute path
if { ![string match {/*} $project_creation_path] } {
cd $project_creation_path
set project_creation_path [pwd]
cd $starting_dir
}

puts "create_project flags: $flags_project"
puts "import_files flags: $flags_import"


# If you want to customize the values below, the full list is available on
# [Gowin EDA path]/IDE/data/device/device_info.csv
# column B (2nd)
set part_number GW1NR-LV9QN88PC6/I5
# column D (4th)
set device GW1NR-9C
# column F (6th)
set version C
# column G (7th)
set package QFN88P

if {!$flag_skip_creation} {
puts "Creating project"
create_project \
-name $project_name \
-dir $project_creation_path \
-pn $part_number \
-device_version $version \
{*}$flags_project
}

# Creating the project creates a new directory in project_path with the
# project's name and changes into that directory. Let's save it for later.
# project_dir should be equal to $project_path/project_name
set project_dir [pwd]

# --- Importing neorv32 library files ---
source $script_dir/import_neorv32.tcl

# --- Importing bootloader template file and constraint file ---
import_files \
-file $neorv32_dir/rtl/test_setups/neorv32_test_setup_bootloader.vhd \
{*}$flags_import
import_files \
-file $script_dir/tang-nano-9k_test_setup_bootloader.cst \
{*}$flags_import

# --- Modify bootloader template file ---
set fd [open $project_dir/src/neorv32_test_setup_bootloader.vhd r]
set fc [read $fd]
close $fd
# CLOCK_FREQUENCY : natural := 100000000; -- clock frequency of clk_i in Hz
regsub -all {100000000;} $fc {27000000; } fc
# gpio_o : out std_ulogic_vector(7 downto 0); -- parallel output
regsub -all \
{gpio_o\s*?:\s*?out\s+std_ulogic_vector\s*?\(\s*?[0-9]+\s+downto\s+0\s*?\)} \
$fc {gpio_o : out std_ulogic_vector(5 downto 0)} fc
# gpio_o <= con_gpio_o(7 downto 0);
regsub -all \
{gpio_o\s*?<=\s*?con_gpio_o\s*?\(\s*?[0-9]+\s+downto\s+0\s*?\)} \
$fc {gpio_o <= con_gpio_o(5 downto 0)} fc
set fd [open $project_dir/src/neorv32_test_setup_bootloader.vhd w]
puts -nonewline $fd $fc
close $fd

# --- Setting top level file ---
set_option -top_module neorv32_test_setup_bootloader

# --- Setting dual-purpose pin configuration ---
set_option -use_done_as_gpio 1

# --- Other set_options ---
set_option -synthesis_tool gowinsynthesis
set_option -output_base_name tang-nano-9k

# --- Unset variables ---
unset flags_project
unset flags_import
unset flag_skip_creation
unset starting_dir
unset script_dir
unset neorv32_dir
unset part_number
unset device
unset version
unset package


# --- Return to the newly created project directory ---
cd $project_dir
44 changes: 44 additions & 0 deletions gowineda/tang-nano-9k/import_neorv32.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Usage:
# * Use on an existing project where you want to import neorv32. Importing
# copies all the neorv32 core files into your project. It makes your project
# self-contained. To update your neorv32 library, first get the up to date
# files and run the updated import_neorv32.tcl with the -force flag from
# the Gowin EDA TCL console.
#
# * On the command console (%) type:
# source /path/to/this/import_neorv32.tcl
# Or, with the force flag
# set nrv_force_import true
# source /path/to/this/import_neorv32.tcl
# unset nrv_force_import


# Assume we are being called from the project directory
if {![info exists project_dir]} {
set project_dir [pwd]
puts "Assumming project directory is $project_dir"
}

# Environment variables (flags_import is declared by create_project)
if {![info exists flags_import]} {
set flags_import ""
if {[info exists nrv_force_import] && ($nrv_force_import == true)} {
lappend flags_import -force }
}

set import_script_dir [file dirname [info script]]
set import_neorv32_dir $import_script_dir/../../neorv32/

# Add all neorv32 core files to the project
set corefiles [glob $import_neorv32_dir/rtl/core/*.vhd]
foreach corefile $corefiles {
import_files -file $corefile {*}$flags_import
set_file_prop -lib neorv32 $project_dir/src/[file tail $corefile]
# TODO: verify set_file_prop call is refering to the files correctly
}
set memfiles [glob $import_neorv32_dir/rtl/core/mem/*.default.vhd]
foreach memfile $memfiles {
import_files -file $memfile {*}$flags_import
set_file_prop -lib neorv32 $project_dir/src/[file tail $memfile]
# TODO: verify set_file_prop call is refering to the files correctly
}
26 changes: 26 additions & 0 deletions gowineda/tang-nano-9k/tang-nano-9k_test_setup_bootloader.cst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//Part Number: GW1NR-LV9QN88PC6/I5
//Device: GW1NR-9
//Device Version: C

IO_LOC "gpio_o[0]" 10;
IO_PORT "gpio_o[0]" IO_TYPE=LVCMOS33 DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "gpio_o[1]" 11;
IO_PORT "gpio_o[1]" IO_TYPE=LVCMOS33 DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "gpio_o[2]" 13;
IO_PORT "gpio_o[2]" IO_TYPE=LVCMOS33 DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "gpio_o[3]" 14;
IO_PORT "gpio_o[3]" IO_TYPE=LVCMOS33 DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "gpio_o[4]" 15;
IO_PORT "gpio_o[4]" IO_TYPE=LVCMOS33 DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "gpio_o[5]" 16;
IO_PORT "gpio_o[5]" IO_TYPE=LVCMOS33 DRIVE=8 BANK_VCCIO=3.3;

IO_LOC "uart0_rxd_i" 18;
IO_PORT "uart0_rxd_i" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "uart0_txd_o" 17;
IO_PORT "uart0_txd_o" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;

IO_LOC "rstn_i" 3;
IO_PORT "rstn_i" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "clk_i" 52;
IO_PORT "clk_i" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;

0 comments on commit 40897cd

Please sign in to comment.