Arduboy clone on RISC-V/FPGA

ooooh. Noice! How often do you commit the writes? From my understanding of the Arduino EEPROM - the writes are “immediate write-back” – which makes sense for in the integrated EEPROM. However for nand-flash (you case - SD card) or nor-flash (my case - typical w25 series chip), the writes are much costlier.

I saw that in ESPBoy, the writes are specifically committed (esp EEPROM lib has a commit()). The author inserted such code in the games itself, after a sequence of EEPROM modifications (say new entry in the scoreboard or something).

I don’t want to do that. Preliminary idea - I am thinking of caching and auto committing the writes every second. I’d have the entire 1K of the “eeprom” in ram anway - so, I’ll just the changes once in a while, if any.

In my system (which has a generous 128KB ram), the games are warm-loaded. The Loader is the main app from which the user picks a game to play, and then the loader copies over the game to a specific bounded region of the ram - and then jumps to it.

Hence as a second idea, I am thinking of a “start” button which suspends the game and returns to the Loader. At which point the gamer can chose to commit the “save” to memory. And other options - close game, resume, etc.

Thoughts?

I have given the problem of saving files on flash some thought, and slept on this idea. FPGA boards almost always use a typical W25 series SPI NOR Flash. The iCEBreaker fpga board that I am using has a generous 16MB W25Q128JV.

I am leaning towards something dead simple like a copy-on-write circular buffer in the flash. The savegames are fixed 1KB, as @Pharap said – since it’s what the size of the EEPROM is. I am thinking of a scheme where the savegame, if modified is written back (committed) to the flash at most once every second.

Assume, each “file” takes up one 4KB block (min erase sector on a typical w25-series spi nor flash = 4KB). A certain number of blocks forms the “filesystem” (FS). When starting the game, I’d O(N) search the blocks for its savegame and load it into the ram. No index block required (as you’d expect in CoW or for that matter, most FS), and the search cost is no biggie.

As the game runs, the savegame in the ram is modified. If the savegame remains modified for some time – indicating it is stable, it is copied and a write-back starts. I will search for the next free block starting from the current location in the circular buffer, write the new savegame into the free block, and issue an erase for the current one.

The find (block allocation), write (0.7~3ms per page of 256B) and erase sequence (45~400ms) would be sequenced across game-frames or soft-timers and would thus be non-blocking (and totally handled in the background). Since, I only need to write-back at most once per second, the sequence would be done and the flash would be ready for a new write. Usually, we’d not expect to write back that often.

I think this would be the cheapest code solution for the job. Very application specific, and I get wear-levelling. Power-off resilience can be ensured with some metadata and atomic sequence of the write+erase op (maybe? – need to think about this more). I’d need some code to check the blocks upon boot and ensure the bad blocks (half erased/half written) are cleared out, i.e. some garbage collection. That’s a stretch goal though, I am not strongly aiming for power-resilience. But, overall, this would be cheap.

I can do things a little smarter by committing 3 full writes (256B header + 3 x 1KB data) to the same 4KB block before moving onto a different block and issuing an erase. A bit mask in the header can keep this status. When moving to a new block, the header has to be copied over and started fresh. The important part is that a savegame uses the whole block (4KB) and does not share. In this scheme I can mess with the logical block size to decrease the overhead of the header – though at the cost of erase time (of physical blocks – for example 32KB erase takes 120ms~1.6s). This scheme is a hybrid CoW + Logging FS.

However, if I were to chose a real FS – littleFS is seriously looking to be the best choice. Very informative presentation - https://www.youtube.com/watch?v=ogdqeaO-83s - from the author of littleFS.

EDIT: I approached this wrong. I should spin this - Flash cart(ridge)

So, I re-ported Arduboy2. It feels much cleaner this time around - project.

SiNe-DeMo (with learnings from the Arduboy_MiSTer thread. Default sin with doubles was slow as you folks already figured out.

Sorry for the lame duck questions, but: How open is the MiSTer? Can it be cloned/forked?

Curious about spinning up a dedicated arduboy / mister compatible board?

@uXe built the Arduboy core for MiSTer.

Afaik, it is FOSS - https://misteraddons.com/

Edit: The FPGA board I am using to run my RISC-V SoC is the iCEBreaker. It uses the small Lattice ice40up5k - an FPGA with 5280 LUTS. The same FPGA also comes in a salt grain sized 2.1 x 2.45 mm wlcsp package (as used in FOMU). And SPI flash also come in super small packages (uson-8 or wson-8 or even wlcsp). Imagine the possibilities.

I remember @uxe telling me it comes super small. Generally the moq for fab shops that have those processes is sorta high.

Development prototype looking good. This should be more than enough to build and test the entire software stack. Thru-hole tactile buttons are prickly. So, I guess on the next version of this board, I’ll switch out to the nice ones on the Arduboy Mini. And, reverse the order of the buttons (A, B).

6 Likes

Hey that was quick nice job!

1 Like

That addon really gives me more of an idea to make the sheild version. I mean, you’ve done it… just for this fpga.

It would be cool to have it be a multitool so it also has breakouts for a pro micro or even the standard arduino risers…

I’m inspired!

What’s the transistor for, are you driving the peizo?

I am thinking of making another version in adafruit feather form factor to work with the OrangeCrab, Or this exciting compact icebreaker-bitsy – which is the icebreaker in a bitsy form factor. Prolly just the later as a nice “shield” - with BMS this time.

Yeah, the transistor is for the piezo, like this (R1=R2=1K):
image

Sweeeet. 100% possible. The PCB will be riddled with holes though…

PS: Silkscreen on the back
image

5 Likes

Could do it with just test pads instead of through holes, so you just solder directly to the board. Or surface mount headers too.

Too good :slight_smile: I like alot

1 Like

SMD connectors. I can see it. But, won’t the stress on the pads be high when inserting/removing main boards?

On a side note, apparently the icebreaker-bitsy (teensy form factor) can expand to a feather using this neat Adafruit teensy-to-feather adaptor. Should work any teensy as originally intended as well. So, perhaps a “wing” is the common denominator.