PicoSoC using only BRAM


#1

In order to produce a menu system for the tiny-fpga-game-soc, I have produced a version of PicoSoC for the TinyFPGA BX that runs code from BRAMs and does not use the flash memory.

This should be usable for more than just the game menu application.

The picorv32 Risc-V CPU uses 4 BRAMs for its registers etc., leaving 28 BRAMs (14kB) for use for code, data, heap and stack.

Like tiny-fpga-game-soc, the C code for the SoC is in Arduino-style libraries, and there are currently libraries for:

  • Direct access to the ili9341 LCD
  • Read and write the SD card on the back of the LCD
  • Read and write access to the flash memory
  • Buttons via GPIO pins
  • Uart for debugging
  • i2c access to Nintendo controllers (including Nunchuks)
  • Millisecond delay function

The audio and video libraries used by the Game SoC will not work on this SoC because they need BRAMs or timer interrupts, but a simpler audio system would be possible.

Access to the LCD screen is directly from code sending commands and data using the ili9341 protocol, using the 8-bit parallel 8080 interface. Currently I use the default small font from the Adafruit GFX library to write character data to the screen, but graphics is also possible. I implemented a fast flood-fill mode for clearing the screen, which was otherwise rather slow.

This SoC will run on the PCB that @Fabien has built, but SD card access will not work on that as it does not include the wiring for the SD card.

The main purpose of this Soc was to produce a menu system for the Game SoC.

The menu application does the following:

  • Reads the root directory of a FAT32 SD card and displays the contents as a menu on the LCD screen
  • Each file in the root directory is assumed to be a game (or other) application with the hardware.bin and firmware.bin files for the application concatenated.
  • The Select button is used to select a game, and start is pressed to start it
  • The file is then read from the SD card and the hardware.bin and firmware.bin portions written to the TinyFPGA BX flash memory
  • A warm boot is then done

This starts the game application.

Unfortunately after running the game, the menu has been wiped from the flash memory and replaced with the game. To leave the menu in flash, I will need to reconfigure the TinyFPGA BX to support 3 configurations rather than the current 2 in its multi-boot configuration. I will need @lukevalenty’s help with that.

But as I said, the RAM-only SoC is usable for more than just this game menu. It runs much faster than versions of PicoSoC that use flash memory.

I have not quite finished the game menu yet, but all the features of the SoC are working.


#2

Wow! Sensational! :slight_smile:

I’m excited now, waiting for the kit from Fabien to arrive so we can start playing with it… and although the SD card may not be wired up, I’m sure it’s only a few lengths of strategic kynar wire and some careful soldering away :wink:

I’m curious about this - how much slower is it? Also, given the fact that you’ve removed a ton of really “heavy” stuff - ie. the graphics/sprite code, do you think we’d be able to clock the CPU faster (enough faster) to compensate? If we use the CPU we can probably use more tricks like only repainting dirty areas of the screen rather than brute-forcing things… This may not be all that effective for games where the whole screen scrolls, although even then the ILI9341 supports some level of hardware scrolling too, doesn’t it?

This has me wondering… for performance critical bits of code (eg. interrupt handlers; chasing the raster in games) I wonder if we could copy the code into a RAM buffer, and then jump to / execute from RAM instead of flash …

Anyway, this is sensational work and makes me very happy :). … great to see…

AsterGateroids is still progressing along… I’ve got the home screen designed, and have done most of the graphics now… although I’ve been a bit distracted building a controleo reflow oven for the last few days…

I’d like to add support for “bullet” ‘sprites’ - essentially just x,y locations on the screen to draw a white dot - so I can have both a decent number of bullets, and asteroid sprites, and the player sprite, all in action at the same time… the current 8 sprites seems like it’ll be a bit limiting.

D.


#3

Yes, I was wondering about that too. It was originally very much slower for writing a whole screen (the initial clear screen). But I was running it on the flash memory version with a loop to write 320 x 240 16-bit pixels to the screen. From flash memory, this was very slow as any jump has to re-read the flash memory and that slows things down a lot. It was clearing the screen in about one second, so about 50 times slower. I added a fast xfer mode to write the same pixel multiple times to consecutive locations, and that fixed the problem. You now cannot see the clear screen.

However, I did not test that on the RAM version where jumps are not a problem. I suspect it would be very much faster on that, But doing 320 x 240 x 2 8-bits writes is going to take time even in assembler.

But as you say, we could optimise screen writing, use hardware scrolling and increase the CPU speed. I suspect we can double the CPU to about 32Mhz, but I am not sure it will go much faster than that.

Custom op codes might help as well.


#4

The latest version of this code is a working menu, but it only writes the hardware.bin file to the flash memory, and then reboots. To deal with picorv32 games, I need to write firmware.bin to address 0x50000 as well. I think I will concatenate hardware.bin and firmware.bin with 68 bytes of padding between them to produce the game file binary, as things are simpler if firmware,bin starts on a 512 byte boundary.

Or alternatively, if I put 28kB + 68 bytes padding between hardware.bin and firmware.bin, I could write the whole file to 0x28000 and the current code would work unchanged.

I still have some problems with writing to the LCD screen so you sometimes have to press reset for the menu to appear. That works best when powered by battery.


#5

I think I know how to set a new warm boot configuration now, so that I can keep the menu in flash memory, write the game hardware.bin to a different address and do a warm boot to that. In the first 0xa0 bytes of the flash memory is a table with 5 32-byte entries, the first for the power-on image and 4 for warm boot images. Three bytes in the table specifies the address of the bitstream. The multiboot.bin file for the BX in the Bootloader respository has all entries other than the third set to load the bootloader at address 0x0000a0. The third entry (second warm boot) has the user image address 0x28000.

There is a an icestorm utility, icemulti, which will create such a multi-boot file.

So to modify the entry to set a new warm boot configuration, I could read the first 4kb of the flash memory, erase it, modify the 3-byte address and write it back. However, I would only get one go at getting this right as otherwise I would probably destroy the USB bootloader and (temporarily) brick the device.

So before I do this, I probably need to ensure that I can write a new multiboot image to the BX. To do that, I need access to the SPI pins. I can either solder wires to them like you did when you were debugging SPI memory, or I can buy something like this board. There are then multiple tools that I could use to write the multiboot image to the BX flash memory. I would probably use my spidriver , as that comes with suitable sample code, but an Arduino, Bus Pirate or another BX are all possible. As is Lattice’s own programmer.

Using a BX to program another BX looks fairly simple. If you just take theBootloader and change the pin mappings for SPI, it should do the job, and you should be able to use tinyprog unchanged to do it as it lets you specify a non-standard start address.


#6

The menu is now working with the SD card using Fabien’s PCB. I wired the 4 SPI pins for the SD card to the same pins as the direction buttons (as all 24 easily accessible pins were used), so the menu cannot use those buttons.

The menu is currently a bit fragile as it makes lots of assumptions about the FAT32 file system including 4096 byte clusters and only one FAT sector. That effectively limits it to 2 games and a defragged file system, so I need to support more FAT sectors.

It also currently leaves the selected game in flash memory, so you need to flash the menu again if you want a different game. To fix that I need to do surgery on the multiboot table as described above.

Here is the menu:


#7

:mage: :star_struck: :+1: :bowing_man:

Can’t wait for my kit to arrive :slight_smile:

D.


#8

I now have a menu with 4 games that is “sticky”. That is the menu stays in flash memory and you return to it by pressing the reset button or switching the console off and on.

It relies on you having updated the multiboot menu on the BX as the menu writes the hardware.bin for the game to address 0x78000 and warm boots to that. You can update the multiboot menu using tinyprog without having to solder and wires to your BX, but you only get one go at that, as if you get it wrong or if it fails, you will need to restore the BX via the SPI pins on the underside.

I could implement returning to the menu via a button combination but that will use some PLBs.

I have not updated the metadata for the BX to reflect its new configuration. I could write a tool to do that. I don’t know where the code that @lukevalenty uses to set up the original metadata is.