Tiny-FPGA-BX-Game-SoC Pacman


I did post about those being the wrong way round (on the original topic) :grinning:

Starting up the ili9341 has been a bit hit and miss for me. Sometimes it worked sometimes not. Sometimes the colours were wrong, so it it looked as if the MADCTL command to set BRG had not worked. With any luck your changes have made it more reliable.


There are actually two Adafruit libraries that use different sequences for the ili9341: https://github.com/adafruit/TFTLCD-Library/blob/master/Adafruit_TFTLCD.cpp and https://github.com/adafruit/Adafruit_ILI9341.

I went through that when I was getting the SPI version of the display to work (on BlackSoC). I know @fabien’s sequence was a bit long, but I left it alone as it appeared to be working. It is a black art setting up these initialisation sequences.

I did wonder if we wanted to support switching between the display being driven from the video RAM or directly from the CPU. That way we could have the initialisation in code and possibly save some gates.


Sorry, my reading comprehension obviously needs some work. I just went back and re-read your post - it seems like we both ended up burning a few hours on it, so please accept my sympathy and don’t feel like there are any hard feelings :slight_smile:

The LCD seems to start up quite consistently for me… it was one of those things where after having made the final change that I needed to make to get it working, it just went super smoothly because I’d already gone to such great lengths trying to figure out what might have been happening that I’d pre-discovered all the other potential issues.

I’m at a bit of a loss now though. There’s no way I’m going to be able to get the audio to fit without some adjustment.

Some of that adjustment is going to be made a fair amount easier if I cull the VGA code and clean things up around an LCD-only codebase - for example, there’s a lot more flexibility around exactly how things work if you don’t need to meet an exact pixel-clock.

Secondarily I may need to cull the audio code a bit more. Maybe pare it back to 8-bit (maybe even 6-bit) waveform generators instead of 12; that sort of thing.

I seem to recall Fabien mentioning that he had circuit boards being made for this. Do we have any indication as to what the wiring on those looks like?

… anyway, how do you feel about losing VGA support? Or maybe creating a totally separate driver for VGA that may have more (or fewer) features than the LCD driver?



I could probably do the same for the SD card SPI and save another pin.


I think we should concentrate on the LCD version for now. I have not set up my VGA breadboard to use the Digilent Pmod and support more colours, so I haven’t got that working anyway. I am happy for you to do what you think best. It would be good to get VGA support again sometime as supporting a TV games console as well as a oortable LCD version would be good.

I have not seen the wiring for @fabien’s board. I did wonder about how he was wiring buttons and whether he had or could add support for the SD card.


:grimacing: :man_facepalming:

The second one looks much closer to the original init sequence in the verilog code. I still stand by my statement though that a number of the commands in there aren’t in the official ILI9341 documentation, so it’s a bit of a mystery what they might be doing. :confused:


I have done the first part of the SD card support. I have added an sdcard ifdef and an sdcard example, which reads the root directory from an SD card in the LCD SD card reader.

The next bit is probably harder, as I have to write hardware.bin and firmware.bin for the selected game to the flash memory and configure the Ice40 with hardware.bin. I also need to maker either the menu or the game use a different flash address.


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

That was quick!! Nice one!

The next bit is probably harder, as I have to write hardware.bin and firmware.bin for the selected game to the flash memory and configure the Ice40 with hardware.bin

Based on a quick look at Luke’s bootloader, it looks like there’s a “warmboot” primitive that you need to instantiate, and then bring a “boot” line high in that to get the the FPGA to reload it’s config. Potentially we could expose that “boot” line to the CPU somehow…

Writing the flash may be a little bit tricky given that it’s going to be “in-use” by the CPU when we’re trying to write to it. It may require some sort of a “DMA” system - eg. fill a block RAM, then trigger a block-ram-to-flash copy that’s taken care of by the FPGA, during which the CPU gets stalled or something… anyway, great work, and good luck! :slight_smile:


Oh, Luke can probably add to this, but I wonder if we also need to think about reading and using the same metadata that tinyprog does in order to make sure that we are writing to the correct locations? That’d mean somehow exposing that metadata from the flash to the SoC too…



Yes, I am just looking at this. The Ice40 seems to support 4 configurations but the BX just seems to use two - one for bootloader and one for the user program. It would be useful to use a third one so that the menu system can stay as the user program and not overwrite itself. But I don’t know how the address of the third and fourth configurations in flash memory gets configured.

I am not sure whether it is better to get the menu or the game to use a different flash address for the code. Probably the menu as that is a fixed size, but it means that if the game is not loaded via the menu it cannot use the default -u address, and we would probably need to use the tinyprog -a argument.

Copying with the flash memory being in use does sound a bit tricky.


I have added the capability of direct write to the ili9341 using -Dili9341_direct. This avoids all the tile and sprite code (like oled currently does) and writes directly to the LCD from code. It is useful for text-based applications like the proposed SD card menu.

It is rather fragile at the moment for reasons, I don’t understand. I get a lot of problems on start-up, using the CS pin, and sometimes writing data, but the example works fairly reliably, but rather slowly. I had to add code to clear the screen twice as the first go intermittently clears only part of it.

I changed the startup sequence and timings to those of the Adafruit TFTLCD library, so that does not seem to be my problem.


The menu could look something like this. I could use a bigger and better font.


Here is a working start of the menu program using ili9341 LCD in direct mode. It reads the root directory of a FAT32 card and displays the contents as a game menu.

I still have the difficult bit to do, which is to read the contents of the game (hardware and firmware), write it to the flash memory and execute it.

I have a couple of possible designs for that.

Design 1: Modify spimemio to support writes to the flash memory. That is quite a bit of work as writes are more complicated than reads and need a series of command, e.g. write_enable, sector erase, page program and write disable. So the state machine for that would be quite complex. Then modify picosoc.v to support writing to flash a 512 byte sector at a time. I think it can be done directly from the RAM buffer that the code uses to read sectors from the SD card, as picosoc.v has access to the RAM. It can be told where the sector buffer is by a config register. So the C code would issue a single write to an address in the flash memory, which picosoc.v would interpret that as a sector write and go into a special mode that reads 512 bytes from RAM and writes it to the flash memory at the specified address. The CPU will be stalled until the sector write is finished.

The second design is to produce a variant of picosoc that does not use flash memory but BRAM only. As I am accessing the LCD directory, that uses no BRAM. Picosoc seems to use 12 BRAMs, leaving 20 or 10kb that I could use for code. If I could fit all the code to read the SD card and access the LCD etc. in 10kb, then I could use a simpler design for writing to the flash memory as it would not be in use.

The logic for writing to the flash memory is in python in Luke’s programmer in the bootloader project. The USB to SPI bridge looks as if it is dumb and just passes commands and data across from the python program.

Whichever way I do this it looks hard and risky. it is risky as I can easily write to wrong flash sectors and overwrite the bootloader, metadata or some other flash pages that I don’t know how to restore. So it is an interesting project.

There is a simpler design for a menu of multiple games that uses the same hardware.bin for all of them., but writes the code for each game to different addresses in the flash memory. That would not use the SD card but would only support a small number of games.

Then there is your idea of executing code from the SD card. I think that is hard too, as the commands to access SD cards are a lot different to the commands to access flash memory, even if they both use SPI.


I like this idea… it’s probably the easiest to achieve of all of them too (assuming you can pack the code densely enough). Once you’ve compiled your firmware you could turn it into a .mem file and use the initmem* option for your RAM to embed the firmware into the hardware .bin file.

To help with saving bytes you could always strip out all the IRQ handling stuff from the assembly part of the firmware; you could maybe even cut back on the number of words allocated to RAM since you won’t need to worry about things like a special stack for the IRQ handler etc.

I suspect PicoSoC will run a lot faster out of block RAM rather than serial flash - in some ways it’s a shame we don’t have just a little bit more available :slight_smile: then again, it’s making the most of the limitations we face that makes this interesting :).



Yes, I think I will go with that design. There is code for creating the mem file and using it for a bootloader in icosoc, so I can copy that. I can write the programmer in C using the existing Clifford Wolf spi_master code that I am using the the SD card. I can write the flash programmer code in C, either by transcribing the TinyFPGA code from python or copying a C version, such as icoprog.


The BRAM-only SoC is working, so I am now working on the menu program: