HDAE5000 Hard Disk Interface
HD-AE5000 Hard Disk Interface
This page documents the low-level hard disk interface used by the HD-AE5000 expansion for the Technics KN5000 keyboard. Understanding this interface is essential for MAME emulation and homebrew development.
Overview
The HD-AE5000 uses an IDE/ATA compatible hard disk drive with direct memory-mapped registers. The ATA registers are accessible at addresses 0x130010-0x130020 from the main CPU.
A separate Intel 8255 PPI at 0x160000 provides a parallel port interface for communication with a PC running the HD-TechManager5000 software.
┌──────────────────┐ ┌──────────────────┐
│ TMP94C241F │ Direct Memory Access │ IDE Hard Disk │
│ Main CPU │<─────────────────────────>│ @ 0x130010 │
│ │ │ (ATA Registers)│
│ │ └──────────────────┘
│ │
│ │ ┌─────────────────┐
│ │<───>│ Intel 8255 │<───> PC Parallel Port
└──────────────────┘ │ PPI @ 0x160000│
└─────────────────┘
IDE/ATA Background
What is IDE/ATA?
IDE (Integrated Drive Electronics) and ATA (AT Attachment) are standards for connecting hard disk drives to computers. The HD-AE5000 uses a 2.5” laptop-style IDE drive with 1.08GB capacity, which was a substantial amount for 1996-era consumer electronics.
ATA Register Set (Firmware-Verified)
The HD-AE5000 maps ATA registers directly to memory addresses. The register layout was verified by analyzing firmware code at 0x2974DD-0x297501 and 0x2976AB-0x297883:
| Address | Register | Read | Write |
|---|---|---|---|
| 0x130010 | Data (16-bit) | Sector data | Sector data |
| 0x130012 | Error/Features | Error code | Features |
| 0x130014 | Sector Count | Sector count | Sector count |
| 0x130016 | Sector Number | Sector/LBA Low | Sector/LBA Low |
| 0x130018 | Cylinder Low | Cylinder Low/LBA Mid | Cylinder Low/LBA Mid |
| 0x13001A | Cylinder High | Cylinder High/LBA High | Cylinder High/LBA High |
| 0x13001C | Device/Head | Device/Head | Device/Head (0xA0 | head) |
| 0x13001E | Status/Command | Status | Command |
| 0x130020 | Device Control | - | Device Control |
The HD-AE5000 firmware uses CHS (Cylinder/Head/Sector) addressing, as evidenced by debug strings in the ROM:
hddtrck- Track (cylinder) counthddhead- Head counthddsctr- Sectors per trackhddscby- Bytes per sector (typically 512)
ATA Commands Used by Firmware
The following commands were identified by analyzing firmware writes to the Command Register (0x13001E):
| Command | Hex | Address | Description |
|---|---|---|---|
| Read Sectors | 0x20 | 0x29781D | Read one or more sectors (PIO mode) |
| Write Sectors | 0x30 | 0x29772B | Write one or more sectors (PIO mode) |
| Standby | 0x94 | 0x297501 | Spin down drive with timeout parameter |
| Identify Device | 0xEC | 0x2978C3 | Return 512-byte device identification block |
PPI Parallel Port Interface
Purpose
The Intel 8255 PPI at 0x160000 is NOT used for IDE communication - the IDE registers are directly memory-mapped. Instead, the PPI provides a parallel port interface for PC communication with the HD-TechManager5000 Windows software.
This allows file transfer between a PC and the HDAE5000’s hard disk via the PC’s parallel port.
PPI Port Assignments
| Address | Port | Direction | Function |
|---|---|---|---|
| 0x160000 | Port A | Bidirectional | Data byte to/from PC |
| 0x160002 | Port B | Input | Status byte from PC |
| 0x160004 | Port C | Output | Control signals to PC |
| 0x160006 | Control | Write | PPI mode configuration |
Disk Access Protocol
Based on firmware analysis at 0x2974C7-0x297924, disk access follows this pattern:
1. Wait for Drive Ready
Wait_HD_Ready (0x297438):
1. Read Status register (0x13001E)
2. Check bits: BSY=0 (bit 7), DRDY=1 (bit 6)
3. Mask with 0xC0, compare to 0x40
4. Repeat until ready or timeout (0x3FFFFF iterations)
2. Initialize Drive (0x2974C7)
Init_HD:
1. Wait for drive ready
2. Write 0xFF to Features (0x130012)
3. Write 0x00 to Sector Count (0x130014)
4. Write 0xFF to Sector/Cyl Low/Cyl High (0x130016/18/1A)
5. Write 0xA0 to Device/Head (0x13001C)
6. Write 0x94 (Standby) to Command (0x13001E)
3. Read Sectors (0x297788)
Read_Sectors:
1. Wait for drive ready (Status & 0xC0 == 0x40)
2. Write 0x01 to Sector Count (0x130014)
3. Write (0xA0 | head) to Device/Head (0x13001C)
4. Write cylinder low to 0x130018
5. Write cylinder high to 0x13001A
6. Write sector number to 0x130016
7. Write 0x20 (Read) to Command (0x13001E)
8. Wait for DRQ (Status & 0xC8 == 0x48)
9. Read 256 words from Data register (0x130010)
10. Wait for completion (Status & 0xC0 == 0x40)
11. Check error bit (Status & 0x01)
4. Write Sectors (0x29769B)
Write_Sectors:
1. Wait for drive ready
2. Write 0x01 to Sector Count (0x130014)
3. Write (0xA0 | head) to Device/Head (0x13001C)
4. Write CHS address to registers
5. Write 0x30 (Write) to Command (0x13001E)
6. Wait for DRQ
7. Write 256 words to Data register (0x130010)
8. Wait for completion
9. Check error bit
5. Identify Device (0x297884)
Identify_Device:
1. Wait for drive ready
2. Write 0xFF to all address registers
3. Write 0xA0 to Device/Head (0x13001C)
4. Write 0xEC (Identify) to Command (0x13001E)
5. Wait for DRQ
6. Read 256 words from Data register to 0x200000
7. Parse CHS geometry from identification data
6. Reset Controller (0x29747A)
Reset_HD:
1. Write 0x0E to Device Control (0x130020) - SRST + nIEN
2. Write 0x0A to Device Control (0x130020) - Clear reset, keep nIEN
3. Wait for drive ready
Error Handling
The firmware includes multilingual error messages for various disk failures:
| Error | English Message | Likely Cause |
|---|---|---|
| SRAM Error | “Hard disk SRAM error” | Cache RAM failure on HDAE5000 |
| Reset Error | “Hard disk reset error” | Controller not responding |
| Read Error | “Hard disk read error” | Bad sector or media failure |
| ID Read Error | “Hard disk ID read error” | Identify Device command failed |
| Track 0 Error | “Hard disk track 0 error” | Cannot seek to track 0 |
| FSB Error | “Hard disk FSB read error” | Filesystem block corrupted |
| FAT Error | “Hard disk FAT read error” | File allocation table corrupted |
These errors are also available in German and French translations.
Filesystem Structure
The HDAE5000 uses a custom filesystem, not FAT16 or FAT32. Key structures include:
FSB (File System Block)
The master filesystem metadata block containing:
- Volume information
- Free space tracking
- Directory pointers
FGB (File Group Block)
Groups related files together:
- File group pointer (
FGB ptr) - Group width (
FGB wid) - Number of entries (
FGB num)
FEB (File Entry Block)
Individual file metadata:
- File entry pointer (
FEB ptr) - Entry width (
FEB wid) - Number of entries (
FEB num)
PPORT Commands for Disk Operations
The PC parallel port (PPORT) protocol includes these disk-related commands:
| Code | Command | Description |
|---|---|---|
| 01 | Send Infos About HD | Report CHS parameters and model |
| 03 | Read FSB from HD | Read filesystem block |
| 04 | Send FSB to PC | Transfer FSB to PC |
| 05 | Rcv FSB from PC | Receive FSB from PC |
| 06 | Write FSB to HD | Write filesystem block |
| 07 | Load HD to Memory | Load file into KN5000 RAM |
| 08 | Send data to PC | Send data block to PC |
| 10 | Rcv data from PC | Receive data from PC |
| 11 | Save memory to HD | Save RAM contents to file |
| 16 | Delete files | Remove files from disk |
| 17 | Format HD | Low-level disk format |
| 18 | Switch HD-motor off | Spin down drive motor |
PC Parallel Port Protocol
The HD-TechManager5000 Windows software (ppkn50.dll) communicates with the HDAE5000 using a bidirectional parallel port protocol. This section documents the low-level handshaking derived from disassembly of ppkn50.dll.
Parallel Port Mode: PS/2 Bidirectional
The protocol requires PS/2 bidirectional mode (also called “byte mode”), not SPP nibble mode, EPP, or ECP.
Why not SPP nibble mode?
On a pure unidirectional SPP port, the standard way to receive data from a peripheral is nibble mode: the peripheral puts 4 bits on the status lines (base+1, bits 3–7), the PC reads them, then the peripheral sends the other 4 bits — two reads per byte through the status port.
The ppkn50.dll does not use nibble mode. The receive-byte function (at address 0x10001360 in ppkn50.dll) reads data from base+0 (the data port) via a single in (%dx), %al instruction at address 0x1000142A, after setting control bit 5 to switch the data bus direction. There is no status-port bit shifting, no two-nibble reassembly — it’s a direct 8-bit read from the data port.
Why not EPP or ECP?
EPP adds hardware-handshaked registers at base+3 (address) and base+4 (data). ECP adds DMA and FIFO registers. The ppkn50.dll never accesses any port beyond base+0, base+1, and base+2. All handshaking is software-driven (strobe/busy polling).
Evidence from ppkn50.dll binary
The send-byte and receive-byte functions explicitly switch the data port direction via control register bit 5:
Send byte (ppkn50.dll address 0x100011E0):
100011f0: ec in (%dx),%al ; read control (base+2)
100011f1: 24 5e and $0x5e,%al ; clear bit 5 (output mode) + bit 0 + bit 7
100011f3: ee out %al,(%dx) ; write control
100011f8: 8a 45 0c mov 0xc(%ebp),%al ; load data byte
100011fb: ee out %al,(%dx) ; write to data port (base+0)
Receive byte (ppkn50.dll address 0x10001360):
10001372: ec in (%dx),%al ; read control (base+2)
10001373: 0c a1 or $0xa1,%al ; set bit 5 (input mode) + bit 0 + bit 7
10001375: ee out %al,(%dx) ; write control
; ... poll status bit 7, wait for data ready ...
1000142a: ec in (%dx),%al ; read data port (base+0)
The AND $0x5E clears bit 5 (switch to output), the OR $0xA1 sets bit 5 (switch to input). This is the defining characteristic of PS/2 bidirectional mode. A pure SPP port ignores bit 5, and reading base+0 returns the output latch — which would corrupt received data.
Direction switching summary:
| Control bit 5 | Data port (base+0) | Operation |
|---|---|---|
| 0 (cleared) | Output | PC writes data to HDAE5000 |
| 1 (set) | Input | PC reads data from HDAE5000 |
Compatibility: A PC with only unidirectional SPP (no PS/2 bidirectional support) will not work with TechManager5000 — data reads will return the output latch value instead of the HDAE5000’s data. The PC must have at least a PS/2-compatible parallel port (standard on PCs from 1987 onwards).
MAME emulation note: MAME’s pc_lpt_device required a fix to support PS/2 bidirectional mode. The original data_r() implementation always returned m_data & peripheral_data (SPP pull-up behavior), which masks out peripheral data bits wherever the output latch has zeros. For example, after sending byte 0x01 and switching to input mode, only bit 0 of the peripheral’s response would be visible. The fix (March 2026, branch kn5000_research_techmanager) checks the inverted control bit 5 and returns pure peripheral data when bidirectional mode is active.
Physical Interface
PC Parallel Port (PS/2 Bidirectional):
| Port Address | Register | Direction | Function |
|---|---|---|---|
| base+0 (0x378) | Data | Bidirectional | 8-bit data byte (direction controlled by ctrl bit 5) |
| base+1 (0x379) | Status | Input | Status signals from HDAE5000 |
| base+2 (0x37A) | Control | Output | Control signals to HDAE5000 (bit 5 = direction) |
HDAE5000 PPI (Intel 8255 at 0x160000):
| Address | Port | Direction | Function |
|---|---|---|---|
| 0x160000 | Port A | Bidirectional | Data byte to/from PC |
| 0x160002 | Port B | Input | Status from PC |
| 0x160004 | Port C | Output | Control signals to PC |
Status Port Bits (base+1)
| Bit | Name | Description |
|---|---|---|
| 7 | BUSY | Inverted; 0=HDAE5000 busy, 1=ready |
| 6 | ACK | Acknowledge signal |
| 4 | SELECT | HDAE5000 online indicator |
| 3 | ERROR | Error condition |
Note: Bit 7 (BUSY) is inverted in hardware by the PC parallel port. The ppkn50.dll XORs with 0x80 after reading to compensate.
Control Port Bits (base+2)
| Bit | Name | Description |
|---|---|---|
| 3 | SELECT_IN | Select printer |
| 2 | INIT | Initialize/reset |
| 1 | AUTOFEED | Strobe acknowledge |
| 0 | STROBE | Data strobe signal |
Byte Transfer Handshaking
Send Byte to HDAE5000:
PC HDAE5000
| |
|-- Write Data to Data Port -->|
|-- Assert Strobe (bit 1) ---->|
| |
|<---- BUSY goes LOW ----------| (data received)
| |
|-- Deassert Strobe ---------->|
| |
|<---- BUSY goes HIGH ---------| (ready for next)
Receive Byte from HDAE5000:
PC HDAE5000
| |
|<---- BUSY goes LOW ----------| (data available)
| |
|-- Read Data from Data Port --|
|-- Assert ACK (bit 1) ------->|
| |
|<---- BUSY goes HIGH ---------| (acknowledged)
| |
|-- Deassert ACK ------------->|
Timeout Values
- Byte transfer timeout: 10,000ms (0x2710)
- Polling iterations: 512 before time check
- Connection test retries: 5 times with 1000ms delay
Error Codes (from ppkn50.dll)
| Code | Meaning |
|---|---|
| 0 | Success |
| -1 | DLL not initialized |
| -2 | Port not open / connection failed |
| -3 | Handshake timeout |
| -4 | Transfer error |
| -5 | Port busy |
| -10 | Escape pressed |
| -20 | Invalid port number |
DLL Exported Functions
The ppkn50.dll exports these functions for PC applications:
| Function | Command | Description |
|---|---|---|
InitializeTheDllPP50 |
- | Initialize DLL |
OpenThePortNumberPP50 |
- | Select LPT port (1-3) |
CloseThePortPP50 |
- | Close parallel port |
TestTheKNPPPP50 |
0x01 | Test connection |
ReadFsbFromKnHdToKnMemPP50 |
0x03 | Read FSB from HD |
SendFsbFromKnMemToPCPP50 |
0x04 | Transfer FSB to PC |
SendFsbFromPCToKnMemPP50 |
0x05 | Transfer FSB to KN |
LoadFileFromKnHdToKnMemPP50 |
0x07 | Load file HD→KN |
DeleteFileOnKnHdPP50 |
0x16 | Delete file |
FormatTheKn50HardDiskPP50 |
0x17 | Format HD |
TurnOffTheKn50HdMotorPP50 |
0x18 | Spin down motor |
RAM Variables
Key RAM locations used by disk routines:
| Address | Name | Purpose |
|---|---|---|
| 0x229D90 | HD_STATUS_FLAG | Current drive status |
| 0x229D92 | HD_RESULT_FLAG | Last operation result |
| 0x229D99-0x229DAE | HD_CONFIG | Drive configuration flags |
| 0x229DC8 | HD_CONTROL | Control register shadow |
| 0x229DD9 | HD_ENABLE | Drive enabled flag |
| 0x230EDA | HDAE5000_INIT_FLAG | 0=no HD, non-zero=HD present |
Design Considerations
Why CHS Instead of LBA?
The HDAE5000 uses CHS (Cylinder/Head/Sector) addressing rather than the newer LBA (Logical Block Addressing). This was common for drives of this era (1996) and provides:
- Direct physical addressing
- Compatibility with older drive firmware
- Simpler sector calculation
Drive Protection
The firmware includes protective features:
- Motor timeout: Spins down drive during inactivity
- No real-time playback: Files must be loaded to RAM first
- Verification: Reads back written data to confirm
Sector Size
Standard 512-byte sectors are used, as indicated by the hddscby (sector bytes) debug string.
Emulation Considerations
For MAME emulation, the HDAE5000 disk interface requires:
- Direct ATA Register Mapping: ATA registers at 0x130010-0x130020
- Data register (16-bit): 0x130010
- Command block registers (8-bit): 0x130012-0x13001E
- Device Control (8-bit): 0x130020
- PPI Emulation: Full 8255 PPI at 0x160000 for PC communication (not for IDE)
- IDE Drive Model: CHS-addressed IDE drive simulation
- Status Bits: Proper BSY/DRDY/DRQ/ERR flag handling
- PIO Mode: All transfers are PIO (no DMA observed)
- Custom Filesystem: FSB/FGB/FEB structure parsing
Verified Implementation Details
The following details were confirmed through firmware analysis:
- Base Address: ATA registers start at 0x130010, not 0x130000
- Transfer Mode: All data transfers use PIO mode via 16-bit Data register
- Sector Size: 512 bytes (256 word transfers)
- Addressing: CHS mode only (no LBA observed)
- Timeout: Drive ready timeout uses 0x3FFFFF (~4M) iteration loop
- Status Polling: Firmware polls Status register in tight loops (no interrupts)
Further Research
Areas requiring additional investigation:
- Filesystem structure details (FSB/FGB/FEB layout)
- Error recovery procedures
- Exact timing requirements for real hardware
Completed:
- PC parallel port protocol details (documented above from ppkn50.dll analysis)
Related Documentation
- HDAE5000 Overview - Firmware and initialization
- Memory Map - Address space layout
- Hardware Architecture - System overview
References
- ATA/ATAPI-4 Specification (T13/1153D)
- Intel 8255A PPI Datasheet
- HDAE5000 ROM disassembly analysis
- ppkn50.dll disassembly (HD-TechManager5000 parallel port DLL)