This tutorial will show how to implement a system including a RISC-V processor on Lattice MachCO3 FPGA. We will use a MachXO3L Starter Kit board from Lattice.
MachXO3L is Latticeās newest instant-on, non-volatile, small footprint FPGAs that use advanced packaging technology to enable the lowest cost devices. The family features the latest in small packaging, low-power, and aggressive cost combined with fast performance.
We will use Lattice Diamond for to build the output from Instant SoC. The VHDL file generated by Instant SoC will be used as “Top-Level” in the design. The system will use one UART displaying a startup message and the LEDs will show the bits of a counting value. The tutorial will be a good starting point for your own project using MachXO3 and Instant SoC.
Make sure Instant SoC and Lattice Diamond are installed properly.
Start Instant SoC and select a directory. Make sure to check the “create a example cpp file” option. Press the “Setup Project Folder” to create the project files.
Start Visual Studio Code and open the folder you created. Open the “example.cpp” file and change the timer interval from 1 us to 100 ms. We also change the name on the output from “counter” to “led”.
The clk input on the board is 12 MHz so we need the change the “clk” constructor argument to 12. The C++ code will then look like the following.
#include "fc_io.h" #include "fc_system.h" int main() { //% hw_begin FC_IO_Clk clk(12); FC_IO_Out led(8); FC_System_Timer timer; //% hw_end int counter_value = 0; timer.Start(100, TU_ms); for (;;) { timer.WaitTimer(); led = counter_value++; } }
Build it with “Ctrl+Shift+B”. A couple of files are now generated, e.g. example.vhd. This VHDL file contains a RISC-V processor with memories and code to execute the C++ code above. If you prefer Verilog a Verilog header is also created.
Start Diamond and create a project. Select the LCMXO3L-6900C-5BG256C device. Add the “example.vhd” file from the Instant SoC project directory. In the “Process” view check “Export files, Bitsream files”. Build the project.
Open the “Spreadsheet view” to set the io locations. Set the led(0):led(7) to : H11, J13, J11, L12, K11, L13, N15, P16
Set clk signal to C8.
Build the project and download the bit-stream file to the board. You will now see the led counting with the led(0) changing with an interval of 100 ms, led(1) 200 ms and so on.
Add an UART to the system
We will now show how easy it is to add peripherals to the system, in this case an UART. Open the example.cpp file and add a FC_IO_UART_TX object in the hardware definition sector. The hardware definition sector is starting with the “//% hw_begin” and ends with “//% hw_end”. We set the baudrate to 115200 and the out-going hardware FIFO depth to 32 bytes. Any number of peripherals can be added in this way.
Write a startup message to the UART using the stream out operator “<<“. The code will now look like the following:
#include "fc_io.h" #include "fc_system.h" int main() { //% hw_begin FC_IO_Clk clk(12); FC_IO_Out led(8); FC_IO_UART_TX tx(115200,32); FC_System_Timer timer; //% hw_end int counter_value = 0; tx << "RISC-V now running on MachXO3"; timer.Start(10, TU_ms); for (;;) { timer.WaitTimer(); led = counter_value++; } }
Build the Instant SoC system to update the VHDL file. The port now includes a tx out signal. Set a suitable location for this signal in Diamond spreadsheet view. You could look at the signal using an oscilloscope or connect it to a logic level UART receiver.
Note that the component generated by Instant SoC does not have to be a top-level component. It can be used as any other VHDL or Verilog components. Since the resulting code is very optimized you can often include several Instant SoC components in one design.