Skip to content

Commit

Permalink
Merge pull request #68 from pulp-platform/marcowidmer-fpga-zcu104
Browse files Browse the repository at this point in the history
  • Loading branch information
Manuel Eggimann committed Aug 6, 2019
2 parents 7604b23 + d99d715 commit f33ecbc
Show file tree
Hide file tree
Showing 36 changed files with 1,484 additions and 39 deletions.
102 changes: 65 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,31 +171,60 @@ More information is available in the documentation here: pulp-builder/install/do

## FPGA

PULPissimo has been implemented on FPGA for the Xilinx Genesys 2 board.
Follow the next steps to generate the bitstream and use it as an emulator of the microcontroller.
PULPissimo has been implemented on FPGA for the various Xilinx FPGA boards.

Go to the fpga folder and run
### Supported Boards
At the moment the following boards are supported:
* Digilent Genesys2
* Xilinx ZCU104

In the release section you find precompiled bitstreams for all of the above
mentionied boards. If you want to use the latest development version PULPissimo
follow the section below to generate the bitstreams yourself.

### Bitstream Generation
In order to generate the PULPissimo bitstream for a supported target FPGA board first generate the necessary synthesis include scripts by starting the `update-ips` script in the pulpissimo root directory:

```Shell
make help
./update-ips
```

This lists a brief description of all available Make targets.
This will parse the ips_list.yml using the PULP IPApproX IP management tool to
generate tcl scripts for all the IPs used in the PULPissimo project. These files
are later on sourced by Vivado to generate the bitstream for PULPissimo.

In this tutorial we use the Digilent Genesys2 board which is the only one supported at the moment.
Now switch to the fpga subdirectory and start the apropriate make target to generate the bitstream:

Therefore, run
```Shell
cd fpga
make <board_target>
```
In order to show a list of all available board targets call:

```Shell
make genesys2
make help
```

in order to generate the PULPissimo bitstream for the GENESYS2 board. If your invocation command to start Vivado isn't `vivado` you can use the Make variable `VIVADO` to specify the right command (e.g. `make genesys2 VIVADO='vivado-2018.3 vivado'` for ETH CentOS machines.)
Boot from ROM is not available yet. The ROM will always return the `jal x0,0` to trap the core until the debug module takes over control and loads the programm into L2 memory.
Once the bitstream `pulpissimo_genesys2.bit` is generated in the fpga folder, you can open Vivado
`vivado` (we tried the 2018.3 version) and load the bitstream into the fpga or use the Configuration File (`pulpissimo_genesys2.bin`) to flash it to the on-board Configuration Memory.
This process might take a while. If everything goes well your fpga directory
should now contain two files:

- `pulpissimo_<board_target>.bit` the bitstream file for JTAG configuration of the FPGA.
- `pulpissimo_<board_target>.bin` the binary configuration file to flash to a
non-volatile configuration memory.

In Vivado:

If your invocation command to start Vivado isn't `vivado` you can use the Make
variable `VIVADO` to specify the right command (e.g. `make genesys2
VIVADO='vivado-2018.3 vivado'` for ETH CentOS machines.) Boot from ROM is not
available yet. The ROM will always return the `jal x0,0` to trap the core until
the debug module takes over control and loads the programm into L2 memory. Once
the bitstream `pulpissimo_genesys2.bit` is generated in the fpga folder, you can
open Vivado `vivado` (we tried the 2018.3 version) and load the bitstream into
the fpga or use the Configuration File (`pulpissimo_genesys2.bin`) to flash it
to the on-board Configuration Memory.

### Bitstream Flashing
Start Vivado then:

```
Open Hardware Manager
Expand All @@ -205,34 +234,35 @@ Program device

Now your FPGA is ready to emulate PULPissimo!

### Board Specific Information
Have a look at the board specific README.md files in
`fpga/pulpissimo-<board_target>/README.md` for a description of peripheral
mappings and default clock frequencies.

To run or debug applications for the fpga you need to use a recent version of the PULP-SDK (commit id 3256fe7 or newer.'). Configure the SDK for the FPGA platform by running the following commands within the SDK's root directory:
### Compiling Applications for the FPGA Target
To run or debug applications for the FPGA you need to use a recent version of
the PULP-SDK (commit id 3256fe7 or newer.'). Configure the SDK for the FPGA
platform by running the following commands within the SDK's root directory:

```Shell
source configs/pulpissimo.sh
source configs/fpgas/pulpissimo/genesys2.sh
source configs/fpgas/pulpissimo/<board_target>.sh
```

If you updated the SDK don't forget to recompile the SDK and the dependencies.

In order for the SDK to be able to configure clock dividers (e.g. the ones for
the UART module) to the right values it needs to know which frequencies
PULPissimo is running at. If you didn't change anything in the synthesis script, the default frequencies are:


| Clock Domain | Default Frequency on Genesys2 board |
|----------------|-------------------------------------|
| Core Frequency | 20 MHz |
| SoC Frequency | 10 MHz |
PULPissimo is running at. You can find the default frequencies in the above
mentioned board specific README files.


We need to override two weakly defined variables in our source code to configure the SDK to use these frequencies:
In our application we need to override two weakly defined variables in our source code to configure the SDK to use these frequencies:
```C
#include <stdio.h>
#include <rt/rt_api.h>

int __rt_fpga_fc_frequency = 20000000;
int __rt_fpga_periph_frequency = 10000000;
int __rt_fpga_fc_frequency = <Core Frequency> // e.g. 20000000 for 20MHz;
int __rt_fpga_periph_frequency = <SoC Frequency> // e.g. 10000000 for 10MHz;

int main()
{
Expand All @@ -257,21 +287,16 @@ make clean all
This command builds the ELF binary with UART as the default io peripheral.
The binary will be stored at `build/pulpissimo/[app_name]/[app_name]`.


### GDB and OpenOCD
In order to execute our application on the FPGA we need to load the binary into
PULPissimo's L2 memory. To do so we can use OpenOCD in conjunction with GDB to
communicate with the internal RISC-V debug module.

For the genesys2 board we need to connect two micro USB cables to the board: The
first cable connects to the JTAG port that is usually used for FPGA
configuration. Once the PULPissimo bitstream is written to the FPGA the same
port is used to let OpenOCD communicate with the RISC-V debug module within
PULPissimo. The second micro USB cable needs to be attached to the genesys2's
UART port to observe the output of the application's `printf` statements.
PULPissimo uses JTAG as a communication channel between OpenOCD and the Core.
Have a look at the board specific README file on how to connect your PC with
PULPissimo's JTAG port.


Due to a long outstanding issue in the RISC-V openocd project (issue #359) the
Due to a long outstanding issue in the RISC-V OpenOCD project (issue #359) the
riscv/riscv-openocd does not work with PULPissimo. However there is a small
workaround that we incorporated in a patched version of openocd. If you have
access to the artifactory server, the patched openocd binary is installed by
Expand Down Expand Up @@ -300,12 +325,15 @@ source sourceme.sh && ./pulp-tools/bin/plpbuild checkout build --p openocd --std
The SDK will automatically set the environment variable `OPENOCD` to the
installation path of this patched version.

Launch openocd with the configuration file for the genesys2 board as an argument with:
Launch openocd with one of the provided or your own configuration file for the
target board as an argument.

E.g.:

```Shell
$OPENOCD/bin/openocd -f pulpissimo/fpga/pulpissimo-genesys2/openocd-genesys2.cfg
```
In a seperate terminal launch gdb from your pulp_riscv_gcc installation passing the ELF file as an argument with:
In a seperate terminal launch gdb from your `pulp_riscv_gcc` installation passing the ELF file as an argument with:

`$PULP_RISCV_GCC_TOOLCHAIN_CI/bin/riscv32-unknown-elf-gdb PATH_TO_YOUR_ELF_FILE`

Expand Down
2 changes: 2 additions & 0 deletions fpga/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pulpissimo/*
pulpissimo_genesys2.bin
pulpissimo_genesys2.bit
pulpissimo_zcu104.bin
pulpissimo_zcu104.bit
15 changes: 13 additions & 2 deletions fpga/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.DEFAULT_GOAL:=help

all: genesys2 ## Generates the bitstream for all supported boards board.
all: genesys2 zcu104 ## Generates the bitstream for all supported boards board.

clean_all: clean_genesys2 ## Removes synthesis output and bitstreams for all boards.
clean_all: clean_genesys2 clean_zcu104 ## Removes synthesis output and bitstreams for all boards.

genesys2: ## Generates the bistream for the genesys2 board
cd pulpissimo-genesys2; make all
Expand All @@ -15,6 +15,17 @@ clean_genesys2: ## Removes all bitstreams, *.log files and vivado related files
rm -f pulpissimo_genesys2.bit
rm -f pulpissimo_genesys2.bin

zcu104: ## Generates the bistream for the zcu104 board
cd pulpissimo-zcu104; make all
cp pulpissimo-zcu104/pulpissimo_zcu104.runs/impl_1/xilinx_pulpissimo.bit pulpissimo_zcu104.bit
cp pulpissimo-zcu104/pulpissimo_zcu104.runs/impl_1/xilinx_pulpissimo.bin pulpissimo_zcu104.bin
@echo "Bitstream generation for zcu104 board finished. The bitstream Configuration Memory File was copied to ./pulpissimo_zcu104.bit and ./pulpissimo_zcu104.bin"

clean_zcu104: ## Removes all bitstreams, *.log files and vivado related files (rm -rf vivado*) for the zcu104 board.
cd pulpissimo-zcu104; make clean
rm -f pulpissimo_zcu104.bit
rm -f pulpissimo_zcu104.bin

help: ## Show this help message
@echo "PULPissimo on FPGA"
@echo ""
Expand Down
56 changes: 56 additions & 0 deletions fpga/pulpissimo-genesys2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# PULPissimo on the Digilent Genesys2 Board
[\[Documentation\]](https://reference.digilentinc.com/reference/programmable-logic/genesys-2/start)

## Bitstream Generation
In the fpga folder, run
```Shell
make genesys2
```
which will generate `pulpissimo_genesys2.bit`.
Use Vivado to load it into the FPGA.

## Default SoC and Core Frequencies

By default the clock generating IPs are synthesized to provide the following frequencies to PULPissimo:

| Clock Domain | Default Frequency on Genesys2 board |
|----------------|-------------------------------------|
| Core Frequency | 20 MHz |
| SoC Frequency | 10 MHz |


## Peripherals
PULPissimo is connected to the following board peripherals:


| PULPissimo Pin | Mapped Board Peripheral |
|----------------|-----------------------------------------------------|
| `SPIM0` pins | QSPI Flash |
| `I2C0` pins | I2C Bus (connects to Board Current Measurement ICs) |
| `spim_csn1` | LED0 |
| `cam_pclk` | LED1 |
| `cam_hsync` | LED2 |
| `cam_data0` | LED3 |
| `cam_data1` | Switch 1 |
| `cam_data2` | Switch 2 |
| `cam_data3` | Button C |
| `cam_data4` | Button D |
| `cam_data5` | Button L |
| `cam_data6` | Button R |
| `cam_data7` | Button U |

### Reset Button
The USER RESET button (BTN1) resets the RISC-V CPU.

### UART
PULPissimo's UART port is mapped to the onboard FTDI FT232R USB-UART bridge and thus accessible through the UART micro-USB connector J15.

### JTAG
PULPIssimo's JTAG plug is connected to Channel 0 of the onboard FTDI USB JTAG
programmer. Therefore we can attach OpenOCD withouth the need of an external
JTAG programmer. Just attach a micro-USB cable to the JTAG SW17 micro-USB connector and use the
provided OpenOCD configuration file:

```Shell
$OPENOCD/bin/openocd -f pulpissimo/fpga/pulpissimo-genesys2/openocd-genesys2.cfg
```
22 changes: 22 additions & 0 deletions fpga/pulpissimo-zcu104/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#Ignore vivado project files generated by the tcl script
**/.Xil/*
**/reports/*
**/*.cache/*
**/*.hw/*
**/*.ip_user_files/*
**/*.runs/*
**/*.sim/*
**/*.srcs/*
*.edf
*.xpr
*.jou
*.log

.cxl.*

*_stub.v
gmon.out

/pulpissimo/**/pulpissimo.bit

**/xdc/constraints.xdc
44 changes: 44 additions & 0 deletions fpga/pulpissimo-zcu104/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
PROJECT:=pulpissimo_zcu104
VIVADO ?= vivado
VIVADOFLAGS ?= -nojournal -mode batch -source scripts/prologue.tcl

include fpga-settings.mk

.DEFAULT_GOAL:=help

.PHONY: help

all: ips ## Generate the bitstream for pulpissimo with vivado in batch mode. The vivado invocation command may be overriden with the env variable VIVADO.
$(VIVADO) -mode batch -source tcl/run.tcl

gui: ips ## Generates the bitstream for pulpissimo with vivado in GUI mode. The vivado invocation command may be overriden with the env variable VIVADO.
$(VIVADO) -mode gui -source tcl/run.tcl &

ips: clk ram ## Synthesizes necessary xilinx IP

clean-ips: clean-clk clean-ram ## Clean all IPs

clk: ## Synthesizes the Xilinx Clocking Manager IPs
cd ips/xilinx_clk_mngr; make clean all
cd ips/xilinx_slow_clk_mngr; make clean all

clean-clk: ## Removes all Clocking Wizard IP outputs
cd ips/xilinx_clk_mngr; make clean
cd ips/xilinx_slow_clk_mngr; make clean

ram: ## Synthesizes the Xilinx Block Memory Generator IPs for PULPissimo's L2 Ram
cd ips/xilinx_interleaved_ram; make clean all
cd ips/xilinx_private_ram; make clean all

clean-ram: ## Removes all Block Ram IP outputs related to l2 ram
cd ips/xilinx_interleaved_ram; make clean
cd ips/xilinx_private_ram; make clean

clean: ## Removes all bitstreams, *.log files and vivado related files (rm -rf vivado*)
rm -rf ${PROJECT}.*[^'bit']
rm -rf ${PROJECT}.*[^'bin']
rm -rf *.log
rm -rf vivado*

help:
@grep -E -h '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
52 changes: 52 additions & 0 deletions fpga/pulpissimo-zcu104/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# PULPissimo on the Xilinx ZCU104 Board
[\[Datasheet\]](https://www.xilinx.com/support/documentation/boards_and_kits/zcu104/ug1267-zcu104-eval-bd.pdf)

## Bitstream Generation
In the fpga folder, run
```Shell
make zcu104
```
which will generate `pulpissimo_zcu104.bit`.
Use Vivado to load it into the FPGA.

## Default SoC and Core Frequencies

By default the clock generating IPs are synthesized to provide the following frequencies to PULPissimo:

| Clock Domain | Default Frequency on ZCU104 board |
|----------------|------------------------------------|
| Core Frequency | 20 MHz |
| SoC Frequency | 10 MHz |


## Peripherals
Most peripherals of are connected to the ARM processing system domain of the SoC and cannot be used from the programmable logic domain.
The peripherals available to PULPissimo are thus very limited.

### Reset Button
The CPU RESET button (SW20) resets the RISC-V CPU.

### UART
PULPissimo's UART port is mapped to Channel D of the FT4232HL chip.
When connecting the board to a computer using the USB/JTAG/UART micro-USB connector (J164), it is the last of the four detected serial devices.

### JTAG
Unfortunately, only one channel of the FT4232HL chip is connected to the programmable logic domain.
Since we are using that channel for UART, the micro-USB connector on the board cannot be used to communicate with the RISC-V debug module over JTAG.
Instead, you need to connect a separate JTAG adapter to the GPIO port (PMOD0 header) of the board:

| JTAG Signal | FPGA Port | J55 Pin |
|-------------|-----------|----------|
| tms | PMOD0_0 | Pin 1 |
| tdi | PMOD0_1 | Pin 3 |
| tdo | PMOD0_2 | Pin 5 |
| tck | PMOD0_3 | Pin 7 |
| gnd | GND | Pin 9 |
| vdd | 3V3 | Pin 11 |

An OpenOCD configuration file for the Digilent JTAG-HS1 adapter is included.
To use it, run

```Shell
$OPENOCD/bin/openocd -f pulpissimo/home/meggiman/projects/pulp/pulpissimo/fpga/pulpissimo-zcu104/openocd-zcu104-digilent-jtag-hs1.cfg
```
Loading

0 comments on commit f33ecbc

Please sign in to comment.