BX portable game console | project collaboration


#21

Awesome!!! I’ll have to see if I can track down some nunchucks from somewhere too.

I’d love to be able to say I’ve been as productive as you appear to have been, but unfortunately I’ve been chasing my tail a little today… I haven’t had much luck getting PicoSoC to work. For whatever reason it just doesn’t want to boot for me. I’ve pared it right back to the basics; just a simple LED peripheral now, but still no luck.

As you can see, I’m deep enough down the rabbit hole that I’ve soldered a header on to the flash SPI test points and hooked it up to a logic analyser to see if that would help me understand what’s going on… Unfortunately, as I sort of suspected, it doesn’t appear to be sending any requests to the flash chip after the initial FPGA boot :frowning:

I think perhaps a cup of tea and some deep reflection is required :coffee:


#22

I did not have any problem getting it working. Do you have the right variant of the riscv32i toolchain? What OS are you running on? I had already used BlackSoc, so I had the toochain built.


#23

I’m using a linux VM for development, and I used Clifford’s project to install all of the variants of the toolchain under /opt:

$ ls /opt/
riscv32i  riscv32ic  riscv32im  riscv32imc

I’m using the riscv32i arch at the moment because I’ve got the mul/div and compressed ISA flags turned off in the CPU. Maybe I’ve accidentally turned off something else that I shouldn’t have :slight_smile:

ETA: I just tried synthesising a full-spec CPU, still no luck.

D.


#24

I only built the riscv32i variant and use that. Did you start by using the example in the TinyFPGA BX repository, unchanged?

I used that and then modified it to put the console code back using a USB uart connected to pin1.


#25

Yep - the TinyFPGA repo was the prototype I used. I think tomorrow I’ll go right back to basics - re-check out Luke’s repo and go from there.

Interestingly I thought I might have just found something. The reference card that comes with TinyFPGA has SPI_SS listed as being on FPGA pin F8; whereas in pins.pcf, it’s F7. That said, I checked the schematic, and it looks like it’s maybe just the reference card that’s wrong.


#26

Anyway, it is nice SPI programmer/debugger that you have there :grinning:


#27

For what it’s worth, I was able to get the PicoSoC from the TinyFPGA BX repo working using only the stock MacOS binaries for the 64-bit RISC-V toolchain, available from the RISC-V org.

I did have to modify the Makefile to specify both the architecture and ABI when compiling with “riscv64-unknown-elf-gcc -march=rv32imc -mabi=ilp32”. I was then able to remove the compressed ISA by changing only the gcc commandline to “-march=rv32im -mabi=ilp32” – no separate version of the toolchain required. I verified that the resulting firmware was always using large (4-byte) opcodes by disassembling with “riscv64-unknown-elf-objdump -S firmware.elf” and the LED blink firmware works fine when I synthesize a stripped-down SoC:

picorv32 #(
.STACKADDR(STACKADDR),
.PROGADDR_RESET(PROGADDR_RESET),
.PROGADDR_IRQ(PROGADDR_IRQ),
.BARREL_SHIFTER(0),
.COMPRESSED_ISA(0),
.ENABLE_MUL(0),
.ENABLE_DIV(0),
.ENABLE_IRQ(1),
.ENABLE_IRQ_QREGS(1)
) cpu (

I was able to strip things down further, removing IRQ support from the SoC, if I comment out the set_irq_mask call from firmware.c. (If I don’t comment it out, the IRQ mask opcode will cause the SoC CPU to crash when there is no IRQ support in the CPU.)


#28

I just successfully built the firmware for riscv32i in a Debian Stretch VM, using the prebuilt RISC-V cross compilation toolchain from Debian. No custom toolchain build required. Here is how I did it.

First, edit /etc/apt/sources.list and add the following line at the bottom:

deb http://ftp.us.debian.org/debian/ unstable main

Then you can install the RISC-V toolchain as follows:

sudo apt update
sudo apt-get install gcc-riscv64-linux-gnu

Now clone the TinyFPGA BX repo, and in TinyFPGA-BX/examples/picosoc do this:

riscv64-linux-gnu-gcc -march=rv32i -mabi=ilp32 -ffreestanding -c start.S firmware.c
riscv64-linux-gnu-ld -melf32lriscv_ilp32 -Bstatic -T sections.lds --strip-debug start.o firmware.o -o firmware.elf
riscv64-linux-gnu-objcopy -O binary firmware.elf firmware.bin

Then building hardware.bin with yosys / arachne-pnr / icepack as normal, I programmed the FPGA with tinyprog -p hardware.bin -u firmware.bin.

Maybe this helps @gundy get things working, although the problem may not be the toolchain. However, I thought I’d document the steps here for anyone else trying to get the PicoSoC running.


#29

Thanks everyone for your help. The cuppa, the reflection, and going back to basics seems to have helped. I’ve got a basic PicoSoc running now.

Current problem: Interrupts only seem to fire once for me, and then the CPU stops working. I’ll try to figure that one out after lunch.


#30

I’m still going down a rabbit hole here…

I’ve pulled everything remotely superfluous out of my IRQ handler, which is now in pure assembly and doesn’t even save anything to the stack:

This works fine:

irq_vec:
    picorv32_retirq_insn()

This doesn’t:

irq_vec:
    // backup x10/x11 in q2/3
    picorv32_setq_insn(q2, x10)
    picorv32_setq_insn(q3, x11)

    // modify X10/X11
    addi x10, zero, 0
    addi x11, zero, 0

    // restore x10 and x11 from Q registers
    picorv32_getq_insn(x10, q2)
    picorv32_getq_insn(x11, q3)

    // return from IRQ
    picorv32_retirq_insn()

I’ve got the ENABLE_IRQ_QREGS flag set to one (which should mean that the Q registers are enabled), so I’m at a bit of a loss as to what might be happening.


#31

OMG! I found it!!!

In picosoc.v the register file definition only supports 32 registers, and picorv32 attempts to store q0-q3 at indexes 32-35.

Notice the below code takes a 6-bit address, but only defines 32 addresses, and truncates the address lines to 5-bits when reading/writing the register memory.

module picosoc_regs (
    input clk, wen,
    input [5:0] waddr,
    input [5:0] raddr1,    
    input [5:0] raddr2,
    input [31:0] wdata,
    output [31:0] rdata1,
    output [31:0] rdata2
);

reg [31:0] regs [0:31];
always @(posedge clk)
    if (wen) regs[waddr[4:0]] <= wdata;

    assign rdata1 = regs[raddr1[4:0]];
    assign rdata2 = regs[raddr2[4:0]];
endmodule

Duh.

Another cuppa for me, and then back to work I suppose. :slight_smile:


#32

Do you have your draft driver on github or anywhere available?

I am considering a sort of mini-Gameboy with a 128x128 Oled SPI color display:

It would have a socket for the TinyFPGA and a battery on the other side of the PCB, and probably a battery charger.


#33

I’ve put it here: https://github.com/Fabien-Chouteau/tinyfpga-bx-game-soc/blob/develop/hdl/picosoc/video/ili9341.vh

Don’t know if it will be useful to you since I used a different screen and a parallel interface.


#34

Thanks. I thought I would look at the parallel interface as well, as it is faster than SPI. So I will probably buy the same screen you have. I have already bought one of the SPI 4-pin variants, so eventually I can try both, plus the Oled screens.


#35

I have started another variant of this project which is slightly different to @gundy’s.

I have not used the .vh include files, as I am not keen on them, so I have selected the files to build using Makefiles. I started again with Luke’s picosoc examplle, so I have got all of Dave’s restructuring. I have not attempted top do timer interrupts, so haven’t hit the problems associated with that.

I added a memory location 0x20000004 for button input, currently with up to 8 buttons. I plan to debounce in software.

I also added memory locations 0x70000000 and 0x70000004 for i2cwrite and read for Wii Nunchuks.

There are currently 4 examples:

  • uart output
  • button input
  • audio output
  • nunchuk input

There is a single audio pin with the pdm_dac, which you need to drive from software. It current just outputs a tone using a square wave.

I am currently working on the nunchuk input.

I then need to add some display output. I was planning to start with my 128x128 SPI Oled screen.


#36

Here is my test rig for the SoC:

The Nunchuk is now working and I am making progress on the SSD1351 SPI driver for the 128x128 OLED display.

The Nunchuk needs proper driving software though. I have currently just shown that I can get data from it. Similarly the audio needs some sort of software driver and the buttons need a debouncer.

I am beginning to think we will need two TinyFPGAs for a useful game console as I cannot see us getting a good GPU and audio synth in the same device as all the other stuff.


#37

I am beginning to think we will need two TinyFPGAs for a useful game console as I cannot see us getting a good GPU and audio synth in the same device as all the other stuff.

C’mon!!! We can do it!!! I’ve accepted now that my initial specs for the audio side of things may have been a bit too ambitious, so I’m now working on culling features that can be handled in code. A good example is the envelope generators - they were quite complicated, and could easily be replaced with a simple “volume” register per channel that can be driven by the CPU in a player routine.

I guess with the GPU there could be a few complications:

  • dealing with multiple clock domains (unless we can run the whole thing off the GPU clock)
  • single writer, multiple readers of video RAM

Figuring out how to multiplex CPU and GPU access to the video memory without wasting BRAM blocks could be fun. Maybe we could give the CPU the ability to read/write VRAM during vertical/horizontal refresh? or temporarily disable the GPU/blank the screen to enable updates?

Then again, maybe some of this has been solved already?


#38

Part of the issue is that I seem to be able to fit in quite a lot less on the TinyFPGA PicoSoC than I can on BlackSoC. I think that is because BlacKSoC and icoSoC use SRAM rather than flash memory and that takes a lot less Verilog code to drive.


#39

I have the VGA version working now with a Nunchuk. I am currently working on the OLED screen version.

The VGA version only just fits and arachne-pnr often fails to route. The API is a bit deficient as all I can do is move a single sprite around the tiled 2D screen. I could probably fit in 4 16x16 sprites. Setting the sprite position appears to work, despite crossing clock boundaries.

I could probably do a Pacman game.


#40

I’m going to see if I can find myself a nunchuck today…

I’ve got a few basic things up and working now… and so far everything seems to fit relatively easily (although there are still lots of things missing).

What I’ve got (sort of) working here:

  • 4 channel audio (with volume register replacing the ADSR envelope generator)
  • 320x240 VGA video - 40x25 window into 64x64 tile map of 8x8 textures (no sprites)
  • timer (using the built-in PicoSoc timer)
  • IRQ driven audio routine to play a song (same one from the other demo)

I took a slightly different approach with the video. I IO mapped tile and texture memory, so the CPU can write to them (although it can’t read). The only reader is the video output rasterer. This means I can use the SB RAM blocks pretty much as-is - they even support separate read/write clocks which is handy.

In fact, removing the “read” access to the GPIO/audio/video side of things is what probably saved me the most gates so far. It seems that shipping all of those 32-bit chunks of data around eats into the wire/routing budget.

After lunch I’m planning on adding sprite support, and then once I get hold of a nunchuck I’ll add in I2C support, and that should be enough to allow me to start focussing on some of the higher level stuff (eg. decent audio player routine; song editor; better example projects & documentation). :slight_smile:

D.