Working with Zedboard
lowRISC was ported to Zedboard in KU Leuven - COSIC to design and verify trusted computing hardware extensions
Porting lowRISC to Zedboard
Zedboard is versatile development board utilising Zynq SoC. It has been used in several implementations of RISC-V; hosting it as a neighbour to the Zynq’s hard-coded ARM cores. However, in Zedboard the ARM cores of the Zynq are dominant: almost all peripherals or ports connect to the ARM Processing System (PS), and they are not directly reachable from Programmable Logic (PL). That makes the RISC-V, implementated in PL, inaccessible without passing through the ARM PS. Therefore, the RISC-V implementations for Zynq (including the original release by Berkeley or the earliest lowRISC design) use so called Host/Target Interface (HTIF), which has the front-end server running on PS and communicating with the target RISC-V implemented in PL, which is the tethering of RISC-V to ARM.
Compared to the other RISC-V implementations, lowRISC’s achievement of offering an untethered RISC-V implementation is great; however, made the design leave the Zynq devices initially. However, with the implementation described in this page, the Zedboard support is added again. Zedboard’s SD Card and UART ports are connected directly to ARM; therefore, the port of lowRISC to Zedboard requires obtaining two low-cost PMOD modules to provide RISC-V with dedicated IO, and continue working untethered.
Together with the PMODs, the board looks like it is in the image below:
Dedicated IO is provided to RISC-V with PMODs; however, the Zedboard has a single DDR RAM, and it is connected to the Zynq SoC through the memory controller of ARM PS. Therefore, in this Zedboard port of lowRISC, the RISC-V accesses to memory through the ARM PS. In other words, the memory is shared between the ARM and RISC-V cores. The
chip-top.v file is expanded to make nasti memory port of RISC-V accessible as module IO, instead of connecting it to MIG IP Core as other board implementations do. On top of this, a block diagram is provided which instantiates the ARM PS7. Finally,
Wrapper.v is provided as the top-design file, which connects the ARM PS7 and RISC-V. This connection manages clock and reset signals, and connects the RISC-V nasti memory port to the PS7’s memory controller through HP0 AXI port.
A great outcome of this port is one board with two systems on same chip; one of which is ARM, the most accepted architecture for embedded devices, and the other is RISC-V, the most promising. Once can configure to run them independent of each other, and establish shared memory communication as they physically share the memory.
The Tutorial on Working with Zedboard
Get the lowRISC development environment.
git clone -b debug-v0.3 --recursive https://github.com/lowrisc/lowrisc-chip.git
Now you need to prepare the environment as described here
- If you haven’t before, compile and install RISC-V cross compiler
If you haven’t before, install Vivado and set your environment Note: The Zedboard port is implemented with Vivado 2016.2
Set environment variables:
export FPGA_BOARD=zed source set_env.sh
Implement the FPGA Project
Go to the Zedboard submodule.
Before continuing, make sure that you have the correct pin mapping of your PMOD connections in the
$TOP/fpga/board/zed/constraint/pin_plan.xdc file. In the default configuration (above image), PMOD SD is connected to JB headers of the Zedboard, and PMOD RS232 is connected to the (upper pins of) JC headers. If PMOD USBUART is preferred, as it is not pin-to-pin compatible with the RS232, comment the RS232 mapping lines on the
pin_plan.xdc file, and uncomment the lines for USBUART.
As the work environment is ready, you can work with make targets:
|generates the FPGA backend Verilog files
|generates the Vivado project
|opens the project in Vivado GUI
|generates bit-stream for programming.
|finds out the boot BRAMs’ name and position (for updating src/boot.bmm).
|replaces the content of boot BRAM with a new src/boot.mem (must update src/boot.bmm first).
|programs the device with updated bitstream.
|compiles the example codes in
$TOP/fpga/bare_metal/examples, and automatically executes
make bit-update for the compiled.
“Hello World!” from RISC-V
To receive the friendly welcome message, execute hello and program make targets sequentially. The first make target will compile the hello code in
$TOP/fpga/bare_metal/examples/ for RISC-V ISA, then load it to BRAM of the design which stores the user code that will be executed first. Next, the design will be synthesized, implemented and corresponding bitstream will be generated. The second make target is to program the device with the generated bitstream.
To receive RISC-V’s terminal dump, a serial terminal should be running for the UART port associated with the PMOD module. You can use microcom, which is the recommended serial terminal application:
microcom -p /dev/ttyUSB0 -s 115200
Booting Linux on RISC-V
Above this subtitle, setting the environment, generating hardware, and programming the device were introduced. For booting Linux, the same procedure will be followed, except the change in the target RISC-V application. Instead of hello, the boot target will be used. This target sets the BRAM with bootloader as the first user application. The bootloader opens SD Card (from the PMOD), reads Linux image from there, copies it to memory and hands over hardware’s control to it.
Before jumping to program RISC-V for booting Linux, prepare the SD Card with the Linux image.
Build the port of Linux kernel for the RISC-V instruction set architecture as described here:
curl https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.6.2.tar.xz | tar -xJ
curl -L http://busybox.net/downloads/busybox-1.21.1.tar.bz2 | tar -xj
git remote add origin https://github.com/lowrisc/riscv-linux.git
git checkout -f -t origin/debug-v0.3
# lowRISC-specific hack for enabling power pin for SD card
patch -p1 < spi_sd_power_hack.patch
Copy the generated
$TOP/fpga/board/zed/boot.bin to SD Card.
Program RISC-V with Bootloader
As it was for the hello, execute boot and program make targets sequentially.
Finally, you will see Linux initialise with the dump like:
lowRISC boot program
Load boot.bin into memory
Load 5563024 bytes to memory address 87000000 from boot.bin of 5563024 bytes.
load elf to DDR memory
Boot the loaded program...
rr vvvvvvvvvvvvvvvvvvvvvvvv rr
rrrr vvvvvvvvvvvvvvvvvvvvvvvvvv rrrr
rrrrrr vvvvvvvvvvvvvvvvvvvvvv rrrrrr
rrrrrrrr vvvvvvvvvvvvvvvvvv rrrrrrrr
rrrrrrrrrr vvvvvvvvvvvvvv rrrrrrrrrr
rrrrrrrrrrrr vvvvvvvvvv rrrrrrrrrrrr
rrrrrrrrrrrrrr vvvvvv rrrrrrrrrrrrrr
rrrrrrrrrrrrrrrr vv rrrrrrrrrrrrrrrr
INSTRUCTION SETS WANT TO BE FREE
[ 0.000000] Linux version 4.6.2-gb370a4b (email@example.com) (gcc version 6.1.0 (GCC) ) #27 Tue Mar 7 10:29:24 CET 2017
[ 0.000000] Available physical memory: 122MB
[ 0.000000] Initial ramdisk at: 0xffffffff800172c0 (759029 bytes)
[ 0.000000] Zone ranges:
You can continue with working on Linux by mounting SD Card as it is described here.
Remarks on Programming
It is important to understand that the Zedboard consists of two parts; ARM Processing System (PS) and Programmable Logic (PL). Programming only the PL with the lowRISC implementation is not enough since the implementation depends on PS for the clock, reset and the memory controller; therefore, the PL needs PS to be initialised. To solve this problem,
make program initialises the PS using a pre-set file
$TOP/fpga/board/zed/helperscript/ps7_init.tcl. This file is an SDK generated file for its the default Hello World application project. Of course, one may prefer to run his/her own code on ARM instead of just initialising it, and program the PS according to. In such a case, it is possible to program both the PL and PS using SDK either at design-time, or automatically from SD card (not from the PMOD, but Zedboard’s built-in socket) at power-on.