amiga-bootcamp/10_devices/trackdisk.md
Ilia Sharin da9e7d3b63 Phase 1: enrich 07_dos and 10_devices (highest FPGA priority)
07_dos:
- file_io.md: 108→240+ lines — buffered I/O (FRead/FWrite/SetVBuf),
  access mode comparison, FileHandle struct with offsets, standard
  handles, Printf %ld warning, FileInfoBlock, practical patterns
  (copy file, get size, load to RAM), error code table
- filesystem.md: 91→270+ lines — full disk geometry (ADF/HDF),
  all 8 DOS\x filesystem IDs, root block byte-level layout, file
  header layout with reverse-order pointer quirk, OFS vs FFS data
  blocks with efficiency numbers, bitmap blocks, extension blocks,
  checksum algorithm, Python ADF reader
- locks_examine.md: 113→270+ lines — lock semantics diagram, FileLock
  struct with handler discovery, ExAll bulk scan, practical patterns
  (atomic write, path resolution, volume info), 4 antipatterns
  (leaked locks, exclusive too long, unchecked IoErr, DupLock),
  pattern matching

10_devices:
- audio.md: 73→240+ lines — hardware architecture diagram, channel
  registers with offsets, period/frequency table, priority allocation,
  double-buffering, audio interrupts, AM/PM modulation, direct HW
- timer.md: 80→230+ lines — CIA timer hardware, all 5 units with
  decision flowchart, non-blocking delays, signal-based waiting,
  time arithmetic, ReadEClock, periodic game loop pattern, pitfalls
- trackdisk.md: 82→210+ lines — MFM encoding, track format, disk
  geometry, read/write/motor, change notification, track caching,
  direct hardware access, FPGA timing implications
- keyboard.md: 58→220+ lines — CIA-A serial handshake protocol with
  sequence diagram, bit rotation quirk, complete key code map,
  key matrix bitmap, reset sequence, FPGA notes
2026-04-23 20:23:50 -04:00

178 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[← Home](../README.md) · [Devices](README.md)
# trackdisk.device — Floppy Disk DMA Controller
## Overview
`trackdisk.device` interfaces with the Amiga's floppy disk controller — a custom DMA engine that reads and writes raw MFM-encoded data from double-density 3.5" disks. It provides block-level access (512 bytes/sector, 11 sectors/track, 80 tracks × 2 sides = 1,760 sectors = 880 KB per disk).
---
## Hardware Architecture
```mermaid
graph LR
subgraph "Custom Chips"
DSKBYTR["DSKBYTR<br/>$DFF01A<br/>Disk Data Byte"]
DSKLEN["DSKLEN<br/>$DFF024<br/>DMA Length"]
DSKPT["DSKPT<br/>$DFF020<br/>DMA Pointer"]
end
subgraph "CIA-B"
CIAPRB["PRA/PRB<br/>$BFD100<br/>Motor, Side, Step"]
end
DISK["3.5 DD Disk"] -->|"MFM bitstream"| DSKBYTR
CIAPRB -->|"Motor/Step/Side"| DISK
DSKPT -->|"DMA to/from"| CHIPRAM["Chip RAM Buffer<br/>(~13 KB/track)"]
```
### Disk Geometry
| Parameter | Value |
|---|---|
| Tracks | 80 (079) |
| Sides | 2 (0=upper, 1=lower) |
| Sectors per track | 11 (DD), 22 (HD) |
| Bytes per sector | 512 |
| Total capacity | 880 KB (DD), 1,760 KB (HD) |
| Rotation speed | 300 RPM (1 revolution = 200 ms) |
| Transfer rate | ~250 kbit/s (DD raw MFM) |
| Track-to-track seek | ~3 ms |
### MFM Encoding
The disk stores data in **Modified Frequency Modulation** format. Each byte becomes 16 bits on disk (clock + data interleaved):
```
Data bit: 1 0 1 1 0 0 0 1
MFM: 01 10 01 01 10 10 10 01
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
c/d pairs (clock bit inserted before each data bit)
```
A raw track is ~12,668 bytes of MFM data (including gaps, sync words, and sector headers).
### Track Format (AmigaDOS)
```
Track = 11 sectors, each containing:
Sync: $4489 $4489 (2 words — MFM-encoded $A1 $A1)
Header: format, track, sector, sectors_to_gap (MFM-encoded)
Header checksum: XOR of header longs
Data: 512 bytes of payload (MFM-encoded = 1024 bytes on disk)
Data checksum: XOR of data longs
Gaps between sectors: variable-length padding
```
---
## Using trackdisk.device
### Opening
```c
struct MsgPort *diskPort = CreateMsgPort();
struct IOExtTD *diskReq = (struct IOExtTD *)
CreateIORequest(diskPort, sizeof(struct IOExtTD));
/* Unit numbers: DF0:=0, DF1:=1, DF2:=2, DF3:=3 */
BYTE err = OpenDevice("trackdisk.device", 0,
(struct IORequest *)diskReq, 0);
```
### Reading Sectors
```c
UBYTE *buf = AllocMem(512, MEMF_CHIP); /* MUST be Chip RAM */
diskReq->iotd_Req.io_Command = CMD_READ;
diskReq->iotd_Req.io_Data = buf;
diskReq->iotd_Req.io_Length = 512; /* bytes to read */
diskReq->iotd_Req.io_Offset = 0; /* byte offset on disk */
/* offset = (track * 2 + side) * 11 * 512 + sector * 512 */
DoIO((struct IORequest *)diskReq);
```
### Writing + Updating (Motor Control)
```c
/* Write a sector: */
diskReq->iotd_Req.io_Command = CMD_WRITE;
diskReq->iotd_Req.io_Data = buf;
diskReq->iotd_Req.io_Length = 512;
diskReq->iotd_Req.io_Offset = 512 * 10; /* sector 10 */
DoIO((struct IORequest *)diskReq);
/* Flush write buffer to disk: */
diskReq->iotd_Req.io_Command = CMD_UPDATE;
DoIO((struct IORequest *)diskReq);
/* Turn off motor when done: */
diskReq->iotd_Req.io_Command = TD_MOTOR;
diskReq->iotd_Req.io_Length = 0; /* 0=off, 1=on */
DoIO((struct IORequest *)diskReq);
```
### Disk Change Notification
```c
/* Wait for disk insertion/removal: */
diskReq->iotd_Req.io_Command = TD_CHANGENUM;
DoIO((struct IORequest *)diskReq);
ULONG changeCount = diskReq->iotd_Req.io_Actual;
/* Async notification: */
diskReq->iotd_Req.io_Command = TD_ADDCHANGEINT;
diskReq->iotd_Req.io_Data = (APTR)&myInterrupt;
SendIO((struct IORequest *)diskReq);
/* myInterrupt is signalled on disk change */
```
### Track Caching
trackdisk.device reads an **entire track** (11 sectors) into an internal buffer on each access. Subsequent reads of other sectors on the same track are served from cache:
```
Read sector 0 → DMA reads track 0 (11 sectors) → cache hit for sectors 110
Read sector 11 → new track → DMA reads track 1
Read sector 5 → cache hit (still in track 0 buffer)
```
> **FPGA implication**: the MiSTer core must emulate this whole-track DMA behaviour for correct timing. Games that measure seek+read latency will behave incorrectly if only single sectors are transferred.
---
## Direct Hardware Access (Games/Demos)
Games often bypass trackdisk.device for speed and copy protection:
```asm
; Direct floppy read — raw track DMA:
LEA $DFF000, A5 ; custom base
MOVE.L #TrackBuffer, $20(A5) ; DSKPT — DMA pointer (Chip RAM)
MOVE.W #$8210, $96(A5) ; DMACON — enable disk DMA
; Select drive, side, seek to track:
MOVE.B #$F7, $BFD100 ; CIA-B PRB — select DF0, motor on
; ... step head to desired track ...
; Start reading one track:
MOVE.W #$8000|6300, $24(A5) ; DSKLEN — enable, ~6300 words
MOVE.W #$8000|6300, $24(A5) ; write twice to start DMA
; Wait for DMA complete (DSKBLK interrupt):
BTST #1, $DFF01F ; INTREQR — DSKBLK bit
BEQ.S .-4
```
---
## References
- NDK39: `devices/trackdisk.h`, `resources/disk.h`
- HRM: *Amiga Hardware Reference Manual* — Disk Controller chapter
- ADCD 2.1: trackdisk.device autodocs
- See also: [filesystem.md](../07_dos/filesystem.md) — FFS/OFS block format on top of trackdisk