Family Computer Disk System
The Famicom Disk System was a Japan-exclusive storage device for the Famicom, designed to reduce Nintendo's cost of making copies of games by switching from mask ROM chips to a storage medium based on Mitsumi's Quick Disk. Unfortunately for Nintendo, it also reduced the pirates' cost of making copies of games.
.FDS format
fwNES was an NES emulator developed by Fan Wan Yang. Its most lasting contribution to the NES scene was its disk image file format, an image of the Quick Disk media.
The FDS format (file name suffix .fds
) is a way to store Famicom Disk System disk data. It consists of the following sections, in order:
- Header (16 bytes)
- Disk data (65500 * x bytes)
The format of the header is as follows:
- 0-3: Constant $46 $44 $53 $1A ("FDS" followed by MS-DOS end-of-file)
- 4: Number of disk sides in 65500 byte units
- 5-15: Zero filled
Note: Most games are an even number of sides. Ports from NROM were one side. No commercial FDS game had an odd number of sides greater than 1.
Overview
- PRG ROM : 8 KB BIOS at $E000-$FFFF
- PRG RAM: 32 KB at $6000-$DFFF
- CHR capacity: 8 KB RAM
- Nametable mirroring: Controlled by mapper
- Subject to bus conflicts: No
Games are stored on one or multiple disk sides. The FDS BIOS is used to load data from disks to PRG RAM or VRAM, and games can execute form there.
FDS Disk Side format
Each disk side must be structured into block as follows :
1, 2, 3, 4, 3, 4, ...., 3, 4
The 3, 4 pattern should be repeated once per file present on the disk.
From the last file, fill the side with all 0 so that the side has exactly 65550 is reached.
Block format
Disk info block (block 1)
SIZE CONTENTS 1 $01 14 FC Disk String "*NINTENDO-HVC*" (not including the ") 1 Manufacture Code Same code as used in GameBoy(?) 4 Game Name Code 1 Game Version Number (start with $00, increase each revision) 1 Side Number $00: Side-A $01: Side-B 1 Disk Number (fist disk is actually $00) 1 Err.9 (indicate disk # ?, usually $00) 1 Err.10 (indicate disk # ?, usually $00) 1 Boot Read File Code 5 Unknown 3 Manufacture Permit Date Recorded in BCD, in the year of "showa"(+1925) For example, 21 march 2010 becomes $85, $03, $21 (because 2010-1925 = 85) 10 Unknown 3 Created Date Recorded in BCD, in the year of "showa"(+1925) 9 Unknown
The *NINTENDO-HVC*, stored in ASCI standard, strings proves this is a FDS disk, and if the string doesn't exactly match the BIOS will refuse to read the disk further. If the FDS is started with a disk whose side number and disk number aren't both 0, it will be prompted to insert the first disk side. Some games do however make this number 0 even for the second disk to make it bootable as well.
All files which IDs is smaller than the boot read file code will be loaded when the game is booting.
The FDS will also refuse to run the game if the first file isn't a nametable type file which is traditionally named "KYODAKU-" and which print a text on the screen.
File amount block (block 2)
This block contains the total number of files recorded on disk. The info in this block is checked only at system boot. Since there may exist more files than the number recorded in this block, emulators should ignore the value recorded in this block.
SIZE CONTENTS 1 $02 1 File Amount
File header block (block 3)
SIZE CONTENTS 1 $03 1 File Number 1 File Indicate Code (file identification code) ID specified at disk-read function call 8 File Name 2 File Address (16-bit little endian) the destination address when loading 2 File Size (16-bit little endian) 1 Kind of File 0:Program (PRAM) 1:Character (CRAM) 2:Name table (VRAM)
The file Number must go in increasing order, first file is 0. File IDs can be freely assigned, and this is the number which will decide which file is loaded from the disk (instead of the file number). An ID smaller than the boot number means the file is a boot file, and will be loaded on first startup.
File names are uppercase ASCII.
File data block (block 4)
SIZE CONTENTS 1 $04 -- disk data
Registers
$402x registers are write-only $403x registers are read-only
IRQ timer low ($4020)
7 bit 0 --------- LLLLLLLLL |||| |||| ++++-++++- 8 LSB of IRQ timer
IRQ timer high ($4021)
7 bit 0 --------- LLLLLLLLL |||| |||| ++++-++++- 8 MSB of IRQ timer
IRQ timer enable ($4022)
7 bit 0 --------- xxxx xxEx | +-- Enable IRQ timer
Each CPU clock cycle the timer is decremented by one if the enable flag is set. When the counter reach 0, an IRQ is generated. Read $4030 to acknowledge the IRQ.
Note : Since the disk transfer routine also uses IRQs, it's very important to disable timer IRQs before doing any access to the disk.
Master I/O enable ($4023)
7 bit 0 --------- xxxx xxSD || |+- Enable disk I/O registers +-- Enable sound I/O registers
This register sounds obscure. FDS bios just writes $00 then $83 to it.
Write data register ($4024)
The data that this register is programmed with will be the next 8-bit quantity to load into the shift register (next time the byte transfer flag raises), and to be shifted out and appear on pin 5 of the RAM adaptor cable (2C33 pin 52).
FDS Control ($4025)
7 bit 0 --------- IS1B MRTD |||| |||| |||| |||+- Drive Motor Control |||| ||| 0: Stop motor |||| ||| 1: Turn on motor |||| ||+-- Transfer Reset |||| || Set 1 to reset transfer timing to the initial state. |||| |+--- Read / Write mode |||| | (0: write; 1: read) |||| +---- Mirroring (0: horizontal; 1: vertical) |||+------ CRC control (set during CRC calculation of transfer) ||+------- Always set to '1' |+-------- Read/Write Start | Turn on motor. Set to 1 when the drive becomes ready for read/write +--------- Interrupt Transfer 0: Transfer without using IRQ 1: Enable IRQ when the drive becomes ready for
A FDS game that wants to change mirroring probably don't want to touch motor related bits, so it should do a read-modify-write from the pseudo registers (see below).
External connector ($4026)
Output of expansion terminal where there's a shutter on the back of the ram card. The outputs of $4026 (open-collector with 4.7K ohm pull-ups (except on bit 7)), are shared with the inputs on $4033.
Disk Status Register 0 ($4030)
7 bit 0 --------- IExB xxTD |||| || |||| |+- Timer Interrupt (1: an IRQ occurred) |||| +-- Byte transfer flag. Set every time 8 bits have been transfered between the RAM adaptor & disk drive (service $4024/$4031). |||| Reset when $4024, $4031, or $4030 has been serviced. |||+------ CRC control (0: CRC passed; 1: CRC error) |+-------- End of Head (1 when disk head is on the most inner track) +--------- Disk Data Read/Write Enable (1 when disk is readable/writable)
Read data register ($4031)
This register is loaded with the contents of an internal shift register every time the byte transfer flag raises. The shift register recieves it's serial data via pin 9 of the RAM adaptor cable (2C33 pin 51).
Disk drive status register ($4032)
7 bit 0 --------- xxxx xPRS ||| ||+- Disk flag (0: Disk inserted; 1: Disk not inserted) |+-- Ready flag (0: Disk read; 1: Disk not ready) +--- Protect flag (0: Not write protected; 1: Write protected or disk ejected)
External connector read ($4033)
7 bit 0 --------- BIII IIII |||| |||| |+++-++++- Input from expansion terminal where there's a shutter on the back of the ram card. +--------- Battery status (0: Good; 1: Voltage is low).
When a bit is clear in $4026 port it will read back as '0' here (including battery bit) because of how open collector input works.
Sound ($4040-$4089)
For details on sound information, see FDS audio.
Pseudo-registers
Those registers are used by the FDS bios and FDS programs. They are used to overcome the problem that NES/FDS registers are write only, so it is effectively possible to modify only one bit of them without affecting other bits.
[$FF]: value last written to $2000 $80 on reset. [$FE]: value last written to $2001 $06 on reset [$FD]: value last written to $2005#1 0'd on reset. [$FC]: value last written to $2005#2 0'd on reset. [$FB]: value last written to $4016 0'd on reset. [$FA]: value last written to $4025 $2E on reset. [$F9]: value last written to $4026 $FF on reset. $F5..$F8 : Used by controller read routines $00..$0F is used as temporary memory for the BIOS. The main program can use it as temporary memory too.
Those values are used by the BIOS to determine action on interrupt.
($0102): PC action on reset [$0101]: PC action on IRQ. set to $80 on reset [$0100]: PC action on NMI. set to $C0 on reset ($DFFE): disk game IRQ vector (if [$0101] = 11xxxxxxB) ($DFFC): disk game reset vector (if ($0102) = $5335, or $AC35) ($DFFA): disk game NMI vector #3 (if [$0100] = 11xxxxxxB) ($DFF8): disk game NMI vector #2 (if [$0100] = 10xxxxxxB) ($DFF6): disk game NMI vector #1 (if [$0100] = 01xxxxxxB)
A few important notes : - $102 indicate reset type : $AC = first boot of the game, $53 = the game was soft-reseted by the user - To use your own IRQ routine, you must manually write $c0 to $101 - There is 3 possible NMI vectors, #3 is used by default. If you only use one, then make all 3 identical.
BIOS calls
To be written