|This page is work in progress. Please check back later.|
GMod3 is a C64 flash cartridge primarily aimed at OEM for use with games. As opposed to GMod2, it is also available to regular customers (16MByte version only). It contains 2MBytes to 16MBytes flash (depending on the version) that can be programmed from every C64/C128 model.
There are up to eight banking registers mapped to $DE00-$DE07. The registers are always active and there is no way to disable them. The addresses are fully decoded. This means that there are no mirrors for these eight write-registers.
|$DE00||Bank 0-255||all versions|
|$DE01||Bank 256-511||4MB and higher versions only|
|$DE02||Bank 512-767||8MB and higher versions only|
|$DE03||Bank 768-1023||8MB and higher versions only|
|$DE04||Bank 1024-1279||16MB version only|
|$DE05||Bank 1280-1535||16MB version only|
|$DE06||Bank 1536-1791||16MB version only|
|$DE07||Bank 1792-2047||16MB version only|
On the hardware side, these are NOT completely separate registers. Instead, the eight bits that you're writing to are the same eight register bits over all eight registers. The lower three bits of the address are stored as additional banking bits, so you should view this register block as a single 11-bit banking register. You can conveniently set the bank like this:
ldx #bankhi ; upper 3 bits of the bank number lda #banklo ; lower 8 bits of the bank number sta $de00,x
Reading back the contents of the lower eight bits is possible by reading any of the eight addresses. The banking bits 8 to 10 can be read in bits 0, 1 and 2 of read-register $de08, which is mirrored up to $de0f. The other bits are guaranteed to be 0, so no masking is required.
ldx $de08 ; upper 3 bits of the bank number lda $de00 ; lower 8 bits of the bank number
The startup/reset value of all eleven banking-bits is 0.
Register $DE08 is the control register
|Address||Bit 7||Bit 6||Bit 5||Bit 4||Bit 3||Bit 2||Bit 1||Bit 0|
Unused bits should be written 0 for future compatibility. The startup values mean that the cartridge will start as an 8k game cartridge, mapping bank#0 to $8000 of the computer. Setting the Exrom bit to 1 will disable the 8k cartridge mode and free the $8000 memory area. Please note that the $01 processor register can also be used to free the path to C64 memory in that area. Even if 8k cartridge mode is switched off, all $dexx registers stay available.
Setting the IRQ-Vector bit to 1 will replace the $fff8-$ffff area with this byte-pattern, regardless of the state of the $01 processor register:
$08 $00 $08 $00 ; NMI Vector, $0008 $0c $80 ; RESET Vector, $800c $0c $00 ; IRQ Vector, $000c
This will result in the IRQ vector to point to address $000c and the NMI vector to point to address $0008 and will shorten the IRQ service time if code is executed directly from the 8k area in $8000 (note that switching the $e000-$ffff area to RAM is not possible while a cartridge in $8000 is active - this is overcome with the IRQ vector feature). Since the IRQ-Vector bit is reset to 0 on a reset, the seemingly-resulting altered reset vector has no effect. However, it's a factory option to set the IRQ Vector bit to 1 on a reset. This will make it more difficult to dump a cartridge, as the typical Kernal-ROM patches that ignore the CBM80 string won't have any effect.
Having the IRQ/NMI vectors point to a location in zeropage allows placing JMP instructions at these addresses, which results in an IRQ/NMI soft-vector in zeropage at the following two addresses. Modifying these is possible with fast zeropage-addressing, saving valuable cycles. Further, placing the IRQ vector (which is more commonly used, as it can be issued by the VIC) after the NMI vector gives the alternate possibility of placing the IRQ service routine directly to address $000c, without the added cycles that a JMP would take. Further, placing the IRQ vectors at the beginning of zeropage will give a high amount of continuous zeropage memory:
$0000 CPU-Port-Direction $0001 CPU-Port-Data $0002 available $0003 available $0004 available $0005 available $0006 available $0007 available $0008 JMP (NMI-HW-Vector target) $0009 NMI-Soft-Vector Lo $000a NMI-Soft-Vector Hi $000b available $000c JMP (IRQ-HW-Vector target) $000d IRQ-Soft-Vector Lo $000e IRQ-Soft-Vector Hi $000f ... available $00ff
The control register is a write-only register. Reading the control register will NOT return the value you've written, but the upper three bits of the eleven bank-bits in D0-D2 (see previous paragraph).
If BitBang mode is activated with the BitBang bit set to 1, automatic command/address generation for the SPI flash is deactivated, so you will instantly lose access to the $8000 ROM, and reading back the bank register(s) is also disabled. As a result, any routine accessing the flash through BitBang mode MUST run from the computer's RAM. Further, it is recommended to switch to bank#255 before activating BitBang mode in order to have the chip select line of the SPI flash "inactive" once BitBang mode is on. Flash cannot be written per-byte (as can be done on EEPROMs), but only on a per-page basis, so if you only want to alter a few bytes, you should copy the complete page to RAM, switch to BitBang mode, set the Exrom bit to 1 (for more RAM availability) and then do a page-erase/page-program sequence once you have done your changes in the RAM buffer. Further, since you will also lose the currently-set bank, it is recommended to read the bank register's content and store it in RAM, so it can be restored after the BitBang session has ended.
In BitBang mode, the bank-bits are hard-wired to the serial SPI flash chip:
|Address||Bit 7||Bit 6||Bit 5||Bit 4||Bit 3||Bit 2||Bit 1||Bit 0|
Reading any address of the $de00 space will return the state of the Flash-Dout pin in bit#7. The other bits are all 0, so there is no need for extra masking. Since write-registers are still active in BitBang mode, (both the bank registers and the control register) you can choose any other address in the $dexx space to read the status of the Flash-Dout pin using a ROL instruction without affecting the contents of any write-register. For good measure and future compatibility, a single address should be chosen. The examples in our public repository are using $de10.
Please note that the Flash-CS bit is active-low. Although the bit arrangement is similar to what G-Mod2 uses, the polarity of the Flash-CS signal is active-low here (the EEPROM of G-Mod2 uses active-high). Data from Flash-Din is taken over into the SPI clash chip on the rising edge of Flash-CLK.
- Public GMod3 examples repository