Family Computer Disk System

From NESdev Wiki
Revision as of 18:55, 21 March 2010 by Bregalad (talk | contribs) (Added FDS registers and pseudo-registers info (whew...))
Jump to navigationJump to search

fwNES was an NES emulator developed by Fan Wan Yang. Its most lasting contribution to the NES scene was its disk image file format.

.FDS format

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:

  1. Header (16 bytes)
  2. 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 : Disk sides are expected to equal 1 (single sided disk) or be an even number (n double sided disk). An even number would mean the last disk is single-sided, but no commercial FDS games were this way.

References

Overview

  • PRG ROM : 8 KB BIOS
  • 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

To be written

FDS File Format

To be written

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

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)
$00..$0F : Used as temporary memory for the BIOS. The main program can use it as temporary memory too, but shouldn't expect them to be preserved by any BIOS call.

BIOS Calls

To be written