Floppy Disk Controller Subsystem

This page documents the FDC (Floppy Disk Controller) handler routines from the KN5000 firmware. The FDC interfaces with a uPD72068GF-3B9 controller at IC208.

Status: Many routines are disassembled below but not yet integrated into the assembly source (still stored as raw bytes with EQU labels).


SOME_DELAY Routine (0xF97612) - Timing Delay

The SOME_DELAY routine provides millisecond-scale timing delays used throughout FDC operations.

Disassembly

SOME_DELAY:                 ; F97612
    SRL 1, WA               ; Divide WA by 2 (logical shift right)
    LD DE, (SYSTEM_TIMESTAMP) ; Snapshot current timestamp
    LD HL, 0                ; Initialize timeout counter
    CP HL, 0ffffh           ; Initial check (always passes)
    RET NC                  ; (never triggers on first pass)

SOME_DELAY_Loop:               ; Polling loop
    LD BC, (SYSTEM_TIMESTAMP) ; Read current timestamp
    SUB BC, DE              ; Elapsed = current - start
    CP BC, WA               ; Compare elapsed to target
    RET UGT                 ; Return if elapsed > target (delay complete)
    INC 1, HL               ; Increment timeout counter
    CP HL, 0ffffh           ; Check for timeout (65535 iterations)
    JR C, SOME_DELAY_Loop      ; Continue polling
    RET                     ; Timeout exit (safety)

Operation

  1. Input: WA register contains the delay duration
  2. Division: WA is divided by 2 (so actual delay is half the input value in ticks)
  3. Timing: Polls SYSTEM_TIMESTAMP until elapsed time exceeds target
  4. Safety: Timeout exits after 65535 loop iterations to prevent hangs

SYSTEM_TIMESTAMP Source

SYSTEM_TIMESTAMP (address 0x0409) is a 32-bit counter incremented by the Timer 1 interrupt handler (INTT1_HANDLER at 0xEF0BF9). The timer is configured during system initialization:

; Timer configuration at EF042D
LD (T01MOD), 01dh   ; Timer 0/1 mode: cascade mode, T32 source
LD (TREG0), 00ah    ; Timer 0 reload = 10
LD (TREG1), 010h    ; Timer 1 reload = 16
SET 1, (T8RUN)      ; Start Timer 1

Each SYSTEM_TIMESTAMP tick represents approximately 1 millisecond based on the Timer 0/1 cascade configuration with the 20 MHz system clock.

Delay Formula

Actual_delay_ms = WA / 2

Common FDC Delay Values

WA Value Effective Delay Usage Context
2 ~1 ms Brief settling (FDC_INIT, FDC_STATUS_HANDLER)
10 (0x0A) ~5 ms Hardware reset settle, FDC_CMD_ENABLE loop
16 (0x10) ~8 ms Status handler secondary delay
200 (0xC8) ~100 ms Motor spin-up, long operations

Usage in FDC Code

  • FDC_INIT (0xF96BBF): WA=2 - 1ms delay after register setup
  • FDC_CONFIG_VERIFY: WA=2 - Settling delays between operations
  • FDC_STATUS_HANDLER: WA=2, then WA=0x10 - Status change delays
  • FDC_CMD_ENABLE loop (0xF97C40): WA=0x0A - 5ms delay per ready-check iteration
  • FDC Reset (0xF97ECF): WA=0x0A - Reset pulse timing

FDC Memory Map

Address Size Name Description
0x8A10 2 FDC_DRIVE_TYPE Drive type identifier
0x8A16 2 FDC_STATUS_FLAG Status/ready flag
0x8A1C 2 FDC_SECTOR_COUNT Sector count register
0x8A1E 2 FDC_SECTOR_SIZE Sector size (0x200 or 0x400)
0x8A20 1 FDC_INIT_FLAG Initialization flag (0xFF=init done)
0x8A24 1 FDC_ERROR_CODE Current error code
0x8A26 1 FDC_CACHED_STATUS Cached status value
0x8A28 1 FDC_COMMAND_REG Command register
0x8A2B-8A36 - FDC_MODE_PARAMS Mode configuration parameters
0x8A40 2 FDC_HANDLER_INDEX Handler dispatch index
0x8A44 2 FDC_OUTPUT_MODE Output control mode
0x8A48 2 FDC_TRACK_NUMBER Current track number
0x8A4A 2 FDC_TRANSFER_PTR Data transfer pointer
0x8A5C 4 FDC_XWA_SAVE XWA register save area
0x8A68 1 FDC_OPERATION_MODE Current operation mode
0x8A6A 1 FDC_OUTPUT_FLAG Output enable flag
0x8A6C 1 FDC_DRIVE_MODE Drive mode (0-5)
0x8B00 1 FDC_RESERVED_00 Reserved
0x8B04 1 FDC_LAST_STATUS Last known status
0x8B0C 2 FDC_MAX_TRACK Maximum track number
0x8B10 2 FDC_CURRENT_TRACK Current track cache

Routine Addresses

Address Name Description
0xF96BBF FDC_INIT Basic FDC initialization
0xF96BD0 FDC_CONFIG_VERIFY Configuration and status verification
0xF96D95 FDC_CMD_DISPATCH_SUB Command handler subroutine
0xF97696 FDC_STATUS_HANDLER Status/interrupt handler
0xF976E4 FDC_CMD_EXEC Command execution handler
0xF97835 FDC_SECTOR_XFER Sector/data transfer handler
0xF97984 FDC_MODE_CONFIG Mode configuration (Handler 5)
0xF97C21 FDC_CMD_ENABLE Command enable setup
0xF97C4B FDC_CMD_DISABLE Command disable
0xF97C54 FDC_STATUS_COPY Copy cached status
0xF97C5B FDC_OUTPUT_CTRL Output control
0xF97C7C FDC_INTERRUPT_HANDLER Main interrupt handler

Helper Routine Addresses

Address Name Description Status
0xF97612 SOME_DELAY Millisecond delay using SYSTEM_TIMESTAMP Documented
0xF97544 FDC_DRIVE_DETECT FDC drive detection routine Raw bytes
0xF97592 FDC_DRIVE_STATUS FDC drive status routine Raw bytes
0xF975AC FDC_PRE_OP_CHECK FDC pre-operation check Raw bytes
0xF975DC FDC_TIMING_DELAY FDC timing/delay routine Raw bytes
0xF975E2 FDC_POST_OP FDC post-operation routine Raw bytes
0xF972F9 FDC_CMD_SEND FDC command send routine Raw bytes
0xF974FE FDC_DETECT_CHECK FDC detection check routine Raw bytes

Disassembled Routines

FDC_INIT (0xF96BBF) - Basic FDC Initialization

Sets up FDC control register to 0xFF.

FDC_INIT:                   ; F96BBF
    LD WA, 0036h
    CALR FDC_Send_Command
    LD WA, 2
    CALR SOME_DELAY
    LD (8B04h), 0FFh
    RET

FDC_CONFIG_VERIFY (0xF96BD0) - Configuration/Status Verification

Complex routine that validates FDC status through multiple checks.

FDC_CONFIG_VERIFY:          ; F96BD0
    PUSH XIZ
    CALR FDC_ClearStatus_InitTimer
    CALR FDC_DRIVE_DETECT
    CP HL, 0FFFFh
    JR Z, FDC_CONFIG_L1
    CALR FDC_DRIVE_STATUS
    CP HL, 0FFFFh
    JR Z, FDC_CONFIG_L1
    LD (8B04h), 0FFh
FDC_CONFIG_L1:              ; F96BEB
    CP (8A20h), 0FFh
    JRL Z, FDC_CONFIG_EXIT
    LD (8A20h), 0FFh
    LD WA, 0036h
    CALR FDC_Send_Command
    LD WA, 2
    CALR SOME_DELAY
    CALR FDC_DRIVE_DETECT
    CP HL, 0FFFFh
    JR Z, FDC_CONFIG_L2
    CALR FDC_DRIVE_STATUS
    CP HL, 0FFFFh
    JR Z, FDC_CONFIG_L2
    CALR FDC_ClearStatus_InitTimer
    CALR FDC_CMD_DISPATCH_SUB
    CP (8A24h), 0
    JR Z, FDC_CONFIG_L3
    LD (8A20h), 0
    JRL T, FDC_CONFIG_EXIT
FDC_CONFIG_L3:              ; F96C2A
    CALR FDC_Read_Status
    BIT 7, L
    JR NZ, FDC_CONFIG_L4
    LD WA, 0032h
    CALR FDC_Set_Status
    JR T, FDC_CONFIG_L5
FDC_CONFIG_L4:              ; F96C3A
    LD WA, 0031h
    CALR FDC_Set_Status
FDC_CONFIG_L5:              ; F96C3F
    CALR FDC_Read_Status
    BIT 6, L
    JR Z, FDC_CONFIG_L6
    LD WA, 002Fh
    CALR FDC_Set_Status
FDC_CONFIG_L6:              ; F96C4C
    CALR FDC_Read_Status
    CP L, 0FFh
    JR NZ, FDC_CONFIG_L7
    LD WA, 00FCh
    CALR FDC_Set_Status
    JR T, FDC_CONFIG_EXIT
FDC_CONFIG_L7:              ; F96C5C
    LD WA, 0001h
    CALR FDC_Set_Status
    CALR FDC_DRIVE_DETECT
    CP HL, 0FFFFh
    JR Z, FDC_CONFIG_L2
    LD WA, 0001h
    CALR FDC_Set_Status
    CALR FDC_DRIVE_STATUS
    CP HL, 0FFFFh
    JR NZ, FDC_CONFIG_L8
FDC_CONFIG_L2:              ; F96C7B
    LD (8A20h), 0
    LD (8B04h), 0FFh
    JR T, FDC_CONFIG_EXIT
FDC_CONFIG_L8:              ; F96C88
    LD WA, 0036h
    CALR FDC_Send_Command
    LD WA, 2
    CALR SOME_DELAY
FDC_CONFIG_EXIT:            ; F96D93
    POP XIZ
    RET

FDC_CMD_DISPATCH_SUB (0xF96D95) - Command Handler Subroutine

Primary handler that initializes FDC and returns status. Called by: FDC_HANDLER_10 (dispatch table entry).

FDC_CMD_DISPATCH_SUB:       ; F96D95
    LD WA, 0036h
    CALR FDC_Send_Command
    LD WA, 2
    CALR SOME_DELAY
    CALR FDC_Read_Status
    CP L, 0FFh
    JR NZ, FDC_H10_OK
    LD WA, 00FCh
    CALR FDC_Set_Status
FDC_H10_OK:                 ; F96DAE
    LD HL, 0
    RET

FDC_STATUS_HANDLER (0xF97696) - Status/Interrupt Handler

Checks and updates FDC status, handles interrupts.

FDC_STATUS_HANDLER:         ; F97696
    LD A, (8A36h)
    CP A, (8B04h)
    RET Z
    LD (8B04h), (8A36h)
    LD WA, 2
    CALR SOME_DELAY
    CALR FDC_TIMING_DELAY
    LD WA, 000Fh
    CALR FDC_CMD_SEND
    CALR FDC_POST_OP
    CP (8A24h), 0
    JR Z, FDC_SH_L1
    LD (8B04h), 0FFh
FDC_SH_L1:                  ; F976C3
    LD WA, 0010h
    JRL T, SOME_DELAY

; Secondary status handler
FDC_STATUS_HANDLER_2:       ; F976C9
    LD (8A28h), 0C6h
    CALR FDC_Setup_DMA_Mode
    CALR FDC_TIMING_DELAY
    LD WA, 00C6h
    CALR FDC_CMD_SEND
    CP (8A24h), 0
    RET NZ
    JRL T, FDC_POST_OP

FDC_CMD_EXEC (0xF976E4) - Command Execution Handler

Handles FDC command execution with detection and validation.

FDC_CMD_EXEC:               ; F976E4
    PUSH IZ
    CALR FDC_DETECT_CHECK
    CP HL, 0
    JR Z, FDC_CE_L1
    LD (8A68h), 001h
    JRL T, FDC_CE_DISPATCH  ; 0xF9782A
FDC_CE_L1:                  ; F976F4
    CALR FDC_DRIVE_DETECT
    CP HL, 0
    JR NZ, FDC_CE_L2
    LD (8A68h), 008h
    JRL T, FDC_CE_DISPATCH
FDC_CE_L2:                  ; F97703
    LD (8A68h), 001h
    JRL T, FDC_CE_DISPATCH

FDC_CE_PROCESS:             ; F9770B
    LD (8A24h), 0
    CALR FDC_STATUS_HANDLER
    CP (8A24h), 0
    JR Z, FDC_CE_L3
    LD A, (8A24h)
    LD IZL, A
    EXTS IZ
    CALR FDC_CONFIG_VERIFY
    LD A, IZL
    LD (8A24h), A
    JRL T, FDC_CE_EXIT      ; 0xF97833
FDC_CE_L3:                  ; F97730
    LD WA, (8A48h)
    CP WA, (8B0Ch)
    JR ULE, FDC_CE_L4
    LD (8A48h), 0001h
FDC_CE_L4:                  ; F97740
    LDW (8B10h), (8A48h)
    LD (001Ch), 0
    ; ... continues with more sector handling

FDC_MODE_CONFIG (0xF97984) - Mode Configuration (Handler 5)

Configures FDC for different operating modes (0-5).

FDC_MODE_CONFIG:            ; F97984
    CALR FDC_PRE_OP_CHECK
    CP (8A24h), 0
    JRL NZ, FDC_MC_EXIT     ; 0xF97A3C
    CALR FDC_INTERRUPT_HANDLER
    CP (8A24h), 0
    JRL NZ, FDC_MC_EXIT
    CALR FDC_SeekRecalibrate
    CP (8A24h), 0
    JRL NZ, FDC_MC_EXIT
    LD A, (8A6Ch)           ; Load FDC mode
    CP A, 2
    JR Z, FDC_MC_MODE2
    CP A, 3
    JR Z, FDC_MC_MODE3
    CP A, 5
    JR Z, FDC_MC_MODE045
    CP A, 4
    JR Z, FDC_MC_MODE045
    CP A, 0
    JR NZ, FDC_MC_COMMON
FDC_MC_MODE045:             ; F979BD - Mode 0, 4, 5
    LD (8A2Eh), 002h
    LD (8A33h), 050h
    JR T, FDC_MC_COMMON
FDC_MC_MODE3:               ; F979C9
    LD (8A2Eh), 002h
    LD (8A33h), 06Ch
    JR T, FDC_MC_COMMON
FDC_MC_MODE2:               ; F979D5
    LD (8A2Eh), 003h
    LD (8A33h), 074h
FDC_MC_COMMON:              ; F979DF
    LD (8A36h), 0
    LD (8A2Bh), 0
    LD (8A34h), 0E5h
    LD (8A2Ch), 0
    LD (8A29h), 0
    ; ... continues

FDC_CMD_ENABLE (0xF97C21) - Command Enable Setup

Sets bit 3 at 0x28, waits for FDC ready.

FDC_CMD_ENABLE:             ; F97C21
    PUSH IZ
    SET 3, (28h)
    LD WA, 00FEh
    CALR FDC_CMD_SEND
    CP (8A24h), 0
    JR Z, FDC_CE_READY
    LD WA, 0031h
    CALR FDC_Set_Status
    JR T, FDC_CE_DONE
FDC_CE_READY:               ; F97C3A
    LD IZ, 1
    CP IZ, 0
    JR Z, FDC_CE_DONE
FDC_CE_LOOP:                ; F97C40
    LD WA, 000Ah
    CALR SOME_DELAY
    DJNZ IZ, FDC_CE_LOOP
FDC_CE_DONE:                ; F97C49
    POP IZ
    RET

FDC_CMD_DISABLE (0xF97C4B) - Command Disable

Clears bit 3 at 0x28.

FDC_CMD_DISABLE:            ; F97C4B
    RES 3, (28h)
    LD WA, 000Eh
    JRL T, FDC_CMD_SEND

FDC_STATUS_COPY (0xF97C54) - Copy Cached Status

Simple 2-instruction routine.

FDC_STATUS_COPY:            ; F97C54
    LD (8A24h), (8A26h)
    RET

FDC_OUTPUT_CTRL (0xF97C5B) - Output Control

Controls FDC output based on value in 0x8A44.

FDC_OUTPUT_CTRL:            ; F97C5B
    LD WA, (8A44h)
    CP WA, 1
    JR Z, FDC_OC_ENABLE
    CP WA, 0
    JR NZ, FDC_OC_OTHER
    JR T, FDC_OC_DISABLE
FDC_OC_OTHER:               ; F97C69
    LD WA, 00FEh
    CALR FDC_Set_Status
    RET
FDC_OC_ENABLE:              ; F97C70
    LD (8A6Ah), 0FFh
    RET
FDC_OC_DISABLE:             ; F97C76
    LD (8A6Ah), 0
    RET

FDC_INTERRUPT_HANDLER (0xF97C7C) - Main Interrupt Handler

Checks status and dispatches to appropriate handlers.

FDC_INTERRUPT_HANDLER:      ; F97C7C
    PUSH QIZ
    CP (8A24h), 0
    JR NZ, FDC_IH_EXIT
    LD WA, 4
    CALR FDC_CMD_SEND
    CP (8A24h), 0
    JR NZ, FDC_IH_EXIT
    CALR FDC_Wait_Ready_Timeout
    CP (8A24h), 0
    JR NZ, FDC_IH_EXIT
    CALR FDC_Read_Data
    LD QIZH, L
    BIT 7, QIZH
    JR Z, FDC_IH_L1
    LD WA, 0032h
    CALR FDC_Set_Status
FDC_IH_L1:                  ; F97CAE
    BIT 5, QIZH
    JR NZ, FDC_IH_L2
    LD WA, 0031h
    CALR FDC_Set_Status
FDC_IH_L2:                  ; F97CBA
    BIT 6, QIZH
    JR Z, FDC_IH_EXIT
    LD WA, 002Fh
    CALR FDC_Set_Status
FDC_IH_EXIT:                ; F97CC6
    POP QIZ
    RET

Handler Dispatch Table (0xF97D8D)

The FDC uses a handler dispatch table starting at 0xF97D8D:

Index Address Handler Name Description
0 F97D8D DISPATCH_BASE Basic handler (calls F97639)
1 F97D93 HANDLER_01 CMD_ENABLE + FDC_SeekRecalibrate
2 F97D99 HANDLER_02 CMD_ENABLE + STATUS_HANDLER
3 F97D9F HANDLER_03 CMD_ENABLE + CMD_EXEC
4 F97DA5 HANDLER_04 CMD_ENABLE + SECTOR_XFER
5 F97DAB HANDLER_05 CMD_ENABLE + MODE_CONFIG
6 F97DB1 HANDLER_06 CMD_ENABLE only
7 F97DB5 HANDLER_07 CMD_DISABLE
8 F97DB9 HANDLER_08 STATUS_COPY
9 F97DBD HANDLER_09 OUTPUT_CTRL
10 F97DC1 HANDLER_10 CMD_DISPATCH_SUB
11 F97DC5 HANDLER_11 CMD_ENABLE + INTERRUPT_HANDLER

All handlers end by jumping to FDC_Handler_ExitStatus which sets the status flag and returns.

Code References

Symbol Address Purpose
SOME_DELAY 0xF97612 Millisecond-scale timing delay (polls SYSTEM_TIMESTAMP)
FDC_INIT 0xF96BBF Basic FDC initialization (set control to 0xFF)
FDC_CONFIG_VERIFY 0xF96BD0 Configuration and multi-step status verification
FDC_CMD_DISPATCH_SUB 0xF96D95 Primary command handler subroutine
FDC_STATUS_HANDLER 0xF97696 Status/interrupt polling and update
FDC_CMD_EXEC 0xF976E4 Command execution with detection/validation
FDC_SECTOR_XFER 0xF97835 Sector/data transfer handler
FDC_MODE_CONFIG 0xF97984 Mode configuration (modes 0-5)
FDC_CMD_ENABLE 0xF97C21 Enable FDC command interface
FDC_CMD_DISABLE 0xF97C4B Disable FDC command interface
FDC_STATUS_COPY 0xF97C54 Copy cached status register
FDC_OUTPUT_CTRL 0xF97C5B FDC output enable/disable control
FDC_INTERRUPT_HANDLER 0xF97C7C Main FDC interrupt handler
FDC_ReadSectors 0xF96E00 Read sectors from floppy disc
FDC_WriteSectors 0xF97000 Write sectors to floppy disc
Check_for_Floppy_Disk_Change 0xEF4F5E Detect disc insertion/removal (Port D bit 6)
FDC_InitRecalibrate 0xF97E00 Recalibrate drive head to track 0

MAME Emulation Status

Component Status Notes
FDC device Working UPD72067 at 0x110008/0x11000A, 32MHz clock
DMA data port Working 0x120000 for software DMA channel 3
IRQ routing Working INT4 (command complete), INT5 (DRQ)
Floppy connector Working 3.5” HD (1.44MB, default) and DD (720K), MFI format supported
TC signal NOT IMPLEMENTED Timer 0 output (TO0) should pulse FDC TC, but TMP94C241 CPU core lacks timer output callbacks. Transfers hang without TC.
Disk images Available v5-v10 firmware update disks from archive.org
Disk change detect Fixed Port D bit 6 — dskchg_r() inverted for active-low hardware signal

Test command: mame kn5000 -flop <disk_image.mfi>

Disk Change Signal (Port D Bit 6)

The firmware’s Check_for_Floppy_Disk_Change (at 0xEF4F5E) reads Port D bit 6 before issuing any FDC commands. This signal is active-low on the hardware (low = disk change detected). MAME’s floppy_image_device::dskchg_r() returns active-high (1 = change detected), so the signal must be inverted: (!floppy->dskchg_r()) << 6. Without this inversion, the firmware always shows “ERROR 02! There is no disk in the disk drive.”

The TC (Terminal Count) signal terminates multi-sector FDC transfers. It should be wired from the Main CPU Timer 0 output (TO0) to the FDC TC input. STATUS: NOT IMPLEMENTED — the TMP94C241 MAME CPU core does not expose timer output callbacks (no to0_write devcb). Without TC, FDC Read Data commands hang indefinitely because upd765::tc_done is never set. Implementing this requires adding timer output callback support to the TMP94C241 CPU device, then wiring m_maincpu->to0_write().set(m_fdc, FUNC(upd72067_device::tc_line_w)) in the machine configuration.


Last updated: March 2026