Bung Game Doctor SF3, SF6, SF7 Headers

Version 1.0 - Copyright 2003: The Dumper

The Game Doctor SF3/SF6/SF7 backup units for the SNES use a 512 byte header.

The format is as follows (all numbers are hexadecimal):


47 41 4D 45 20 44 4F 43 54 4F 52 20 53 46 20 33 "GAME DOCTOR SF 3"

This is the ID string for a Game Doctor SF header.


SRAM size limit byte. This is used in conjunction with other bytes in the header that locate the SRAM in the address space of the SNES. Valid values are:

0x80: Either 0 SRAM or 256 Kbit SRAM depending on other bytes in the header (see below).

0x81: 64 Kbit SRAM

0x82: 16 Kbit SRAM

This byte limits the amount of address lines active to the SRAM. You also have to map the SRAM into the SNES address space with other bytes in the header. If you don't map it in the size is 0.


Maps DRAM chunks into the SNES address space. One byte maps one 4 Mbit chunk of DRAM into the SNES address space. One DRAM logical unit is 8Mbit (holds two 4Mbit chunks). If you logically divide your ROM file into 4Mbit chunks, the first chunk will have ID 0x20, the second 0x21, the third 0x22, etc. Where you place the chunk ID in the header determines where the chunk gets mapped into the SNES address space. Here is the map key:

---------------------------------   ---------------------------------
|00H|10H|20H|30H|40H|50H|60H|70H|   |80H|90H|A0H|B0H|C0H|D0H|E0H|F0H|
---------------------------------   ---------------------------------
                -----------------                   -----------------
                |40L|50L|60L|70L|                   |C0L|D0L|E0L|F0L|
                -----------------                   -----------------

00H = map dram chunk into $00-0F:8000-FFFF
10H = map dram chunk into $10-1F:8000-FFFF
E0H = map dram chunk into $E0-EF:8000-FFFF
F0H = map dram chunk into $F0-FF:8000-FFFF

40L = map dram chunk into $40-4F:0000-7FFF
50L = map dram chunk into $50-5F:0000-7FFF
60L = map dram chunk into $60-6F:0000-7FFF
70L = map dram chunk into $70-7F:0000-7FFF

C0L = map dram chunk into $C0-CF:0000-7FFF
D0L = map dram chunk into $D0-DF:0000-7FFF
E0L = map dram chunk into $E0-EF:0000-7FFF
F0L = map dram chunk into $F0-FF:0000-7FFF

In a LoROM game with SRAM you map SRAM into the address space by putting a 0x40 byte in the segment where you want it mapped. One common LoROM mapping puts SRAM in the lower 32K of the $7x and $Fx banks. This is specified by putting a 0x40 in the bytes for 70L and F0L.

I think a 00 in one of these bytes means nothing is mapped to that range.

A 0x60 in one of these bytes is used in an entry to pass-through data to/from the cart in that address range. This can be used for anything with a special chip that needs direct access to the special chip registers in a certain address range. I think there is a timing problem with some special chips using the 0x60 pass-through accesses. With some types of special chips corruption sometimes occurs.

Note that 0x60 is not needed for HiROM DSP1 games. Those addresses are passed through by default. Also, the S-RTC address range (DKJM2) seems to be passed through by default.

0x60 (in 30H and B0H) is needed for LoROM DSP accesses to be passed through.

The Game Doctor has some restrictions on the use of memory units. A HiROM game must be loaded into two different memory units (I suspect that this was a hardware restriction of the SF3 or SF6). My working assumption, which is not correct but is probably over restrictive and will work in all cases, is that you cannot load both High and Low halves of a bank from the same dram unit.

0029-002A: These two bytes map the SRAM into the HiROM style of SRAM mapping. Each bit controls whether SRAM is mapped for a specific range of banks. When a bit is set it maps offsets $6000-$7FFF to SRAM in the specified range of banks.

          0029                       002A
-------------------------  -------------------------
|7x|6x|5x|4x|3x|2x|1x|0x|  |Fx|Ex|Dx|Cx|Bx|Ax|9x|8x|
-------------------------  -------------------------

If the game's SRAM size is 0 these bytes should be 00 00.

If the game is a LoROM game, these bytes will be 00 00.

Standard HiROM mapping bytes are 0C 0C, which corresponds to mapping SRAM to banks 3x,2x,Bx,Ax:6000-7FFF

Tales of Phantasia and Dai Kaiju Monogatari 2 use mapping bytes 00 0F, which corresponds to SRAM in banks 8x,9x,Ax,Bx:6000-7FFF.

There are one or two oddball HiROM SRAM mappings. One I've found is for some 10-12 Mbit HiROM games. Some use 0A 0A. I believe this to be a side effect of the way the MAD-1 decoder is wired in these carts. So far all the exceptions in this category work with the standard SRAM mapping of 0C 0C. They have ranges 3x,Bx:6000-7FFF in common with the standard mappings, which is where these games access the SRAM.

002B-1FFF: Reserved. Filled with 00.

Game Doctor SF7

The BIOS mode memory map:

$00:8000-807F .... BIOS regs, so $80 bytes of the ROM is never accessible (so there is no need to worry about it).
$00:8080-FFFF .... first 32kBytes of ROM
$01:8000-FFFF .... second 32kBytes of ROM
$02:8000-FFFF .... unused
$03:8000-FFFF .... unused
$04:8000-FFFF .... BRAM
$05:8000-FFFF .... SRAM for real time save data (4kByte)
$06:8000-FFFF .... SRAM for copier settings (4kByte)
$07:8000-FFFF .... 32kB page of DRAM 

And then this is just repeated for all banks $00-$7F. It can also be in $80-$FF depending on some register settings.

BIOS mode memory map:

$008000-$00807F registers
	Cartridge Mode memory map settings
		$008000-$008017 (read/write)
			each is a byte and holds the setting of a region of the memory map values have same meaning like in the header
			(gotten from code at 81/A1E3)
		$008018 write, "expansion mem" location settings ? 
		$008019 write, "expansion mem" location settings ?
	Real Time Save information
		$008018 read, bit1 = $4016 bit0
		$00801A read word, latch settings for double write word registers

$008018 read bit7 = ? , bit = ?
$008019 read bit1 = ?
$00801A write ?
$00801B write ?

BIOS memory map settings
	$00801D write, changes what is mapped into banks $80-$FF
		only bit0-bit1 seem to matter
		0 = use cartridge banks $00-$7F
		1 = use cartridge banks $80-$FF
		2 = mirror banks $00-$7F (BIOS regs and all?)
		3 = mirror banks $00-$7F (BIOS regs and all?)

$00801E write ?
$008020 bit7 = 1, means "ready" or "continue" (code waits for bit=1)
$008022 write ?
$008024 write ?
$008028 write ?
$00802A write ?
$00802B write ?
		parallel port
			$00802C data pins 
			$00802D status (not direct pin reading?)
					bit7 = /S7 (direct pin11) = "write bit7" AND not "write bit0"
					bit6 = "write bit4"
					bit5 = "write bit4"
					bit4 = "write bit4"
					bit3 = "write bit3"
					bit2 = /C3 (direct pin17)
					bit1 = C2 (direct pin16)
					bit0 = /C1 (direct pin14)
					bit3 => S3 (direct pin15)
					bit4 => S4 (direct pin13)
					bit5 => S5 (direct pin12)
					bit6 => S6 (direct pin10)
					bit7 ...
						bit7 AND /bit0 ==> /S7 (direct pin11)
			$00802E control (not direct control reg values)
					bit7 = /C0 (direct pin1)
					bit0 = /C1 (direct pin14)
					bit1 = C2 (direct pin16)
					bit2 = /C3 (direct pin17)
					bit3-bit6, read = bit3-bit6 of $00802D
			$00802F read same as $00802D
		DRAM control ??
			$008030 word, ?? controls what is mapped into $078000
				valid $0000 - $01FF = 32kB page (out of 128 MBits) that is mapped in
				(gotten from code at 81/A235)
			$008030-$00803D ... 7 word table??
				(gotten from code at 80/AE80)

$008040-$00805F read same as $00802D
$008060-$00807F read = $FF

        $0080xF (where x = 8 - F)
        any access to $00:80xF will cause a "switch to cartridge mode"
$048000-$04FFFF 32k BRAM (not actually battery backed)
$058000-$058FFF = 4k SRAM
copier listens in on SNES register accesses and writes the results here
$068000-$068FFF = 4k SRAM
I believe the 8k SRAM chip is split between bank $05, $06
(gotten from code at 81/87B7)
The BIOS seems to use this memory region to save copier settings.

$078000-$07FFFF 32k DRAM
everything appears to be mirrored to banks $2x

$258000-$2585FF saved register settings ??,$21xx,$42xx,$43xx,$21xx,$21xx

$068000 = 
66 ($42) byte entries for each DRAM "slot" ... 16 slots -> $420 bytes

routine at 81/A6C6 usually used
$00-$11 ... 18 bytes, game name in slot
$18-$22 ... 11 bytes, file name
        ... 1st two bytes: $53,$46 to be "valid" ie start with SF
$23,$24 ... word: $54,$53 if "invalid" or something
Actual GD3 ROM header info
$25     ... SRAM setting
$26-$3D ... memory map bytes
$3E-$3F ... expansion mem setting
$40     ... word: sum of words $00-$3E of this entry
$068420 = saved $06842E
$068422 = saved X
$068424 = saved Y
$068426 = saved stack
$068428 = saved D
$06842E = saved A
$068436-$068535 temporary storage of first $100 bytes of WRAM
$068541-$0685D2 $92 bytes of "settings", includes tables of jump code
$0685D5 = saved word $00801A
$0685DB = bit0 used for $801D in BIOS mode
$068600 = 16 bytes
	4 x 4byte settings - 24bit pointer (MSB first), then temp holding of a WRAM byte
$068610 = 16 bytes
	for each "slot" the DRAM page/2 which holds the beginning of the ROM
$068620 = $40 bytes, a copy of the internal ROM header $7FC0-$7FFF
$06FFB0,X ?? holds bank settings of some sort?

$12 = (24bit pointer) stack pointer + 1 
$1C = temporary delay counter
$1D = "
$1E = $10 * DRAM "slot" # that is start of game
$20 = upper part of tilemap (settings)
$23 = last byte sent to PC
$25 = main menu #,
	00 = PlayGame
	01 = PlayDisk
	02 = Utility
$29 = word, frame number?
$2E = 00,'D','X' depending on name in $0300
$3E = transfer setting
	80 = ROM
	40 = SAVER
	00 = BRAM
$3F = non-zero if we need to wait for $802E bit7 == nonzero
      zero if we need to wait for $802E bit7 == zero
$80 = old Joypad1 data
$82 = current Joypad1 data
$84 = button just pressed JoyPad1 data
$86 = very important, so please note that this needs more investigation
	= which DRAM "slot" ?
$9F = temporary backup of $86
$C5-$C7 = RAM search findings ... see comments at 80/D842 for details
$C8 = RAMsize setting (calculated when back up cart)
$F5 = parallel port transfer mode/state ??
	bit0 = 1, use GD3
		= 0, use GD6
	for GD6
		bit1 = 1, read
			= 0, write

$0300 = $0B byte buffer to hold DRAM section name (file split names)
$0312 = $04 byte buffer to hold transfer info
	1st: 00
	2nd: 02 if header included, 00 if not
	3rd: number of 64k chunks ($10 = 8 MBit)
	4th: 00
$03B6 = $0B byte buffer ... intially a copy of $0300
$0600 = $200 byte buffer for ROM headers