Loading System
The longest chapter — from "FILE OP ERROR" to the OS actually running in RAM. This is the story of ten discoveries that finally got the ASR-10 to load its operating system.
1. The DOC Eureka
We had been stuck for days. The firmware entered an infinite loop during ES5506 DOC initialization and nothing we tried could break it. The loop was tight: read the voice select register at FC207F, mask it with AND #$1F, test with BEQ, branch back. It was waiting for bits 0–4 to be zero — meaning "no voice active, DOC idle."
Our mock was returning the last value written to the register. That value always had non-zero bits in the lower 5 positions, so the firmware looped forever. The fix was one line: make FC207F return 0x00 (idle) regardless of what was written. The DOC voice select register is a write-to-select, read-for-status register — and the status the firmware wants is "idle."
; ES5506 DOC init -- voice select polling[FFFXXXXX] MOVE.B ($FC207F), D0 ; read voice select status[FFFXXXXX] AND.B #$1F, D0 ; mask bits 0-4[FFFXXXXX] BEQ.S continue ; if zero: DOC idle, proceed[FFFXXXXX] BRA.S *-8 ; else: loop forever; Fix: FC207F read returns 0x00 (idle)DOC voice select: write=select, read=0x00 (idle)Init loop broken. Firmware proceeds.2. 15 MB of Missing RAM
With the DOC loop broken, the firmware ran further than ever before — and hit a new wall. It was writing to addresses 0x408000, 0x808000, and 0xC08000, then reading them back and failing validation. We had mapped these as peripheral registers. They weren't.
They were sample RAM banks. The ASR-10 supports up to 16 MB of sample memory in four 4 MB banks. Our emulator only had 2 MB configured. The firmware's memory test writes a pattern to each bank, reads it back, and calculates available memory. With only Bank 0 responding, the test reported 2 MB and the subsequent init code crashed trying to use addresses it expected to be valid.
Expanding from 2 MB to 16 MB — four banks at 0x008000, 0x408000, 0x808000, 0xC08000 — let the memory test pass cleanly. The firmware counted all four banks, reported 16 MB available, and continued initialization as if this were a fully loaded machine.
3. The Complete Boot
With these two fixes — DOC idle status and full RAM — something remarkable happened. The firmware booted completely, without any ROM patches, through the entire initialization sequence. Every LCD message appeared in order, exactly as it would on real hardware.
ENSONIQ ASR-10 ; splash screen SCSI INSTALLED ; SCSI controller detectedSEARCHING FOR SCSI DEV; scanning SCSI bus PLEASE INSERT DISK ; waiting for floppyThe real ASR-10 boot sequence, running in software for the first time. No hacks, no bypasses. The firmware was asking for a disk because it had finished everything else — hardware init, memory test, SCSI scan — and was ready to load the operating system.
4. FDC Unmasked
To load the OS, we needed a floppy disk controller. We had been mocking an ES5510 DSP at address FC3000 — but something didn't add up. The firmware was writing command sequences to that address range that looked nothing like DSP operations. They looked like disk controller commands: seek, read sector, sense interrupt status.
The ASR-10 service manual confirmed it. Address FC3000 is the NEC uPD72069 Floppy Disk Controller, not the ES5510 DSP. Our ES5510 mock had been silently absorbing FDC commands the entire time, returning benign values that let init pass but couldn't actually read sectors. The real ES5510 DSP address remains unknown — possibly at a different base that the firmware only accesses after loading the OS.
The FDC identity swap was a lesson in assumptions. We named the mock based on what we expected at that address, not on what the firmware was actually doing with it. The I/O traces had been telling us "floppy controller" all along — we just weren't reading them correctly.
5. The Interrupt Controller
A floppy disk controller doesn't just accept commands — it interrupts the CPU when operations complete. The ASR-10 firmware relies on interrupts for everything: FDC completion, disk change detection, DUART serial events. We had to build a proper interrupt system.
We built irq.h: installed the vector table from ROM[0x2000] into RAM, implemented Musashi's interrupt acknowledge callback, and mapped the three critical vectors. After initialization, the firmware sets IPL=3 in the status register, accepting interrupt levels 4 and above.
VectorIRQSourceVec 75L6FDC command complete (uPD72069)Vec 77L6Disk change / media detectVec 86L4DUART (68681) serial eventPost-init SR = 0x2300 (IPL=3, accepts L4+)Vector table: ROM[0x2000] -> RAM[0x0000]6. $049D: The One Variable
Every disk operation in the ASR-10 firmware flows through a single byte at RAM address $049D. After the FDC completes a read, the firmware sets this byte to a result code. Then a message lookup routine at FFFB8EC2 traverses a table of 18 entries — each 6 bytes: a 2-byte code and a 4-byte pointer to a string — stepping through with ADDQ.L #6 until it finds a match.
The message that appears on the LCD is entirely determined by this one variable. Every state of the boot process, every error, every success — all encoded in a single byte.
| $049D | Message | Meaning |
|---|---|---|
0xFE | ENSONIQ ASR-10 | Splash screen |
0x05 | PLEASE INSERT DISK | No disk detected |
0x01 | FILE OP ERROR | Disk read failure |
0x02 | WRONG OS VERSION | OS signature mismatch |
0x03 | NOT ENSONIQ DISK | Invalid disk format |
0xFF | LOADING SYSTEM | OS load in progress |
0x00 | (success) | Operation complete, proceed |
7. The SCC Keyboard Protocol
The firmware doesn't talk to the floppy drive directly through the FDC. Instead, it communicates through an external SCC (Serial Communications Controller) at FC4001. The SCC handles the keyboard matrix, and embedded in that protocol is the drive identification exchange.
Two bytes at $04B6 and $04B7 identify the drive. The firmware expects 0x28 and 0x06 — the ID for a Sony MPF420-1, the 3.5" HD floppy drive used in the ASR-10. The drive detection loop at FFFBB146 polls bit 0 of the SCC status register for incoming data and bit 7 as an abort flag.
; Drive detection at FFFBB146[FC4001] SCC status read ; poll bit 0 (data ready)[FC4001] SCC status read ; poll bit 7 (abort); Drive ID bytes:$04B6 = 0x28; drive type byte 1$04B7 = 0x06; drive type byte 2Drive: Sony MPF420-1 (3.5" HD)8. Ensoniq Disk Format
The Ensoniq disk format is not standard PC. Confirmed through the Giebler PDF and the HxCFloppyEmulator source code: HD format uses 20 sectors per track, 80 tracks, 2 sides, for a total of 3,200 blocks. Each block is 512 bytes. The mapping in a raw .img file is linear: block N lives at offset N×512.
The operating system occupies blocks 24 through 405 — 382 blocks, or 191 KB of code and data. This is the payload that gets loaded into RAM at address 0x0000, overwriting the vector table and everything else. The firmware knows exactly where to find it because the disk directory structure at blocks 2–23 describes the layout.
9. The Validation Gauntlet
Reading the OS blocks from disk is not enough. Before the firmware accepts the data, it runs four validation checks. Each one was a puzzle, requiring the correct data at the right RAM address at the right time.
- Bytes per block at
$0B40must equal0x0200(512) — confirming the disk format is correct. - "OS" signature at
$0542— the two ASCII bytes0x4F 0x53marking this as an operating system image. - "DR" signature at
$0942— the directory marker0x44 0x52confirming the directory structure. - Directory entry at
$0544— a valid entry in the file allocation table pointing to the OS blocks.
Fail any one of these and the firmware sets $049D to an error code: WRONG OS VERSION, NOT ENSONIQ DISK, or FILE OP ERROR. The LCD tells you exactly which check failed, if you know the mapping.
10. OS LOADED
All four checks pass. The firmware begins the bulk read: 191 KB copied from disk blocks 24–405 into RAM at address 0x0000. The LCD displays "LOADING SYSTEM" while sectors stream in. Then the FDC goes quiet.
; Disk read sequenceREAD sector 36 x18; directory scanREAD sector 14 x3; FAT / allocation tableREAD sector 8 x37; OS blocks (first batch)VALIDATE block 2; signature checkREAD sector 1024 x40; OS blocks (bulk transfer); Total: 382 blocks = 195,584 bytes191 KB loaded into RAM at 0x0000 Then the firmware executes the most important instruction of the entire boot: JMP FFF87E5C. This ROM routine loads a new stack pointer from RAM[0x0000] — the first four bytes of the freshly loaded OS — and jumps into the OS code. The ROM has handed control to the operating system.
The Second Splash
And then the LCD flickered. The old splash screen — the one the ROM had displayed during init — was replaced by a new one. The same words, but sent by different code. The first "ENSONIQ ASR-10" came from the ROM. The second comes from the OS running in RAM.
Two identical messages, two completely different origins. The first is hardcoded in the ROM at a fixed string address. The second is generated by the operating system after it initializes its own display routines. The OS has taken over.
── ROM phase ── ENSONIQ ASR-10 ; ROM splash SCSI INSTALLED ; SCSI controller detectedSEARCHING FOR SCSI DEV; scanning SCSI bus PLEASE INSERT DISK ; waiting for floppy LOADING SYSTEM ; reading 382 blocks── JMP FFF87E5C ── SP = RAM[0x0000] PC = OS entry point── OS phase ── ENSONIQ ASR-10 ; OS splash (second time) SCSI INSTALLED ; OS re-detects SCSISEARCHING FOR SCSI DEV; OS scans SCSI busAlive
The OS is running. It's re-initializing the hardware, detecting SCSI devices, and preparing to become a musical instrument. For the first time in software, the Ensoniq ASR-10 operating system is alive.
191 KB of code, loaded from a virtual floppy disk image through an emulated NEC uPD72069 FDC, validated by four signature checks, copied into RAM, and executed by a jump through ROM. The same sequence that happened millions of times on real hardware in recording studios around the world between 1994 and 2003 — now happening inside a software emulator.
Ten discoveries. Ten walls. Ten fixes. From a DOC register returning the wrong idle status to a full operating system booting and re-initializing a machine that hasn't been manufactured in nearly three decades.
The machine is alive.
This project is ongoing. The OS is loaded and running, but the journey continues: the keyboard matrix, MIDI, the ES5506 DOC for wavetable synthesis, and the still-missing ES5510 DSP for real-time effects. Each one is another layer waiting to be resurrected.
