Saturday, April 26, 2014

Running ZPU Softcore on Lattice ICE40

So I got my hands on a new FPGA development board, a Lattice ICE40HX8K eval kit, this is a really basic low-cost board/breakout with a few LEDS, EEPROM and a dual FTDI2232H UART/FIFO, that you can use for programming the EEPROM/FPGA...What I really love about this board, other than the low cost and many I/Os, is that the second FTDI port is configured as a serial port and connected to the FPGA, so basically you get a free USB<->USART bridge which you can use to talk to the FPGA with the same USB cable used for programming (see Linux notes) that's basically all I need as I'm already familiar with FPGAs...
I wanted to evaluate those FPGAs for a new project I'm working on, which will most likely require a minimal SoC with a wishbone bus... My first thoughts was to use my uMIPS core, but it doesn't support the wishbone bus (I might fix that later) so I decided to give the ZPU core a shot, which was definitely worth the time it took to get it working on the Lattice FPGA.

In an effort to save someone else's time, I created this github repo for the project, it has the sw, hdl, project files and a tested bitmap file, all you need to do is to program the bitmap (or synthesis the project with iCEcube2 if you want), open /dev/ttyUSB1, set it to 8N1, 9600, parity=none and reset the core (you will need and external switch for that, connect it between H16 and GND), it should print out "Hello World!"...

ZPU Core:
The ZPU is small 32-bit stack-based CPU, it comes with a gcc-toolchain, lots of variants and examples... For this project I used the zealot/medium variant which comes with a physical I/O layer (provides a USART, GPIO and a timer) and I'm using a single port RAM, no PLLs (to keep things simple) and all the RAM blocks on the ICE40HX8K (16KBs total) for the program image. There's no wishbone yet, I will work on that next.

Compiling Stuff:
First It's worth mentioning here that I modified the I/O memory map (crt_io.c) since there's only 16KBytes of on-chip ram, I modified it to use bit 15 for the I/O space, the modified crt_io.c is included in the repo and the Makefile will compile and link this modified map for you.

If you want to compile a new program, you'll need to download the ZPU toolchain first and use the Makefile in zpu/sw it will generate a bunch of files, the one we're interested in is hello.bram, this contains the instructions/data used to initialize the embedded RAM, copy the contents of this file and replace the one in bram.vhdl.

Linux notes:
I didn't have much trouble getting the software running on Linux, but one thing you might want to do to make things nicer, is to use this udev rule to unbind ftdio-sio from the first FTDI port when the board is connected, this will allow the programmer to use the first port as JTAG with the second (USART) port bound to ftdi-sio at the same time, so you can use it as to talk to the FPGA after programming:

BUS=="usb",ACTION=="add",SYSFS{idVendor}=="0403",SYSFS{idProduct}=="6010",MODE=="0660"
,GROUP=="plugdev",SYMLINK+="ftdi-0"
SUBSYSTEM=="usb",DRIVER=="ftdi_sio",ATTRS{idVendor}=="0403",SYSFS{idProduct}=="6010"
,ATTR{bInterfaceNumber}=="00",RUN+="/bin/sh -c 'echo `basename %p` >/sys/bus/usb/drivers/ftdi_sio/unbind'"

The following is the iCEcube report for this design:

Total Logic Cells: 3099/7680
Combinational Logic Cells: 2471     out of   7680      32.1745%
Sequential Logic Cells:    628      out of   7680      8.17708%
Logic Tiles:               473      out of   960       49.2708%
Registers: 
Logic Registers:           628      out of   7680      8.17708%
IO Registers:              0        out of   1280      0
Block RAMs:                32       out of   32        100%
Pins:
Input Pins:                3        out of   206       1.45631%
Output Pins:               9        out of   206       4.36893%
InOut Pins:                0        out of   206       0%
Global Buffers:            6        out of   8         75%
PLLs:                      0        out of   2         0%

Read more ...