Table of Contents

Flash Cartridges

This page covers information about the 2MB Flash Cartridge for the GameTank.

The cartridge is built around a M29F160FT55N3E2 parallel NOR flash, which has 2 megabytes of storage capacity.

Since the 6502 is only able to address 64K of memory, and the GameTank cartridge slot is only afforded half of that range, a banking scheme is employed to access the full capacity of the flash chip.

The cartridge port only has 15 address bits, while the flash memory has 21. This means that 6 of the flash memory's address bits must be controlled by something other than the CPU's address outputs. Furthermore, since any banking hardware may be in an unknown state at boot there should be an address range that is unaffected by the banking state and thus becomes deterministic. Therefore an additional system address signal is reserved for requesting unbanked memory, and a total of 7 surplus flash address bits must be managed.

Alongside the flash memory, the chip has a shift register connected to pins 2, 4, and 5 on the cartridge. This shift register may control the 7 most significant address bits on the flash. Specifically, it only controls those address bits when the CPU requests an address on the cartridge (A15 HIGH) but in the lower half of cartridge memory (A14 LOW). When an address on the upper half of cartridge memory (A14 HIGH) is requested, the 7 banked address bits are pulled HIGH.

Interfacing with the shift register from software

The pins connected to the shift register are controlled by the VIA, mapped to the lower 3 bits on Output Register A. Given that the respective bits of Data Direction Register A are configured for output mode, these bits on ORA can push a bank number into the shift register one bit at a time.

Bit Use
0 CLOCK
1 DATA
2 LATCH

Each time CLOCK goes from 0 to 1, the value of DATA is pushed into the shift register. When LATCH goes from 0 to 1, the value of the shift register will take effect.

The following code demonstrates a subroutine that pushes the contents of the Accumulator into the cartridge bank register. VIA, ORA, and DDRA are defined such that VIA+ORA is evaluated as $2801 by the assembler and VIA+DDRA is evaluated as $2803. A subroutine is also given for setting up the VIA to control cartridge banking, which should be called at least once before using ShiftHighBits.

SetupVIA:
    LDA #%00000111
    STA VIA+DDRA
    LDA #$FF
    STA VIA+ORA
 
ShiftHighBits:
	STA temp
	LDA #$FF
	STA VIA+ORA
 
	LDA temp
	ROR
	ROR
	ROR
	ROR
	ROR
	AND #2
	ORA #%00000100
	STA VIA+ORA
	ORA #1
	STA VIA+ORA
 
	LDA temp
	ROR
	ROR
	ROR
	ROR
	AND #2
	ORA #%00000100
	STA VIA+ORA
	ORA #1
	STA VIA+ORA
 
	LDA temp
	ROR
	ROR
	ROR
	AND #2
	ORA #%00000100
	STA VIA+ORA
	ORA #1
	STA VIA+ORA
 
	LDA temp
	ROR
	ROR
	AND #2
	ORA #%00000100
	STA VIA+ORA
	ORA #1
	STA VIA+ORA
 
	LDA temp
	ROR
	AND #2
	ORA #%00000100
	STA VIA+ORA
	ORA #1
	STA VIA+ORA
 
	LDA temp
	AND #2
	ORA #%00000100
	STA VIA+ORA
	ORA #1
	STA VIA+ORA
 
	LDA temp
	ROL
	AND #2
	STA VIA+ORA
	ORA #1
	STA VIA+ORA
 
	ORA #4
	STA VIA+ORA
 
	RTS

Reading from banked memory

Any data that you want to access with the movable window should be referenced by its address relative to the start of its bank plus the cartridge port offset. So if you have data to access at $0, $4000, and $C000 bytes into your game binary you'd read from $8000 after setting the bank number to 0, 1, and 3 respectively.

The last 16KB of your game binary are always accessible at $C000-$FFFF, and also accessible at $8000-$BFFF if the bank number has been set to 127 or 255.

Some toolchains like cc65 have features that can assign addresses in seemingly overlapping ranges depending on the linker configuration.

Creating ROM files

Both the GameTankEmulator and GameTankFlashingOverhauled will assume a file with a size of exactly 2^21 bytes is a ROM file for the 2MB flash cartridge. In this file all of the banks are concatenated together in the order of their bank number, including empty banks.

GameTankFlashingOverhauled will also treat any 16384-byte file with an extension like .bankXX (where XX is a hexadecimal number) as a single bank from the flashcart so that less time can be spent flashing empty banks.