tinyfpga prog was originally written for another ice40 family that has much faster fabric than the UP5k used in the icebreaker and as such it actually doesn’t meet timings, among the other issues it has … At some point I did manage to get it recognized with some hacking, but questionable stability.
The code in riscv_usb is similar to what you would find in a classic microcontroller with USB. There is a dedicated hardware USB block that handles the low layers of USB (so it’s not bit-banged or anything like that, it’s a true hardware USB to meet all the critical timings of USB), but the higher level of the USB stack are running on a riscv CPU. (eventually I’d like to get it running on a smaller cpu than a risc-v, it’s WiP). tinyprog is “all hardware” but it also doesn’t pass the USB compliance tests at all, while here I was aiming for full compliance with the spec for maximum compatibility.
However the way it’s designed to work is to have a separate “boot loader” bitstream in flash that’s triggered for instance when a given button is pressed at bootup. So the way I did it so far is to have the default bitstream be a very simple one that just looks at the button state to decide what bitstream to boot ( https://github.com/smunaut/ice40-playground/tree/usb/projects/boot_stub ). Then depending on that it will either boot the “bootloader” bitstream, or the “application” bitstream. Then in the application bitstream itself, if it’s a “usb-based bitstream”, include DFU descriptors there to allow reboot from application to bootloader, or if the application bitstream doesn’t use USB at all, just include a small helper that reboots into bootloader mode when a button is pressed for a long time for instance ( https://github.com/smunaut/ice40-playground/blob/usb/projects/riscv_usb/rtl/dfu_helper.v ).
On the PC side the way it would look (assuming your application bitstream has no USB support at all), well when you plug the board, by default it doesn’t do anything. But if you power it while pressing the button, then it boot in DFU mode and shows up as a normal DFU device to your PC where you can use dfu-util to upload a bitstream. Or you can also press that button for X seconds and it would also reboot in that mode. So to upload a new bitstream you’d need to do either of those to get it to show up on the PC, and then use dfu-util to load the new bitstream and reboot in application mode.
I don’t use APIO but it looks like it has DFU support and so you’d probably just need to add an entry for your board in the boards.json file and then upload from APIO should work. Althouh you’ll need to manually get the board to DFU mode first. (unless your application bitstream has USB support itself and can accept the command to reboot to DFU programatically).
Does that make sense ?