This is an old revision of the document!
GameTank's got games GALORE.
Status: Proposed
Summary
GALORE is project to bring an online cartridge explorer to the GameTank, made possible by a (newly proposed) peripheral to provide the 6502 with FIFO buffer access to the internet.
Hardware Overview
The FujiNet project implements a variety of protocols and user peripherals on vintage computers. It emulates disks, provides network access, and enables crossplay for supported platforms. At its core, it is firmware for the ESP32 with a custom data bus and protocol implemented for each platform.
When it comes to bus protocols, anything goes. The starting point is a microcontroller (RP2040) to serve as arbiter across the physical boundary of the expansion port.
.------. | | ---- |V| ________ | 6502 | ---- |I| ---- \26-pin/ ---- (RP2040) --- [ESP32] | | ---- |A| `------'
The main 6502 communicates through conventional VIA (6522) registers. All processing offloads to the peripheral's ESP32.
Peripheral Architecture
Make use of all VIA pins mapped to the expansion port:
- Pins 11-14, four bits within Register A, as protocol opcode.
- Pins 19-26, eight bits of Register B, as bi-directional data bus.
- Pin 15, VIA CA1, as IRQ attention line from peripheral to CPU.
- Pin 16, VIA CA2, as read-request bit from CPU to peripheral.
- Pin 18, VIA CB2, as write-strobe bit from CPU to peripheral.
Note:
- “CPU” refers to the main 6502 of the GameTank.
- Pin 5 !RESET provides the initial sync between CPU and peripheral.
- Pin 9/10 provide 5V power from the GameTank to the peripheral.
- Without a “peripheral ready” input pin, the CPU polls for status.
The GameTank dedicates 4 pins (0/1/2/7) of VIA Register A to cartridge SPI. Writing the 4-bit opcode requires a round-trip mask (illustrated with informal notation using value `x`):
$280F = ($280F & $87) | ((x & $0F) << 3)
[Footnote] Parallel vs Serial
The peripheral architecture uses parallel data for simplicity. The alternative would be a bit-banged serial line, which would open up pins for multiple peripherals to be connected to the expansion port at once, like a “shield” or “hat.” But this comes with considerable overhead and complication without a clear purpose, especially considering that FujiNet support enables vast potential for expansion at the network level. Should chaining peripherals on the expansion port be of interest, the peripheral architecture here would best support plugins on the other side of the microcontroller arbiter, with opcodes or other FIFO protocol considerations to enable addressing.
Peripheral FIFO
The bus across the physical boundary of the expansion port is a 4-bit opcode with 8-bit data using conventional VIA (6522) handshaking, functionally providing a synchronous client/server request/response system with the CPU as a “client” sending a request to the peripheral acting as a “server” for higher-level functionality (i.e. FujiNet). Data is bidirectional but communication is always initiated by the CPU.
(The opcodes and FujiNet-specific wire protocol are implementation details. Platform bring-up for FujiNet is primarily concerned with how to move bytes in and out of the ESP32, after which there is significant precedence within existing platforms for the various interactions of interest.)
Opcode requirements for platform bring-up:
- Opcode zero is to query status with a conventional, signature “hello” response.
- An operation either has a known response length or the peripheral's response starts with a status byte followed by two bytes indicating a 16-bit data length, followed by the data.
The RP2040 has 264k memory, which supports the full 64k (16-bit) buffer for response data. The response always arrives via interrupt.
[Footnote] Synchronous vs Asynchronous
A variation of this FIFO could support async operation, with the CPU issuing non-blocking requests. The peripheral would immediately respond with a 3-bit descriptor allowing for eight concurrent operations. The interrupt would then include the descriptor in the first byte of the response:
- Most-significant bit of 1 means “error”, else “success”.
- 3-bit descriptor.
- 4-bit opcode echo.
The CPU would then spinlock whenever it needs to block but by default would not have to.
Sync is simpler and therefore the natural choice without a clear motivation otherwise.
Initialization
At reset, both the CPU and the peripheral return to the initial state with the CPU polling (as desired) for a valid status response without having written a request (the one exception to responses always arriving by interrupt).
Reserving opcode zero for status is essential in order to support this state, and the signature “hello” response ensures a peripheral is plugged in (note: there are no pullup/down resistors on the pins). While the signature could be checked in the interrupt, a noisy floating pin could be expensive for a 3.5MHz CPU.
Emulator Support
FujiNet has a “PC” build and the project provides VMs to explore without special hardware. This provides a reference for a project to build support into the GameTank emulator.
Cartridge Explorer
The cartridge explorer is a small program that pulls cartridge metadata from well-known and/or configured internet servers (or offline volumes, etc) and displays an explorer UI, accepting controller input.
The program must support execution from system memory, ultimately without a cartridge, and be able to stay out of the way during program execution, because a game can reasonably assume that it is the only program running. (The explorer could write itself into spare storage on a flash cart and inject a routine to detect a special key input for return-jump to the menu.) At base level, the workflow to explore and download titles requires the user to hotswap cartridges once the explorer program is fully resident in system memory.
Cartridge Flashing
As a console, the GameTank works in coordination with the cartridge, which expands addressable memory, typically with an additional 2MB. Such an execute-in-place mechanism requires that a game explorer downloads a title directly to a reusable flash cart.
In effect, this makes GALORE a software cartridge flashing utility.
Altogether it enables a cartridge uploading workflow as well.
Downloadable File Format
UF2 payload.
There is no standard cartridge format for the GameTank. Initial form factors included 8KB EEPROM and 2MB NOR flash, but anything goes. For this reason, a published title could have different artifacts depending on cartridge capability. As a reusable flash cart, supported features are discovered at runtime.
Multiplatform support is at the core of the UF2 format, with device description as part of the header tag. This allows for a filtered stream of 476-byte blocks (after header content of the wider 512-byte block), which can then be serialized with a small program.
The data can be anything and does not need to be “disk” content. By convention, the cartridge explorer workflow could have a metadata block that contains title, description, author, and screenshot. Additional blocks could even include video previews.
Network Interactions
Implementation detail. Note that parsing offloads to the ESP32, so the network wire protocol is meant to be robust and modern. The 6502 concerns itself only with the bus protocol and filtered streams of cartridge data for serialization.
(Sidenote: the OPDS format is relevant, supporting discovery with faceted browsing in addition to a basic feed.)
