To create a cartridge for your C64 in the simplest form, is wiring a 8K ROM to the expansion port.
The CPU can only see a maximum of 65536 bytes. Adding a cartridge will not give you additional memory, instead it will replace memory at $8000, $A000 or $E000 depending on how ROML, ROMH, EXROM and GAME lines are being handled in the expansion port.
It is possible to bank in and out ROML/ROMH areas to gain access to different banks or RAM. This is how EasyFlash cartriges provide 1MB to the C64, it however only sees 16K of the 1MB at a time.
There are basically three types of cartridges for the C64:
8K Cartridge, $8000-$9FFF (ROML).
GAME = 1, EXROM = 0
ROML is read only. Basic ROM and Kernal ROM are available.
16K Cartridge, $8000-$9FFF / $A000-$BFFF (ROML / ROMH).
GAME = 0, EXROM = 0
ROML/ROMH are read only, Basic ROM is overwritten by ROMH.
16K Cartridge, $8000-$9FFF / $E000-$FFFF (ROML / ROMH). Ultimax mode.
GAME = 0, EXROM = 1
Ultimax mode is an emulation of the Japanese CBM machine called “MAX”. It is a predecessor of the C64 with less RAM. In Ultimax mode ROMH replaces the kernal at $E000. You do not need ROML for a cartridge to function and can be left out.
Cartridge autostart
When starting up, the CPU will load the reset vector from $FFFC/$FFFD into the program counter and continue from there. If a normal cartridge is present, it executes the kernal and checks for a cartridge identifier string.
Kernal will look for the string “CBM80” at $8004- and will do a “JMP($8000)” if found.
If an Ultimax cartridge is inserted, the kernel is overwritten by ROMH and therefor $FFFC/$FFFD must point to your code.
8/16K Cartridge code example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
* = $8000 .word coldstart ; coldstart vector .word warmstart ; warmstart vector .byte $C3,$C2,$CD,$38,$30 ; "CBM8O". Autostart string coldstart sei stx $d016 jsr $fda3 ;Prepare IRQ jsr $fd50 ;Init memory. Rewrite this routine to speed up boot process. jsr $fd15 ;Init I/O jsr $ff5b ;Init video cli warmstart ; Insert your code here inc $d020 jmp *-3 * = $9fff ; fill up to -$9fff (or $bfff if 16K) .byte 0 |
Test the code above with WinVICE:
1 2 3 4 5 |
64tass -a cart.tas -o cart.prg WinVice\cartconv -t normal -name "cartridge name" -i cart.prg -o cart.crt WinVice\x64.exe -cartcrt cart.crt |
Commodore 64 Expansion port pinout:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Pin Type Pin Type Pin Type Pin Type +----+----------+ +----+----------+ +----+----------+ +----+----------+ | 1 | GND | | 12 | BA | | A | GND | | N | A9 | | 2 | +5V | | 13 | /DMA | | B | /ROMH | | P | A8 | | 3 | +5V | | 14 | D7 | | C | /RESET | | R | A7 | | 4 | /IRQ | | 15 | D6 | | D | /NMI | | S | A6 | | 5 | R/W | | 16 | D5 | | E | ∅2 | | T | A5 | | 6 | Dot Clock| | 17 | D4 | | F | A15 | | U | A4 | | 7 | I/O 1 | | 18 | D3 | | H | A14 | | V | A3 | | 8 | /GAME | | 19 | D2 | | J | A13 | | W | A2 | | 9 | /EXROM | | 20 | D1 | | K | A12 | | X | A1 | | 10 | I/O 2 | | 21 | D0 | | L | A11 | | Y | A0 | | 11 | /ROML | | 22 | GND | | M | A10 | | Z | GND | +----+----------+ +----+----------+ +----+----------+ +----+----------+ |
8K Cartridge $8000-$9FFF
16K Cartridge $8000-$BFFF
16K Cartridge $8000-$BFFF (Single chip version)
A 27128 chip and a two input AND gate consisting of two diodes and a resistor. You can also use a 74LS08.
8K Cartridge $e000-$FFFF (Ultimax, no ROML at $8000)
You can create a 16K Ultimax cartridge by adding a 8K EPROM and connect it to ROML($8000-$9FFF).
Link(s):
Check out SukkoPera’s Open Hardware 8Kb Cartridge at: https://github.com/SukkoPera/OpenC64Cart
Update 2015.12: Corrected an error in the 16K cart schematic. EXROM/GAME should be connected and not IO2/EXROM. Text was correct but QC slipped on the drawing. Thanks to mATE for notifying me about it.
Update 2016.01: Updated Ultimax cart schematic with $e000-$ffff. Text was correct but again QC has slipped on the drawing. Thanks to Bart for the heads up.
Update 2017.12: Added single chip 16K schematic.
Comments