Skip to content

Commit e1edfe4

Browse files
committed
cd bios calling convention docs
Signed-off-by: Joseph Mattiello <[email protected]>
1 parent b5379b1 commit e1edfe4

1 file changed

Lines changed: 124 additions & 0 deletions

File tree

docs/cd-bios-calling-convention.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Jaguar CD BIOS Jump Table Calling Convention
2+
3+
Reverse-engineered from the retail CD BIOS ROM (`[BIOS] Atari Jaguar CD (World).j64`),
4+
cross-referenced against the developer BIOS, CDBYPASS ROMs, and MiSTer FPGA implementation.
5+
6+
## Jump Table Layout
7+
8+
The BIOS copies an 18-entry branch table from ROM `$8084A6` to RAM `$3000`.
9+
Each entry is 6 bytes: `BRA.W <offset>` + `NOP`.
10+
11+
| Entry | Address | Name | Parameters |
12+
|-------|---------|--------------------|------------------------------------|
13+
| 0 | $3000 | CD_setup_audio_isr | A0 = GPU RAM base. Copies $E0 bytes of ISR. Sets [$3072]=0. |
14+
| 1 | $3006 | CD_wait_response | Polls BUTCH bit 13, reads DS_DATA response into D1. |
15+
| 2 | $300C | CD_wait_response2 | Same as entry 1. |
16+
| 3 | $3012 | CD_i2s_enable | D0: 0=disable, 1=enable Jerry+FIFO. |
17+
| 4 | $3018 | CD_spin_up | D1=session, D0=wait flag. DSA cmd $18nn. |
18+
| 5 | $301E | CD_stop_drive | D0=wait flag. DSA cmd $0200. |
19+
| 6 | $3024 | CD_set_volume_mute | D0=wait. DSA cmd $5100. |
20+
| 7 | $302A | CD_set_volume_max | D0=wait. DSA cmd $51FF. |
21+
| 8 | $3030 | CD_pause | D0=wait. DSA cmd $0400. |
22+
| 9 | $3036 | CD_unpause | D0=wait. DSA cmd $0500. |
23+
| 10 | $303C | **CD_read** | See below. |
24+
| 11 | $3042 | CD_fifo_disable | Clear bit 2 of I2CNTRL. |
25+
| 12 | $3048 | CD_hw_reset | DSA cmd $7001. Reset BUTCH/DSCNTRL/I2CNTRL. |
26+
| 13 | $304E | **CD_poll** | See below. |
27+
| 14 | $3054 | CD_set_dac_mode | D0=0-2. DSA cmd $70nn. |
28+
| 15 | $305A | CD_read_toc | A0 = buffer ($384 bytes). DSA cmds $03nn/$14nn. |
29+
| 16 | $3060 | CD_setup_cdrom_isr | A0 = GPU RAM base. Copies $150 bytes. Sets [$3072]=$FF. |
30+
| 17 | $3066 | CD_setup_data_isr | A0 = GPU RAM base. Copies $D4 bytes. Sets [$3072]=1. |
31+
32+
## CD_read ($303C) — Full Specification
33+
34+
### Inputs
35+
36+
| Register | Meaning |
37+
|----------|---------|
38+
| D0.L | Packed MSF seek position: `(min << 16) \| (sec << 8) \| frm`. Values are binary (NOT BCD). **Bit 31**: if set, skip hardware init, just re-seek (GPU data area already configured by prior call). |
39+
| D1.L | Sync sentinel for CD-ROM mode ISR. Stored to GPU data area [+16]. In audio mode ISR, ignored. CDBYPASS passes `$41545249` ("ATRI") for boot stub reads. Games may pass DDL markers. |
40+
| D2.L | Speed/mode parameter. Only used in CD-ROM mode ([$3072] bit 7 set). |
41+
| A0 | Destination buffer in Jaguar RAM. Internally decremented by 4 (GPU ISR pre-increments before store). |
42+
| A1 | End address (destination + byte count). Stored to GPU data area [+4]. |
43+
44+
### Behavior (bit 31 clear — full init, used by games)
45+
46+
1. Disable BUTCH IRQs, disable FIFO
47+
2. Store `A0 → GPU_DATA[+0]` (dest), `A1 → GPU_DATA[+4]` (end), `0 → GPU_DATA[+8]` (progress)
48+
3. Drain FIFO, re-enable BUTCH with IRQ
49+
4. Extract MSF from D0: min = `(D0 >> 16) & 0xFF`, sec = `(D0 >> 8) & 0xFF`, frm = `D0 & 0xFF`
50+
5. Send DSA seek commands: `$10MM`, `$11SS`, `$12FF` to DS_DATA ($DFFF0A)
51+
52+
### Behavior (bit 31 set — re-seek, used by BIOS internally)
53+
54+
Skip steps 1-3, only send DSA seek commands (step 4-5).
55+
56+
### Transfer Mechanism
57+
58+
Data arrives asynchronously via the GPU ISR:
59+
- Audio mode ISR ($3000 setup): transfers all incoming I2S data directly to RAM
60+
- **CD-ROM mode ISR ($3060 setup): scans incoming I2S data for the D1 sync sentinel, then starts transferring from that point**
61+
- Data ISR ($3066 setup): variant of audio mode
62+
63+
The ISR writes data to the destination buffer and advances the write pointer.
64+
Transfer completes when the write pointer reaches the end address (A1).
65+
66+
### Sync Sentinel Scanning (CD-ROM mode)
67+
68+
In CD-ROM mode, the GPU ISR does NOT transfer data immediately.
69+
It scans each incoming I2S word for the 32-bit pattern stored in D1.
70+
When the pattern is found, the ISR begins the actual data transfer.
71+
72+
This is how the BIOS locates specific data on disc:
73+
- The boot stub seeks to near the session-2 start
74+
- The I2S stream contains all sectors from that point forward (crossing track boundaries)
75+
- The ISR scans through potentially hundreds of sectors of boot stub / padding data
76+
- When it finds the DDL marker matching D1, it starts copying game data to RAM
77+
78+
### BIOS Internal Completion
79+
80+
The BIOS does NOT use CD_poll. It polls DSP RAM flag at `[$F1B4C8]` — the GPU ISR
81+
writes `$FFFFFFFF` there when the transfer completes, and the BIOS loops until negative.
82+
83+
## CD_poll ($304E)
84+
85+
### Inputs
86+
None.
87+
88+
### Outputs
89+
90+
| Register | Meaning |
91+
|----------|---------|
92+
| A0 | Current RAM write position (GPU ISR advances this as data arrives) |
93+
| A1 | Bytes transferred so far (from GPU data area [+8]) |
94+
95+
Boot stubs typically save the end address in A6 before calling CD_read, then poll:
96+
```
97+
.poll: JSR ($304E).w
98+
CMPA.L A6, A0 ; current position >= end?
99+
BLT .poll
100+
```
101+
102+
## CDBYPASS Boot Sequence (Reference)
103+
104+
1. `JSR $3048` — hardware reset
105+
2. `JSR $3006` — CD_init (D0=2, audio mode)
106+
3. `JSR $305A` — read TOC to $2C00
107+
4. TOC scan: find session marker (byte[4]==1), take next entry's MSF
108+
5. MSF adjustment: subtract 6 frames (pregap offset)
109+
6. `JSR $3060` — set up **CD-ROM mode ISR** (A0=$F030A4)
110+
7. First `JSR $303C` — CD_read 4096 bytes, D1="ATRI", to $6010
111+
8. Scan loaded data for "TRI " header, extract load address + length
112+
9. Second `JSR $303C` — CD_read (length) bytes of game data
113+
10. Copy to final load address, `JMP` to it
114+
115+
## Sector Data Format
116+
117+
Jaguar CD data tracks are typed as AUDIO in CUE sheets. Each sector is 2352 bytes
118+
of raw data (no Mode 1 sync/header/ECC structure). The I2S bus transfers all 2352 bytes.
119+
120+
The I2S transfer swaps bytes within 16-bit words. The GPU ISR un-swaps before writing
121+
to RAM. Data on disc (in BIN files) is stored pre-swapped.
122+
123+
MiSTer FPGA note: the ring buffer stores 2048 bytes per sector, but this is an
124+
implementation detail of the HPS interface, not a reflection of the Jaguar hardware.

0 commit comments

Comments
 (0)