USB ACM FIFO and RISCV core demo


I’ve managed to split the USB ACM device into a standalone Verilog module with a simple FIFO interface for reuse. I also separated the physical layer into a 48 MHz clock domain and have clock-crossing logic to interface with slower logic for the USB endpoints. This works on the iCE40lp8k as well as the smaller, slower FPGAs like the up5k in the Tomu:

As a test case, I’ve replaced the icicle RISCV serial UART with the ACM device so that the softcore on the TinyFPGA BX can communicate with the /dev/ttyACM device on the host machine it is plugged into (no more FTDI cables!):

Bootloader resources

Very impressive. I mentioned you work on this thread - USB Communication. It is geat to see that you have made so much progress with the TinyFPGA version.

Several of us have had USB communication over /dev/ttyACM0 with a uart-like interface working for a while but without your separation of clock domains. Your implementation looks as if it will be a lot more reliable.

I have also been working on a Risc-V application that uses our version but mine uses Clifford Wolf’s picorv32 and picoSoC rather than icicle.

What I have been doing is a proof-of-concept of programming the TinyFPGA using the Arduino IDE, based on work by @uXe and others on the mystorm BlackIce device - see

So the uart I have replaced is Clifford’s simpleuart that is used with PicoSoc. I have the system mostly running but receiving data is not quite working yet - see



thanks for sharing. This is really awesome work.



I am trying to compile/run the code that can be found in the repository. but it ain’t fully working for me

So far I made a few changes to get the code compiling

  • In the makefile I replace the compiler from iscv64-unknown-elf to riscv32-unknown-elf
  • In the makefile I replace the default target to be tinyfpga-bx
  • In current version of icestorm (git) I am getting a crash on pcf files that contain the -nowarn flag. (I removed them) but might post a patch to icestorm.
  • make flash does’t work as it tries to use dfu hence I used tinyprop -p top.bin

I am now stuck in the program compilation

(.text+0x4): relocation truncated to fit: R_RISCV_PCREL_LO12_I against `.L0 ’


I just tried it and did not get the -nowarn problem, but hit the same issue as you.

I did:

git clone -b tinyfpga
cd iclicle

I replaced the TARGET variable in the Makefile with:

TARGET = /opt/riscv/bin/riscv64-unknown-elf

As I had the riscv64 version of the compiler in /opt/riscv because I have run icicle before on the BlackIce II board and had built the risc64 version of the compler for that. I have both the risc32i and risc64 versions installed.

I then ran:

make BOARD=tinyfpga-bx

and got the (.text+0x4): relocation truncated to fit: R_RISCV_PCREL_LO12_I against `.L0 ’ error.

Looks like this issue -


Indeed. (changing the load address does remove this issue)
a temporary fix is therefore probably to change the load address (and also on flash to) 0x00000008
and manually insert nop (0x13 00 00 00 , 0x13 00 00 00) at the start of the file

When I just change the load address things start to look good … I am getting world# out of the serial


When I accidentally got the BOARD parameter wrong, I did not get that error, so it worked for the default board. The relevant difference is that the ice40hx8k-b-evn board has PROGMEM = flash, so I wonder if the flash version needs changing.

It is working for me now, but what has happened to “Hello, w”?


If I add some spaces to to

uart_puts(" Hello, world!\r\n");

I start getting

!Helmo, worle!

So there seems to be something wrong with the USB output.


The USB stack seems quite stable in other applications (like my 16x2 character OLED video display and the Tomu USB bootloader), but I also see weirdness like that from the icicle core that makes me wonder if there is something wrong in the CPU logic.

If I replace uart_puts() with a series of uart_putc() calls, it does the right thing and outputs the full string. There are also some oddities on more complex test programs that make function calls; functions that are inlined seem correct, but jumps don’t always go right.


FPGAs seem to be Rick-rolling a lot of LED and LCD output devices.:grinning:



I am trying to get this part working and I am coming to the same type of conclusion. It looks like there is something fishy about argument passing to functions. pass by value (e.g. in registers) looks like mostly working but when working with pointers things start to behave strangely after 4 bytes(e.g. one word).

It is also possible that something goes wrong in cache/memory handling.

I did a few experiments and would like to repeat the same experiments on a normal UART but just disabling the USB UART did gave some errors. I have a few variants but for now this examples shows the strange behavior.

The following program reliably display the following(funny enough the compiler flags use -OS but stlll do some inlining.


Here is the basic code. e.g. replacing the 3 loops with a single loop things to wrong.(I also tries some changes like setting -O0 for the compiler.

int main() {
    LEDS = 0xAA;

    char *second="0123456789abcdef";
    for (;;) {

        int f=0;
        for (int x =0 ; x < 16;x++) {
            uart_putc(second[f + x]);

        for (int x =0 ; x < 4;x++) {
        for (int x =4 ; x < 8;x++) {
        for (int x =8 ; x < 12;x++) {

        for (int x =11 ; x >= 0;x--) {


        uint32_t start = rdcycle();
        while ((rdcycle() - start) <= FREQ);