REFORGE

1998 / PUBLIC DOSSIER

Sega Dreamcast

A chaptered hardware reference with research coverage, visible citation status, and a separate production record.

CHAPTERS
9
PRODUCTION RECORD
NOT STARTED
SOURCE STATUS
EXTERNAL REFERENCES LINKED

The Dreamcast's architecture pairs a 200 MHz Hitachi SH-4 superscalar CPU with a NEC/VideoLogic PowerVR CLX2 tile-based GPU (embedded in the Holly ASIC), a Yamaha AICA sound processor running an independent ARM7DI core, and a proprietary GD-ROM drive—all interconnected through Holly's system bus. This reference documents every subsystem at the register and instruction level needed to build a static recompilation engine: hex addresses, binary encodings, bit layouts, and data formats.

The Dreamcast uses a 29-bit physical address space divided into eight 64MB areas, with the upper 3 bits of the 32-bit logical address controlling cache behavior and privilege. The MMU is disabled in normal operation, so logical-to-physical mapping is fixed. Every hardware register documented below uses P2 uncached addresses (prefix 0xA0000000) unless noted otherwise.

CHAPTER 01

SH-4 CPU: instruction set, registers, and pipeline

The SH-4 (SH7091 variant at 200 MHz) is a 32-bit RISC processor with fixed 16-bit instruction encoding, a hardware FPU with vector extensions, and 2-way superscalar issue. It is the sole processor responsible for all game logic and 3D math—the PowerVR GPU performs no vertex transformation.

Register file

General-purpose registers (32-bit): R0–R15, where R0 has special roles in indexed addressing and some immediate-mode instructions. R15 is conventionally the stack pointer. R0–R7 are banked: two physical sets (BANK0 and BANK1) are selected by SR.RB, enabling fast exception entry without register saves.

Floating-point registers (32 physical banks of 16): FR0–FR15 (single-precision, active bank), XF0–XF15 (extended bank, the other bank). The FPSCR.FR bit swaps which physical bank is "front" (FR) vs. "back" (XF). Double-precision pairs: DR0 = {FR0,FR1}, DR2 = {FR2,FR3}, … DR14 = {FR14,FR15}. Four-component vectors: FV0 = {FR0–FR3}, FV4 = {FR4–FR7}, FV8 = {FR8–FR11}, FV12 = {FR12–FR15}. The back-bank matrix register XMTRX is a 4×4 matrix laid out column-major: column 0 = {XF0–XF3}, column 1 = {XF4–XF7}, column 2 = {XF8–XF11}, column 3 = {XF12–XF15}.

Control/system registers:

RegisterPurpose
SRStatus register (T, S, IMASK, Q, M, FD, BL, RB, MD bits)
GBRGlobal base register for GBR-based addressing
VBRVector base register for exception handler addresses
MACH/MACLMultiply-accumulate high/low (64-bit MAC result)
PRProcedure register (return address for BSR/JSR/BSRF)
PCProgram counter
SSR/SPCSaved SR and saved PC on exception entry
SGRSaved R15 on exception entry
DBRDebug base register
FPSCRFPU status/control (FR, SZ, PR, DN, cause/enable/flag, RM)
FPULFPU communication register (integer↔float transfers)

SR bit layout (reset value 0x700000F0)bit 0 = T (true/false condition), bit 1 = S (MAC saturation), bits 4–7 = IMASK (interrupt mask level 0–15), bit 8 = Q, bit 9 = M (divide step state), bit 12 = FD (FPU disable), bit 28 = BL (exception block), bit 29 = RB (register bank select), bit 30 = MD (0=user, 1=privileged).

FPSCR bit layout (reset value 0x00040001)bits 0–1 = RM (00=round-nearest, 01=round-zero), bits 2–6 = Flag (I,U,O,Z,V sticky), bits 7–11 = Enable (I,U,O,Z,V), bits 12–17 = Cause (I,U,O,Z,V,E—cleared before each FPU op), bit 18 = DN (denorm-as-zero), bit 19 = PR (0=single, 1=double), bit 20 = SZ (FMOV transfer size, 0=32-bit, 1=64-bit pair), bit 21 = FR (FP bank select). The combination SZ=1 + PR=1 is reserved and must never be set.

Instruction set architecture

All instructions are 16 bits wide. Fields commonly encode nnnn (destination register 0–15), mmmm (source register), dddddddd (displacement), iiiiiiii (immediate). The instruction set spans these categories:

Data transfer: MOV Rm,Rn (0110nnnnmmmm0011), MOV #imm,Rn (1110nnnniiiiiiii), MOV.B/W/L with all addressing modes (register indirect, pre-decrement @-Rn, post-increment @Rn+, indexed @(R0,Rn), displacement @(disp,Rn), GBR-based @(disp,GBR), PC-relative @(disp,PC)), MOVA (11000111dddddddd), MOVT, SWAP.B/W, XTRCT, LDS/STS (to/from FPUL, FPSCR, MACH, MACL, PR), LDC/STC (to/from SR, GBR, VBR, SSR, SPC, DBR, SGR, Rn_BANK).

Arithmetic: ADD, ADDC, ADDV, SUB, SUBC, SUBV, NEG, NEGC, MUL.L, MULS.W, MULU.W, DMULS.L, DMULU.L, MAC.L, MAC.W, DT (decrement-and-test), DIV0S, DIV0U, DIV1, CMP/EQ, CMP/GE, CMP/GT, CMP/HI, CMP/HS, CMP/PL, CMP/PZ, CMP/STR, CMP/EQ #imm, EXTS.B/W, EXTU.B/W.

Logic: AND, OR, XOR, TST, NOT—plus @(R0,GBR) variants for AND.B, OR.B, TST.B, XOR.B.

Shift: ROTL, ROTR, ROTCL, ROTCR, SHAL, SHAR, SHLL/SHLR (1/2/8/16), SHAD Rm,Rn (0100nnnnmmmm1100—arithmetic dynamic shift, new in SH-3/4), SHLD Rm,Rn (0100nnnnmmmm1101—logical dynamic shift, new in SH-3/4).

Branch: BF (10001011dddddddd), BT (10001001dddddddd), BF/S and BT/S (with delay slot), BRA (1010dddddddddddd), BSR, BRAF Rm (0000mmmm00100011—PC-relative far branch via register, new vs SH-1), BSRF Rm (0000mmmm00000011), JMP @Rm, JSR @Rm, RTS, RTE (0000000000101011). All unconditional branches and JMP/JSR/RTS/RTE have delay slots.

System: NOP, SLEEP, CLRT, SETT, CLRS, SETS, CLRMAC, TRAPA #imm (11000011iiiiiiii), LDTLB (0000000000111000—load TLB entry from PTEH/PTEL, new in SH-3/4).

Floating-point instructions (all new vs SH-2)

The SH-2 has no FPU. Every FP instruction below is an SH-4 addition. All FP opcodes begin with 1111 in bits [15:12].

InstructionEncodingOperationLatency
FADD FRm,FRn1111nnnnmmmm0000FRn + FRm → FRn3 (SP) / 8 (DP)
FSUB FRm,FRn1111nnnnmmmm0001FRn − FRm → FRn3 / 8
FMUL FRm,FRn1111nnnnmmmm0010FRn × FRm → FRn3 / 8
FDIV FRm,FRn1111nnnnmmmm0011FRn ÷ FRm → FRn10 / 23
FMAC FR0,FRm,FRn1111nnnnmmmm1110FR0×FRm + FRn → FRn3 (SP only)
FCMP/EQ FRm,FRn1111nnnnmmmm0100(FRn==FRm) → T2
FCMP/GT FRm,FRn1111nnnnmmmm0101(FRn>FRm) → T2
FABS FRn1111nnnn01011101FRn→ FRn0
FNEG FRn1111nnnn01001101−FRn → FRn0
FSQRT FRn1111nnnn01101101√FRn → FRn10 / 23
FLOAT FPUL,FRn1111nnnn00101101int(FPUL) → float(FRn)3
FTRC FRn,FPUL1111nnnn00111101trunc(FRn) → int(FPUL)3
FCNVDS DRm,FPUL1111mmm010111101double→single (PR=1)3
FCNVSD FPUL,DRn1111nnn010101101single→double (PR=1)3
FLDS FRm,FPUL1111mmmm00011101FRm → FPUL0
FSTS FPUL,FRn1111nnnn00001101FPUL → FRn0
FLDI0 FRn1111nnnn100011010.0f → FRn0
FLDI1 FRn1111nnnn100111011.0f → FRn0
FIPR FVm,FVn1111nnmm111011014D dot product → FR[n+3]4 (pitch 1)
FTRV XMTRX,FVn1111nn01111111014×4 matrix × vector → FVn7 (pitch 4)
FRCHG1111101111111101Toggle FPSCR.FR (bank swap)1
FSCHG1111001111111101Toggle FPSCR.SZ (transfer size)1
FSRRA FRn1111nnnn011111011/√FRn → FRn (approx)1
FSCA FPUL,DRn1111nnn011111101sin/cos(FPUL) → DR (16-bit fixed angle)3

FMAC is the cornerstone single-precision multiply-accumulate: FR0 × FRm + FRn → FRn with full 28-bit internal precision. FIPR computes a 4-component inner product in 4 cycles. FTRV multiplies XMTRX (the back-bank 4×4 matrix) by FVn in 7 cycles—this is the critical instruction for vertex transformation. FSRRA and FSCA are technically SH-4A instructions but are present on the Dreamcast's SH7091 silicon and widely used by games.

Cache control and other SH-4 additions over SH-2

Beyond the entire FPU, these instructions are new to SH-4

  • PREF @Rn (0000nnnn10000011) — Prefetch 32-byte cache line to operand cache
  • OCBI @Rn (0000nnnn10010011) — Operand cache block invalidate
  • OCBP @Rn (0000nnnn10100011) — OC block purge (writeback + invalidate)
  • OCBWB @Rn (0000nnnn10110011) — OC block writeback (keep valid)
  • MOVCA.L R0,@Rn (0000nnnn11000011) — Move with cache block allocate (no read-fill)
  • SHAD/SHLD — Dynamic shift by register amount (SH-3/4)
  • BRAF/BSRF — PC-relative far branches (added SH-2, absent in SH-1)
  • LDTLB — Load TLB from PTEH/PTEL/PTEA

Addressing modes

ModeSyntaxAccess sizesNotes
Register directRnSource/dest is register value
Register indirect@RnB/W/LEA = Rn
Post-increment@Rn+B/W/LEA = Rn, then Rn += size
Pre-decrement@-RnB/W/LRn -= size, then EA = Rn
Displacement@(disp,Rn)B(4-bit)/W(4-bit×2)/L(4-bit×4)R0-only for B/W
Indexed@(R0,Rn)B/W/LEA = R0 + Rn
GBR+disp@(disp,GBR)B(8-bit)/W(×2)/L(×4)R0-only dest for loads
PC-relative@(disp,PC)W(8-bit×2)/L(8-bit×4)For loading constants
Immediate#imm8-bit signed (MOV), 8-bit (logic)Zero-extended for logic ops

Superscalar pipeline

The SH-4 has a 5-stage pipeline (IF → ID → EX → MA → WB) and can dual-issue by classifying instructions into groups: MT (move/trivial—can pair with anything), EX (execute-stage ALU), LS (load/store), FE (FP execute), BR (branch), CO (co-issue prohibited—always single-issue). Two instructions from different groups can issue together. CO-group instructions (LDC, STC, LDS, STS, TRAPA, RTE, SLEEP, MAC.L, MAC.W) always execute alone.

Memory-mapped control registers (P4 area, 0xFFxxxxxx)

AddressRegisterDescription
0xFF000000PTEHPage table entry high (TLB)
0xFF000004PTELPage table entry low
0xFF000008TTBTranslation table base
0xFF00000CTEATLB exception address
0xFF000010MMUCRMMU control register
0xFF000014BASRABreak ASID A (UBC)
0xFF000018BASRBBreak ASID B
0xFF00001CCCRCache control register
0xFF000020TRATRAPA exception register (bits [9:2] = imm8)
0xFF000024EXPEVTException event code (12-bit)
0xFF000028INTEVTInterrupt event code (12-bit)
0xFF000030PTEAPage table entry assistance
0xFF000034QACR0Store queue address control 0
0xFF000038QACR0(correction: QACR0 at 0x38)
0xFF00003CQACR1Store queue address control 1

CCR (0xFF00001C) bit layoutbit 0 = OCE (OC enable), bit 1 = WT (write-through), bit 2 = CB (copy-back P1), bit 3 = OCI (OC invalidate), bit 5 = ORA (OC-as-RAM enable for 8KB+8KB split), bit 7 = OIX (OC index mode), bit 8 = ICE (IC enable), bit 11 = ICI (IC invalidate), bit 15 = IIX (IC index mode).

Store queues at 0xE0000000–0xE3FFFFFFtwo 32-byte buffers (SQ0 at bit[5]=0, SQ1 at bit[5]=1). Filled with MOV.L writes, flushed via PREF @Rn. Upper physical address bits come from QACR0/QACR1. Critical for burst-writing display lists to the TA FIFO.

Exception handling

Exception entrySR→SSR, PC→SPC, R15→SGR, set SR.MD=1, SR.RB=1, SR.BL=1, write exception code to EXPEVT or INTEVT, branch to VBR + offset. Offsets: +0x100 for general exceptions, +0x400 for TLB miss, +0x600 for interrupts. Reset vectors are fixed at 0xA0000000 (power-on) and 0xA0000020 (manual). Key EXPEVT codes: 0x040/0x060 = TLB miss read/write, 0x0E0/0x100 = address error read/write, 0x120 = FPU exception, 0x160 = TRAPA, 0x180 = illegal instruction, 0x800 = FPU disable.

CHAPTER 02

PowerVR CLX2 (Holly): tile-based deferred rendering

How TBDR works

Unlike immediate-mode renderers that process triangles in submission order and rely on a Z-buffer to resolve visibility (causing massive overdraw), the PowerVR divides the screen into 32×32 pixel tiles and performs per-tile hidden surface removal (HSR) before texturing. This means the texture shading processor (TSP) only processes the visible fragment per pixel—zero overdraw. The process has two asynchronous phases that can overlap across frames:

Binning phase (Tile Accelerator): The CPU submits geometry as global parameters + vertex parameters to the TA FIFO at physical address 0x10000000. The TA sorts each primitive into the tiles it overlaps, building per-tile Object Pointer Buffers (OPBs) and an Object Buffer (OB) in VRAM.

Rendering phase (ISP → TSP): Triggered by writing to STARTRENDER (0xA05F8014). For each tile: the ISP (Image Synthesis Processor) fetches the tile's primitives, performs depth testing and HSR to find the visible surface at each pixel, and the TSP (Texture Shading Processor) applies texturing, shading, and blending only to visible fragments. The completed tile is written to the framebuffer in VRAM. This per-tile architecture means the working set fits in on-chip SRAM, delivering extremely high effective fill rates.

Three rendering lists

  • Opaque (PVR_LIST_OP_POLY): Front-to-back HSR, only the nearest fragment is textured. No alpha blending. Most efficient list.
  • Translucent (PVR_LIST_TR_POLY): Supports alpha blending. The hardware performs order-independent transparency—automatically sorting translucent fragments per-pixel and blending back-to-front. Slower than opaque but avoids manual sorting.
  • Punch-through (PVR_LIST_PT_POLY): 1-bit alpha test against PT_ALPHA_REF. Pixels either fully opaque or fully discarded. Used for cutout textures (foliage, chain-link fences).

Each list also has optional modifier volume variants (opaque modifier, translucent modifier) for stencil-like per-pixel shadow effects using inclusion/exclusion volumes.

Tile Accelerator parameter format

Parameters are submitted as 32-byte aligned blocks to the TA FIFO at 0x10000000 (or 0xB0000000 via P2). Two main types:

Global parameters (32 bytes): Set polygon state for subsequent vertices. Word 0 is a parameter control word encoding: bits [31:29] = parameter type (0=end-of-list, 4=polygon/modifier, 7=vertex), bits [26:24] = list type (0=opaque, 1=opaque modifier, 2=translucent, 3=translucent modifier, 4=punch-through), bits [22:21] = group/strip control. Subsequent words contain: ISP/TSP instruction word (depth compare mode, culling, Z-write), TSP instruction word (texture filtering, UV clamp/flip, fog, alpha), texture control word (address in VRAM, format, mip, VQ, twiddled, size).

Vertex parameters (32 bytes): Position as 3 × 32-bit IEEE floats (X, Y, Z where Z is 1/W for perspective correction), packed ARGB color (32-bit), base/offset colors, UV texture coordinates (32-bit float or 16-bit packed). Bit 28 in the parameter control word signals end-of-strip (last vertex of a triangle strip).

End-of-list: A special 32-byte parameter (type field = 0) marks the end of the current polygon list.

Texture formats

FormatCodeDescription
ARGB1555016bpp, 1-bit alpha + RGB555
RGB565116bpp, no alpha
ARGB4444216bpp, 4-bit alpha + RGB444
YUV422316bpp, luminance/chroma video format
Bump map416bpp, S/R environment-mapped
4BPP palette54bpp, indexed into 1024-entry palette RAM
8BPP palette68bpp, indexed into palette RAM

Twiddled textures store pixels in Morton order (Z-order curve), interleaving U and V coordinate bits. This dramatically improves 2D spatial locality for texture cache access. All power-of-two textures should be twiddled; paletted textures are always twiddled.

VQ (Vector Quantization) compression stores a 2048-byte codebook of 256 entries, each a 2×2 texel block (4 pixels × 2 bytes at 16bpp). The image data is a twiddled array of 8-bit indices into this codebook, achieving approximately 8:1 compression for 16bpp textures. Decoded in hardware at zero performance cost.

Stride textures support non-power-of-two widths (multiples of 32, up to 992). Width is set globally via TSP_CFG register (0xA05F80E4) bits [4:0].

PVR core registers (base 0xA05F8000)

AddressRegisterDescription
0xA05F8000PVR_IDChip ID (0x17FD11DB)
0xA05F8004PVR_REVISIONChip revision
0xA05F8008SOFTRESETBit 0=TA reset, Bit 1=PVR reset, Bit 2=VRAM bus reset
0xA05F8014STARTRENDERWrite to trigger ISP/TSP rendering
0xA05F8020ISP_VERTBUF_ADDRVertex buffer base (OB) in VRAM
0xA05F802CISP_TILEMAT_ADDRTile matrix (OPB) base in VRAM
0xA05F8030SPANSORT_CFGSpan sort config (write 0x101)
0xA05F8040BORDER_COLBorder color RGB888
0xA05F8044FB_DISPLAY_CFGDisplay mode, pixel format, clock double, display enable
0xA05F8048FB_RENDER_CFGRender target format, dithering
0xA05F804CFB_RENDER_MODULORender stride = (bpp × width) / 8
0xA05F8050FB_DISPLAY_ADDR1Framebuffer read address (odd/non-interlaced)
0xA05F8054FB_DISPLAY_ADDR2Framebuffer read address (even field)
0xA05F805CFB_DISPLAY_SIZE[29:20]=modulo, [19:10]=height−1, [9:0]=width in 32-bit words−1
0xA05F8060FB_RENDER_ADDR1Render output address
0xA05F8064FB_RENDER_ADDR2Render output address (even field)
0xA05F8068FB_CLIP_XHorizontal clipping: [26:16]=max, [10:0]=min
0xA05F806CFB_CLIP_YVertical clipping
0xA05F8074CHEAP_SHADOWBit 8=enable, [7:0]=shadow intensity
0xA05F8078OBJECT_CLIPPolygon cull distance (IEEE float)
0xA05F807CFPU_PARAM_CFGObject buffer config, autosort mode
0xA05F8088BGPLANE_ZBackground plane depth (IEEE float)
0xA05F808CBGPLANE_CFGBG config: ISP/TSP mode, VRAM address
0xA05F8098ISP_FEED_CFGSort mode (0=autosort, 1=presorted)
0xA05F80B0FOG_TABLE_COLTable fog color
0xA05F80B4FOG_VERTEX_COLVertex fog color
0xA05F80B8FOG_DENSITYFog density coefficient
0xA05F80BCCOLOR_CLAMP_MAXColor clamp ceiling
0xA05F80C0COLOR_CLAMP_MINColor clamp floor
0xA05F80CCVPOS_IRQRaster position interrupt (top/bottom)
0xA05F80D0SYNC_CFGVideo output enable, interlace, broadcast std
0xA05F80D4HBORDERHorizontal border range
0xA05F80D8SYNC_LOADRefresh/scanline counts
0xA05F80DCVBORDERVertical border range
0xA05F80E4TSP_CFGTexture modulo width, VQ endian
0xA05F80F4SCALER_CFGHorizontal/vertical scaling
0xA05F8108PALETTE_CFGPalette format (0=ARGB1555, 1=RGB565, 2=ARGB4444, 3=ARGB8888)
0xA05F810CSYNC_STATVBlank/HBlank status, current scanline
0xA05F8124TA_OPB_STARTTA Object Pointer Buffer start address
0xA05F8128TA_OB_STARTTA Object Buffer start address
0xA05F812CTA_OPB_ENDTA OPB end limit
0xA05F8130TA_OB_ENDTA OB end limit
0xA05F8134TA_OPB_POSCurrent OPB write position (read-only)
0xA05F8138TA_OB_POSCurrent OB write position (read-only)
0xA05F813CTILEBUF_SIZETile matrix dimensions (in 32px tiles)
0xA05F8140TA_OPB_CFGPer-list OPB allocation sizes, enables
0xA05F8144TA_INITBit 31: initialize TA vertex registration
0xA05F8148YUV_ADDRYUV converter destination in VRAM
0xA05F814CYUV_CFGYUV format and dimensions
0xA05F8164TA_OPL_INITOPL start address (reinit)
0xA05F8200–83FFFOG_TABLE128-entry fog density LUT
0xA05F9000–9FFFPALETTE_TABLE1024 palette entries

8MB VRAM layout

VRAM occupies physical 0x04000000–0x047FFFFF (8MB) in two 4MB banks. The 32-bit area (0xA5000000–0xA57FFFFF via P2) provides sequential access—used for framebuffers. The 64-bit area (0xA4000000–0xA47FFFFF) interleaves banks every 4 bytes for double bandwidth—used for textures. Typical allocation: two framebuffers (~614KB each at 640×480×16bpp), two tile-buffer sets (OPB+OB), texture memory occupying the remainder. Total usable texture space depends on resolution and buffering strategy.

CHAPTER 03

Yamaha AICA: 64-channel sound with ARM7DI core

Architecture overview

The AICA integrates a 64-channel PCM/ADPCM synthesizer, a 128-step programmable DSP, and an ARM7DI processor (no Thumb, no hardware multiplier) running at approximately 45 MHz with 2MB dedicated sound RAM. The ARM7 executes audio driver code independently from the SH-4—it has no built-in firmware and must be loaded by the main CPU.

AICA registers from SH-4 (physical addresses in Area 0)

Address RangeContent
0x00700000–0x00707FFFAICA control registers (32KB)
0x00710000–0x0071000BAICA RTC registers
0x00800000–0x009FFFFFSound RAM (2MB)

Via P20xA0700000 for registers, 0xA0800000 for sound RAM.

Channel registers (64 channels × 0x80 bytes = 0x2000 bytes at offset 0x0000)

Each channel occupies 0x80 bytes starting at base + (channel × 0x80)

OffsetRegisterDescription
0x00PlayControlKey on/off (bits 15–14), loop (bit 9), format (bits 8–7: 0=16-bit PCM, 1=8-bit PCM, 2=4-bit ADPCM), sample addr high
0x04SampleAddrLowLower 16 bits of sample start address in sound RAM
0x08LoopStartLoop start position (samples)
0x0CLoopEndLoop end / total sample length
0x10AmpEnv1Attack rate, Decay1 rate, Decay2 rate
0x14AmpEnv2Release rate, decay level, key rate scaling
0x18SampleRatePitchOCT (bits 15–11, signed −8 to +7), FNS (bits 10–0, frequency number)
0x1CLFOControlLFO frequency, pitch/amplitude modulation waveform and depth
0x20DSPChannelSendDSP channel routing and send level
0x24DirectPanVolSendDirect volume (4-bit), pan (5-bit)
0x28LPF1VolumeMain volume (8-bit, 0xFF=silent), filter enable and Q
0x2C–0x44LPF2–LPF8Per-envelope-stage filter frequency and rates

Key system registers

OffsetRegisterDescription
0x2800MasterVolumeMaster volume (bits 3–0), mono/stereo mode
0x2890TimerATimer A start value
0x28A8ARMClockARM7 clock speed setting
0x28B4INTEnableWrite 0x20 to enable SH-4 interrupts
0x28B8INTSendWrite 0x20 to raise SH-4 interrupt
0x2C00ARMResetBit 0: 1=hold ARM7 in reset, 0=release
0x2D00INTRequestCurrent interrupt number
0x3000–0x31FCDSP program (128 steps)DSP microprogram memory
0x3200–0x32FCDSP coefficients64 coefficient registers
0x3400–0x43FFDSP data/temp RAMWorking memory for DSP effects

SH-4 ↔ ARM7 communication

The SH-4 loads the ARM7 audio driver into sound RAM (0x00800000), then clears bit 0 of ARMReset (0x2C00) to release the ARM7. The ARM7 boots from address 0x00000000 in its local space (= start of sound RAM). Communication uses shared mailbox regions in sound RAM—the SH-4 writes commands and audio data; the ARM7 reads them and controls the 64 channels. Interrupts can be sent bidirectionally via the INTSend/INTRequest registers.

CHAPTER 04

Memory architecture and address map

Physical address space (29-bit, 8 × 64MB areas)

Physical RangeContentSize
0x00000000–0x001FFFFFBoot ROM (mask ROM)2MB
0x00200000–0x0023FFFFFlash ROM (settings/saves)256KB
0x005F6800–0x005F69FFHolly system bus (SB) registers512B
0x005F6C00–0x005F6CFFMaple interface registers256B
0x005F7000–0x005F70FFGD-ROM registers (G1 bus)256B
0x005F7400–0x005F74FFG1 interface / GD-ROM DMA registers256B
0x005F7800–0x005F78FFG2 interface registers256B
0x005F7C00–0x005F7CFFPVR interface registers256B
0x005F8000–0x005F9FFFPVR core / TA registers8KB
0x00700000–0x00707FFFAICA control registers32KB
0x00710000–0x0071000BAICA RTC registers12B
0x00800000–0x009FFFFFSound RAM2MB
0x04000000–0x047FFFFFVRAM (64-bit interleaved access)8MB
0x05000000–0x057FFFFFVRAM (32-bit sequential access)8MB
0x0C000000–0x0CFFFFFFMain system RAM16MB
0x10000000–0x107FFFFFTA polygon converter FIFO
0x10800000–0x10FFFFFFTA YUV converter FIFO
0x11000000–0x11FFFFFFTexture memory direct access
0x14000000–0x17FFFFFFExpansion (modem) port64MB area

Logical address regions (32-bit, SH-4 with MMU off)

RangeNamePALTNCProperties
0x00000000–0x7FFFFFFFU0/P00××User/priv, cached, MMU if enabled
0x80000000–0x9FFFFFFFP1100Priv only, cached (copy-back/through)
0xA0000000–0xBFFFFFFFP2101Priv only, uncached (for HW regs)
0xC0000000–0xDFFFFFFFP3110Priv only, cached, MMU if enabled
0xE0000000–0xFFFFFFFFP4111SH-4 on-chip I/O, store queues

Games typically access main RAM at 0x8C000000 (P1, cached) or 0x0C000000 (P0), and hardware registers at 0xA05Fxxxx (P2, uncached).

Bus architecture

The SH-4 connects to main RAM directly via a 100 MHz, 64-bit SDRAM bus (two 32-bit banks). The SH-4 connects to Holly via a 100 MHz multiplexed address/data bus (MPX mode). Holly's internal root bus connects to: PVR core (with 64-bit 100 MHz VRAM bus), G1 bus (GD-ROM, Boot ROM, Flash—16-bit), G2 bus (AICA, modem, expansion—16-bit), and Maple interface (serial). All DMA is arbitrated by Holly's bus arbiter.

Key DMA channels: SH-4 DMAC has 4 channels (SAR/DAR/DMATCR/CHCR registers at 0xFFA00000–0xFFA0003C per channel, DMAOR at 0xFFA00040). Holly provides additional DMA: Ch2-DMA for PVR (0xA05F6800), Sort-DMA (0xA05F6810), GD-ROM DMA (0xA05F7404), AICA DMA (via G2), Maple DMA (0xA05F6C04).

CHAPTER 05

GD-ROM: proprietary disc format and controller

The GD-ROM (Gigadisc) is a dual-density proprietary disc format. The low-density area (inner tracks, ~35MB) is standard CD-readable and contains a warning audio track and small data track. A security ring separates it from the high-density area (outer tracks, ~984MB at double density), which contains the game data and is unreadable by standard CD drives. The drive reads using CAV (Constant Angular Velocity) at 4× in the low-density area and 6–12× in the high-density area, with a 128KB buffer. The file system is ISO 9660 with Joliet extensions.

GD-ROM registers (G1 bus, ATAPI-like)

AddressRegisterDescription
0xA05F7018Alt StatusAlternate status (no interrupt clear)
0xA05F7080Data16-bit PIO data transfer
0xA05F7084Error/FeaturesError (read) / Features (write)
0xA05F7088IntReason/SectorCountInterrupt reason / sector count
0xA05F708CSectorNumberSector number
0xA05F7090ByteCountLowByte count low
0xA05F7094ByteCountHighByte count high
0xA05F7098DriveSelectDrive select
0xA05F709CStatus/CommandStatus (read) / Command (write)

ATAPI commands0xA0 (PACKET—sends 12-byte command packet), 0x08 (soft reset), 0x90 (diagnostic), 0xA1 (identify). GD-ROM DMA registers at 0xA05F7404 (start address), 0xA05F7408 (length), 0xA05F7414 (enable), 0xA05F7418 (status).

Boot sequence

Boot ROM at 0xA0000000 → authenticates disc → loads IP.BIN (32KB from high-density area FAD ~45150) to 0x8C008000 → IP.BIN contains meta info (hardware ID "SEGA SEGAKATANA", product number, boot filename), SEGA license screen code, and two customizable bootstrap stages → reads 1ST_READ.BIN (filename from IP.BIN offset 0x60) from ISO 9660 filesystem, descrambles it, loads to 0x8C010000 → IP.BIN displays SEGA logo → bootstrap sets up stack, VBR, disables cache → jumps to 0x8C010000.

CHAPTER 06

Maple bus: controller protocol and peripherals

Protocol fundamentals

Maple is a proprietary 2-wire serial bus at ~2 Mbps connecting 4 controller ports, each supporting 1 main peripheral + up to 5 sub-peripherals (expansion slots). All Maple transactions are initiated by the SH-4 through Holly's DMA controller—the CPU writes a linked list of transfer descriptors to main RAM, points the Maple DMA register at it, and triggers the transfer.

Maple DMA registers

AddressRegisterDescription
0xA05F6C04SB_MDSTARDMA command table pointer (physical addr, 32-byte aligned)
0xA05F6C10SB_MDTSELDMA trigger select
0xA05F6C14SB_MDENDMA enable
0xA05F6C18SB_MDSTDMA start (bit 0, auto-clears on completion)
0xA05F6C80SB_MSYSSystem control (timing, speed)

Frame format

Each Maple frame consists of a 32-bit header word followed by 0–255 data words

Byte (in word)Field
Byte 0 (bits 7–0)Data word count (additional payload words)
Byte 1 (bits 15–8)Sender address
Byte 2 (bits 23–16)Recipient address
Byte 3 (bits 31–24)Command code

Address encoding: Bits [7:6] = port (0=A, 1=B, 2=C, 3=D). Bit 5 = main peripheral. Bits [4:0] = sub-peripheral select (one-hot). Host addresses: 0x00, 0x40, 0x80, 0xC0. Main peripheral addresses: 0x20, 0x60, 0xA0, 0xE0. Sub-peripherals: 0x01/0x02/0x04 (port A), etc.

Command codes

CodeCommandDirection
0x01Device Info RequestHost → Device
0x02Extended Device Info RequestHost → Device
0x03Reset DeviceHost → Device
0x04Shutdown DeviceHost → Device
0x05Device Info (response)Device → Host
0x06Extended Device Info (response)Device → Host
0x07AcknowledgeDevice → Host
0x08Data Transfer (response)Device → Host
0x09Get ConditionHost → Device
0x0AGet Memory InformationHost → Device
0x0BBlock ReadHost → Device
0x0CBlock WriteHost → Device
0x0ESet ConditionHost → Device
0xFCRequest ResendAny
0xFDUnknown Command (error)Device → Host
0xFEFunction Not SupportedDevice → Host
0xFFNo Response

Function codes (device capabilities)

CodeFunctionUsed by
0x00000001ControllerStandard pad
0x00000002StorageVMU memory card
0x00000004Screen (LCD)VMU display
0x00000008TimerVMU clock
0x00000010Audio InputMicrophone
0x00000020AR Gun
0x00000040KeyboardDC keyboard
0x00000080Light GunLight gun
0x00000100VibrationPurupuru (rumble) pack
0x00000200MouseDC mouse

Controller data format (Get Condition response)

The standard controller returns condition data with inverted button logic (0 = pressed, 1 = released)

BitButtonBitButton
0C8Z
1B9Y
2A10X
3Start11D
4D-pad Up12Up2
5D-pad Down13Down2
6D-pad Left14Left2
7D-pad Right15Right2

Following the 16-bit button wordR trigger (8-bit, 0–255), L trigger (8-bit, 0–255), analog stick X (8-bit, 0=left, 128=center, 255=right), analog stick Y (8-bit, 0=up, 128=center, 255=down), then second stick X/Y for dual-stick controllers.

VMU (Visual Memory Unit)

The VMU contains a Sanyo LC86K87 8-bit CPU, 128KB flash (200 usable blocks × 512 bytes), a 48×32 monochrome LCD (viewed as 48 wide × 32 tall), 4-direction D-pad + A/B/MODE/SLEEP buttons, and a CR2032 battery. It exposes three Maple functions: Storage (0x00000002) for block read/write of save data, Screen (0x00000004) for LCD bitmap writes (192 bytes = 48×32 pixels at 1bpp), and Timer (0x00000008) for the real-time clock. Block reads/writes use commands 0x0B/0x0C with a location word encoding partition, phase, and block number.

The Purupuru (Rumble) Pack exposes function 0x00000100 and is controlled via Set Condition (0x0E) with vibration intensity, duration, and frequency parameters.

CHAPTER 07

Conclusion

The Dreamcast's architecture presents several unique challenges for static recompilation. The SH-4's 16-bit fixed-width instructions simplify decoding but its delay slots on all unconditional branches, FP register banking (FPSCR.FR toggling two 16-register banks), and dual-issue superscalar scheduling require careful modeling. The vector instructions FIPR and FTRV operate across register banks—FTRV reads the back bank as a matrix—making bank-swap tracking essential.

The PowerVR's tile-based architecture means the GPU has no equivalent to a traditional draw call pipeline—all geometry flows through the TA FIFO as parameter blocks, and rendering is deferred per-tile. Emulating this requires either full TBDR simulation or converting the TA parameter stream into modern GPU API calls with manual tile management. The store queue mechanism (0xE0000000 + PREF) is the primary fast path for TA submission and must be correctly emulated.

The AICA's independent ARM7 core means a recompiler must run two instruction-set decoders and manage cross-CPU communication through shared sound RAM. The Maple bus adds a third protocol layer with its own DMA descriptor format. All three subsystems operate asynchronously—timing-accurate synchronization between the SH-4, ARM7, PVR rendering, and Maple DMA polling is the central challenge of any Dreamcast recompilation engine.

CHAPTER 08

I/O Dispatch Reference (Final Synthesis)

AICA Audio Registers (G2-bus, $00700000 base)

The AICA is the Dreamcast's descendant of the Saturn SCSP — same Yamaha lineage but with 64 channels (vs 32), an ARM7DI coprocessor (vs 68EC000), and 2 MB sound RAM (vs 512 KB). Registers are accessed via G2-bus from the SH-4 at physical $00700000 (P2: $A0700000).

Per-Channel Registers (64 channels × $80 bytes at $00701000 + slot×$80):

OffsetNameBitsDescription
+$00KYONB/PlayCtrlbit0=KEY_ON trigger, [8:7]=PCMS (0=PCM16, 1=PCM8, 2=ADPCM4), [22:0]=SA highKey control + sample format + address high
+$04SA_LO[15:0]=SA lowSample address low (address = SA >> 1 for byte offset)
+$08LSA[15:0]=loop startLoop start position (samples)
+$0CLEA[15:0]=loop endLoop end / total sample length
+$10AmpEnv1AR(4:0), D1R(4:0), D2R(4:0)EG attack/decay1/decay2 rates (5-bit each)
+$14AmpEnv2RR(4:0), DL(4:0), KRS(3:0), LPSLNKRelease rate, decay level, key rate scaling
+$18PitchOCT[15:11] (signed −8..+7), FNS[10:0]Octave + frequency number
+$1CLFOLFOF(4:0), pitch/amp waveform & depthLFO control
+$20DSPSendDSP channel routing + send levelEffect bus routing
+$24DirectPanDISDL(3:0), DIPAN(4:0)Direct volume (4-bit) + pan (5-bit)
+$28EffectPanEFSDL(3:0), EFPAN(4:0)Effect send (4-bit) + effect pan (5-bit)
+$2CTLTL[7:0]Total level (8-bit attenuation, 0=max, 0xFF=silent)

Read EG[12:0]/SGC at channel offset for current envelope state.

AICA Channel Setup Pseudocode:

void aica_channel_setup(uint8 slot, uint32 sa, uint16 lsa, uint16 lea,
uint8 pcms, uint16 fns, int8 oct,
uint8 tl, uint8 disdl, uint8 dipan) {
uint32 base = 0x00701000 + slot * 0x80;
write32(base + KYONB_OFF, 0);           // clear key-on
write32(base + SA_OFF, sa >> 1);        // sample address (byte→word)
write16(base + LSA_OFF, lsa);
write16(base + LEA_OFF, lea);
write8(base + PCMS_OFF, pcms);          // 0=PCM16, 1=PCM8, 2=ADPCM4
write16(base + FNS_OFF, fns);
write8(base + OCT_OFF, oct & 0xF);
write8(base + AR_OFF, 0x1F);            // max attack rate
write8(base + TL_OFF, tl);
write8(base + DISDL_OFF, disdl);
write8(base + DIPAN_OFF, dipan);
write8(base + EFSDL_OFF, 0xF);          // max effect send
write32(base + KYONEX_OFF, 1);          // trigger key-on
}

Global Registers ($00702800+):

AddressNameR/WBitsDescription
$00702800MVOLRW[15:12]=MN (mono), [11]=M8, [5:0]=MVOL (0=−∞..15=0 dB). Read returns VER[3:0]Master volume. Read returns hardware version ID
$00702804RingbufRW[14:13]=RBL (0=8K..3=64K words), [12:3]=RBPDSP ring buffer config. Write starts effect chain
$00702890TIMARWTimer A start value (8-bit + prescaler)Timer A reload value
$0070289CSCIEBRW[10:0] IRQ enable bits (DMA=4, TimerA/B/C=6–8)Sound CPU interrupt enable
$007028A0SCIPDR[10:0] interrupt pending bitsSound CPU interrupt pending
$007028A4SCIREWO[10:0]Sound CPU interrupt reset — write-1-to-clear
$007028B4MCIEBRW[10:0] IRQ enable bitsMain CPU (SH-4) interrupt enable
$007028B8MCIPDR[10:0] interrupt pending bitsMain CPU interrupt pending
$007028BCMCIREWO[10:0]Main CPU interrupt reset — write-1-to-clear
$00702C00ARMRSTRWbit 0: 1=hold ARM7 in reset, 0=releaseARM7 reset control. Set after DMA-loading driver to wave RAM ($00800000), then clear to boot

Timer Overflow → IRQ Chain: Timer A/B/C overflow → sets SCIPD bit → if SCIEB enabled → ARM7 interrupt. If MCIEB enabled → MCIPD set → Holly ISTNRM sound request → SH-4 interrupt at VBR+$600.

DSP Effect Chain (128-step MPRO at $00703400):

64-bit instruction encodingMASA[5:0], IRA/TWA/TRA/EWA, MRD/MWT, YSEL/XSEL, SHFT, NEGB. Ring buffer formula: (MADRS + ADRS_REG + MDEC_CT + NXADR) mod RBL_size. Coefficients at $00703200 (64 entries). Data/temp RAM at $00703400–$000043FF.

Standard effectsHall reverb = 34 steps, Chorus = 22 steps (LFO on delay line). Representative COEF values (no commercial dumps exist publicly): COEF[0]=0x7FFF (gain),

0x4000
(damp), etc.

Dynarec C++ Driver Pattern (from Flycast — x64/ARM64 with dirty-flag + fallback):

class AICA_DSP {
bool dirty = true;
void* dynarec_code = nullptr;
public:
void Run(u32 samples) {
if (dirty || MPRO_changed) { dsp_recompile(); dirty = false; }
for (u32 i = 0; i < samples; i++) {
if (dynarec_enabled) ((void(*)())dynarec_code)();
else runStep();  // interpreter fallback
}
}
void dsp_recompile() { /* emit x64/ARM64 for 128-step MPRO */ }
};

GD-ROM Controller Registers (G1-bus, $A05F7000 base)

ATAPI Registers (directly mapped):

AddressNameR/WDescription
$A05F7018Alt StatusRAlternate status (read does NOT clear interrupt)
$A05F7080DataRW16-bit PIO data transfer
$A05F7084Error/FeaturesRWError (R) / Features (W): bit 0=DMA mode
$A05F7088IntReasonRWInterrupt reason / sector count
$A05F708CSectorNumberRWSector number
$A05F7090ByteCountLowRWByte count low
$A05F7094ByteCountHighRWByte count high
$A05F7098DriveSelectRWDrive select
$A05F709CStatus/CommandRWStatus (R): BSY/DRDY/DRQ/ERR bits. Command (W): $A0=PACKET, $08=soft reset

GD-ROM DMA Registers:

AddressNameR/WDescription
$A05F7404GDST_ADDRRWDMA destination address in main RAM
$A05F7408GDST_LENRWDMA transfer length (in 32-byte units)
$A05F740CGDST_DIRRWDMA direction
$A05F7414GDST_ENWDMA enable — writing 1 starts transfer
$A05F7418GDST_STATRDMA status: bit 0 = active. Auto-clears on completion. Triggers ISTNRM[14]

GD-ROM DMA Read Protocol (high-density sector read):

void gdrom_dma_read(uint32 fad, uint32 sectors, void* buf) {
write32(0xA05F7404, 0x01);       // FEATURES=DMA mode
write32(0xA05F7408, sectors);
write32(0xA05F709C, 0xA0);       // ATAPI PACKET command
// Send 12-byte CDB: cmd $30 (READ_CD), format, FAD, count
uint8 cdb[12] = {0x30, 0x0C,
(fad>>24), (fad>>16), (fad>>8), fad,
0x00, (sectors>>8), sectors, 0x00, 0x00, 0x00};
for (int i = 0; i < 12; i += 2)
write16(0xA05F7018, (cdb[i]<<8) | cdb[i+1]);
// Configure DMA
write32(0xA05F7404, (uint32)buf);
write32(0xA05F7408, sectors * 2048 / 32);
write32(0xA05F740C, 1);           // direction
write32(0xA05F7414, 1);           // enable → starts transfer
write32(0xA05F7418, 1);           // initiate
while (read32(0xA05F7418) & 1);   // poll or use ISTNRM[14]
}

High-Density Access: GET_TOC command ($14, byte1=1) to switch to GD area.

Sense Key Table + Recovery:

  • $05/$21 (illegal FAD) → re-GET_TOC
  • $03/$11 (medium error) → CD_OPEN retry
  • $0B/$4E (aborted) → SOFT_RESET

KOS-style IRQ Driver:

static void gdrom_irq_callback(uint32 status) {
if (status & (1<<14)) gdrom_dma_done = true;
else if (status & ISTERR_MASK)
gdrom_kos_timed_recovery(cdrom_get_sense());
}

Maple Bus DMA Registers ($A05F6C00 base)

AddressNameR/WDescription
$A05F6C04SB_MDSTARRWDMA command table pointer (physical, 32-byte aligned)
$A05F6C10SB_MDTSELRWDMA trigger select
$A05F6C14SB_MDENRWDMA enable
$A05F6C18SB_MDSTRWDMA start: bit 0 write=start, auto-clears on completion. Read bit 0 = busy
$A05F6C80SB_MSYSRWSystem control (timing, speed)

DMA Descriptor Format (32-byte aligned in main RAM):

WordBitsDescription
0[31]=LAST, [30:27]=PORT, [26]=GUN, [25:0]=LENGTHControl + transfer length
1[31:0]Receive buffer address

Lightgun Support: Set GUN=1 + LAST=1 in descriptor word 0 → 8 SDCKB clock pulses →

hardware latches H/V position to PVR register $A05F80C4 (H[31:16], V[15:0]). CRC variants

0xFF
or 0x00 initial XOR.

VMU Operations (controller + 5 sub-peripherals per port):

typedef struct {
uint32 cmd;        // $0B=block_read, $0C=block_write
uint32 recipient;  // $21 | (sub << 4)
uint32 sender;
uint32 length;
uint8 data[256];
} maple_frame;

int maple_vmu_op(uint8 port, uint8 pt, uint8 phase,
uint8 block, void* buf, bool write, uint8 sub) {
maple_frame f = {
.cmd = write ? 0x0C : 0x0B,
.recipient = 0x21 | (sub << 4),
// ...
};
maple_send_frame(&f);
for (uint8 s = 0; s < 5; s++) maple_queue_frame(&f);
while (!maple_done());
maple_response r; maple_parse_response(&r);
if (r.error & 0x20) { /* phase retry or bad-block remap */ }
uint8 crc = 0xFF;
for (each byte in data) crc ^= byte;
return crc;
}

SH-4 DMAC + Store Queue

DMAC (4 channels at $FFA00000):

OffsetNameR/WDescription
+$00/+$10/+$20/+$30SAR0–3RWSource address
+$04/+$14/+$24/+$34DAR0–3RWDestination address
+$08/+$18/+$28/+$38DMATCR0–3RWTransfer count
+$0C/+$1C/+$2C/+$3CCHCR0–3RWChannel control: DE (enable), TE (end), IE (IRQ enable), TS (transfer size), AR (auto-request), DM/SM (dest/src increment mode)
+$40DMAORRWDMA operation register: DDM (round-robin), PR (priority), NMIF, AE (address error), DME (master enable — must be set before any transfer)

Store Queue (TA Fast Path):

Two 32-byte buffers at $E0000000 (SQ0 at bit[5]=0, SQ1 at bit[5]=1). Fill with MOV.L writes, flush via PREF @Rn instruction. Upper physical address bits from QACR0/QACR1 ($FF000034/$FF00003C).

Primary useburst-write display lists to TA FIFO at physical $10000000 (64-bit transfer size). This is the critical fast path for geometry submission — all high-performance Dreamcast games use Store Queue → TA FIFO for polygon submission.

PVR Tile Accelerator (TA) Parameter Format

Parameter Control Word (PCW — Word 0):

BitsNameDescription
[31:29]cmd4=POLY, 5=SPRITE, 7=VERTEX, 0=END_OF_LIST
[28]end_of_strip1=last vertex of triangle strip
[26:24]listtype0=opaque, 1=opaque_mod, 2=translucent, 3=trans_mod, 4=punch-through
[22:21]group/stripGroup/strip control

ISP Word 1: [31:29]=depth compare mode, [28:27]=cull mode (none/small/CW/CCW), [26]=z-write disable.

TSP Word 2/3: Blend mode (src/dst alpha factors), fog control, texture filter (point/bilinear/trilinear), UV clamp/flip, texture address in VRAM, format (ARGB1555/RGB565/ARGB4444/YUV422/bump/4BPP/8BPP), mip-map, VQ compression, twiddled.

17-Vertex Parse: TA processes up to 17 vertices per polygon submission. Region array links Object Pointer Buffers (OPB) per 32×32 pixel tile.

OPB Chaining (all resolutions):

void ta_link_opb(uint32 tx, uint32 ty, uint32 list, uint32 ptr) {
uint32 tiles_x = (FB_W_CTRL & 0x1) ? 20 : 10;
uint32* region = (uint32*)(TA_OL_BASE + (ty * tiles_x + tx) * 24 + list * 4);
*region = ptr;
write32(TA_NEXT_OPB, ptr + 64);
write32(TA_ITP_CURRENT, ptr);
write32(TA_GLOB_TILE_CLIP, (ty << 16) | tx);
write32(TA_OBJECT_CLIP, (ty << 16) | tx);
write32(TA_SQ_WRITE, ptr);
write32(TA_OL_LIMIT, ptr + 0x100000);
}

Submission via Store Queue (TA_SQ_WRITE at TA FIFO $10000000).

Additional Holly Registers ($A05F8000+)

AddressNameR/WDescription
$A05F8008SOFTRESETWbit 0=TA reset, bit 1=PVR reset, bit 2=VRAM bus reset. Writes trigger immediate re-sync
$A05F8050FB_R_SOF1RWFramebuffer scanout address (odd field / non-interlaced)
$A05F8054FB_R_SOF2RWFramebuffer scanout address (even field)
$A05F80C4GUN_POSRLightgun H/V position: H[31:16], V[15:0]. Latched by SDCKB after GUN maple descriptor
$A05F80CCSPG_VPOSRWVBlank interrupt position (configurable top/bottom scanline)
$A05F80D0SPG_HBLANKRWHorizontal sync/blank timing
$A05F80D4SPG_LOADRWSync load (scanline/refresh counts)
$A05F8144TA_INITWbit 31: initialize TA vertex registration. Must write before first polygon submission per frame

Complete I/O Register Dispatch Table

AddressNameR/WSide Effects
$005F6900Holly ISTNRMR/WR: normal interrupt status (32 flag bits). W: write-1-to-clear (AND NOT)
$005F6904Holly ISTEXTR/WR: external interrupt status. W: write-1-to-clear
$005F6C14Maple MDENWMaple DMA enable
$005F6C18Maple MDSTR/WR: bit 0=DMA busy. W: bit 0=start DMA. Auto-clears on completion → ISTNRM[12]
$005F709CGD-ROM Status/CmdR/WR: BSY/DRDY/DRQ/ERR status bits. W: ATAPI command ($A0=PACKET, $08=reset)
$005F7414GD-ROM DMA ENWWriting 1 starts GD-ROM DMA transfer
$005F7418GD-ROM DMA STATRbit 0=DMA active. Auto-clears on completion → ISTNRM[14]
$005F8008PVR SOFTRESETWbits 0-2: TA/PVR/VRAM reset. Immediate re-sync
$005F8014PVR STARTRENDERWTrigger ISP/TSP rendering. Sets ISTNRM[2] on completion
$005F809CSPG_STATUSRVBlank/HBlank status, current scanline, field parity
$005F80C4GUN_POSRLightgun position: H[31:16], V[15:0]. Latched by SDCKB
$005F8144PVR TA_INITWbit 31: initialize TA vertex registration
$00702800AICA MVOLR/WW: master volume [5:0] + mono [15:12]. R: returns VER[3:0] hardware version
$00702804AICA RingbufWWrite starts DSP effect chain. RBL [14:13] (ring buffer length) + RBP [12:3]
$00702C00AICA ARMRSTWbit 0: 1=hold ARM7 reset, 0=release. Write after loading driver to wave RAM
$FFA00040SH-4 DMAORWDMA master enable (DME). Must be set before any DMAC channel transfer

Integration with Existing Pipeline

Interrupt routing through Holly ISTNRM/ISTEXT:

  • GD-ROM DMA complete → ISTNRM[14]
  • Maple DMA complete / lightgun → ISTNRM[12] + HV latch to $005F80C4
  • PVR render complete → ISTNRM[2]
  • TA object buffer overflow → ISTERR[5]
  • AICA → SH-4 interrupt via MCIPD → Holly ISTNRM sound request bit

SH-4 DMAC + Store Queue fast path:

  • PREF instruction flushes 32-byte SQ → TA FIFO at $10000000
  • DMAOR master enable (DME bit) required before any DMAC channel transfer
  • QACR0/QACR1 ($FF000034/$FF00003C) configure upper address bits for SQ target
  • 64-bit burst transfer size on SQ flush

Verification Notes

Test approach (Flycast/lxdream trace comparison):

  1. Holly ISTNRM — verify write-1-to-clear (AND NOT) behavior, all 32 flag bits
  2. GD-ROM ATAPI — send PACKET command, verify status progression (BSY→DRQ→ready)
  3. Maple MDST — start DMA, verify auto-clear of bit 0 on completion + ISTNRM[12]
  4. AICA ARMRST — load driver to $00800000, clear bit 0, verify ARM7 boots
  5. PVR TA_INIT → STARTRENDER — submit geometry, verify ISTNRM[2] on render done
  6. Lightgun — set GUN=1 in maple descriptor, verify HV latch at $005F80C4

Commercial game validation:

  • Sonic Adventure: Store Queue TA submission + PVR STARTRENDER at 60fps
  • Soul Calibur: Vertex-heavy TA submission with OPB chaining across 640×480 tiles
  • Shenmue: GD-ROM streaming + AICA DSP ambient reverb (34-step hall)
  • House of the Dead 2: Lightgun HV latch + GUN maple descriptor protocol
CHAPTER 09

I/O Dispatch Deepening (Maximum Depth Synthesis)

AICA DSP — ARM7 Address Space + Upload Protocol

The AICA DSP registers have dual address mappings — the SH-4 accesses them via

G2-bus at $00700000+, while the ARM7 coprocessor accesses them locally at $00800000+

SH-4 AddressARM7 AddressNameDescription
$00703200$00803200COEF128 × 13-bit signed coefficients
$00703400–$00703BFC$00803400–$00803BFCMPRO128 DSP program steps (64-bit each)
$00704000–$000043FF$00804000–$000043FFTEMPTemporary ring buffer (auto-decrement)
$00704400–$00704500$00804400–$00804500MEMSMemory sample buffer
$007045C0–$007045C7$008045C0–$008045C7EFREG8 effect output registers (DAC output)

DSP MPRO Upload Format: Each 64-bit program step is written as 4 × 16-bit words

  • STEP[63:48] at base address
  • STEP[47:32] at base + 4
  • STEP[31:16] at base + 8
  • STEP[15:0] at base + 12

COEF Table: 128 entries × 13-bit signed values (vs 64 entries documented in Final Synthesis — the full bank is 128). Used by the DSP for scaling, feedback coefficients, and filter parameters. Loaded via SH-4 G2-bus writes after ARM7 reset.

Additional Per-Channel Register — IMXL/ISEL:

  • Offset +$30: FX mixer send level (IMXL) and DSP bus select (ISEL). Controls which

DSP mixer input bus the channel feeds into. This register shares the offset with DISDL/DIPAN but uses different bit fields for the mixer routing.

DSP Enable: MVOL register ($00702800) bit 4 enables DSP program execution. Must be set after loading MPRO and COEF. The DSP runs synchronously at the AICA sample rate.

Effect Presets (SCSP-ported patterns):

  • Hall reverb: 34 steps
  • Chorus: 22 steps (LFO modulation on delay line)
  • Delay: 20 steps (simple echo with feedback)

G2 Bus Access Constraints:

  • G2-bus writes from SH-4 stall for ≤16µs while AICA DMA is active
  • Reading AICA registers during active DMA transfer blocks until DMA completes
  • Writes to channel registers while KYONEX is pending may be ignored

GD-ROM — Full ATAPI Command Table + ASC/ASCQ Error Codes

The GD-ROM controller uses an extended ATAPI command set defined in Sega's SPI Protocol Ver.1.30 specification (Cdif131e.pdf). The controller registers at $A05F7400+ are mirrored at physical $005F74xx.

Extended Register Layout (G1-bus $A05F7400+):

AddressNameR/WDescription
$A05F7018GD_DATARW16-bit PIO data transfer
$A05F7404GD_FEATURESWFeature select (bit 0 = DMA mode)
$A05F7408GD_SECT_CNTRWSector count
$A05F740CGD_SECT_NUMRWSector number
$A05F7410GD_BYTE_CTL_LORWByte count low
$A05F7414GD_BYTE_CTL_HIRWByte count high
$A05F7418GD_DRV_SELRWDrive select
$A05F741CGD_STATUS/CMDRWR: status bits (BSY/DRDY/DRQ/ERR), W: ATAPI command

ATAPI + Vendor Command Table (SPI Ver.1.30):

OpcodeNameDescription
$00TEST_UNIT_READYCheck drive status (no data transfer)
$12SET_MODEVendor: laser boost / read-retry configuration
$13REQ_ERRORRequest error information (sense key + ASC/ASCQ)
$14GET_TOCRead Table of Contents (byte1=1 for GD high-density area)
$30CD_READPrimary 12-byte read command (FAD-based addressing)
$A8READ(12)Standard ATAPI fallback read command (LBA-based)

ASC/ASCQ Error Code Table (SPI Appendix I, verbatim):

ASCASCQSense KeyDescription
$00$000hNo error
$09$044hLaser power control error (hardware option)
$09$024hFocus servo failure
$09$034hSpindle servo failure
$3A$002hNo media present (disc tray open or empty)
$4E$00BhNew command received during execution (overlapped)

Sector Read + Laser Recovery Sequence (DMA preferred):

void gdrom_read_lba(u32 lba, void* buf, u32 sectors) {
write_gd(0x741C, 0xA0);                    // ATAPI PACKET command
send_12byte_packet(0x30, lba, sectors);     // CD_READ CDB
if (status & 0x01) {                        // ERROR bit set
write_gd(0x741C, 0xA0);
send_12byte(0x13);                      // REQ_ERROR
u8 sense = read_error() >> 4;
u8 asc = read_asc();
u8 ascq = read_ascq();
if (sense == 4 && asc == 0x09 && ascq == 0x04) {
// Laser power control error → SET_MODE laser boost
write_gd(0x741C, 0xA0);
send_12byte(0x12, 0x09, 0x08, 0x00);
delay(50ms);                        // allow laser recalibration
}
retry();
}
// DMA path: set SB_GDSTAR/LEN/DIR=1/EN=1/ST=1; wait ISTNRM bit14
}

Side Effects: ERROR bit assertion → ISTERR interrupt to Holly. Laser servo retry via SET_MODE command ($12) with 50ms recalibration delay.

Maple Bus — Wire Protocol Timing + Response Parsing

The Maple bus operates on 4 independent serial buses (Ports A–D), each with differential clock/data pairs (SDCKA/SDCKB).

Wire Protocol Timing:

PhaseSignal SequenceDurationDescription
StartSDCKA low → SDCKB toggle 4× → SDCKA high~640ns hostBus acquisition
Data bit2-bit phases, sampled on falling edge160ns host / 250ns peripheralBidirectional data
EndSDCKA high → SDCKB high-low → SDCKA toggle 2×~320nsBus release

Edge Spacing: 125ns between different signal lines (SDCKA→SDCKB), 225ns between same signal line edges. These constraints set the maximum bus throughput.

CRC: Byte-wise XOR with init value 0 over frame header + payload bytes. (Note: The Final Synthesis section documents CRC variants with 0xFF or 0x00 init — the Maximum Depth research confirms init=0 as the canonical implementation.)

**Full Binary Transaction Trace (Port 0controller + VMU + lightgun):**

u32 multi_desc[12] = {
0x80000002 | (0x09<<24) | 0x20, rx1,     // 0x09 Get Condition (controller)
0x80000002 | (0x0B<<24) | 0x21, vmu_rx,  // 0x0B VMU Block Read
0x80000001 | (0x80<<24) | 0x22, gun_rx   // 0x80 Light-Gun (LAST=1)
};

Response Function Codes:

CodeNamePayloadDescription
$05Device Info28 wordsDevice capabilities, product name, license string
$07Ack0 wordsWrite acknowledgment (VMU block write success)
$08Data TransferVariableVMU block data + location word
$80GUN0 words8 SDCKB pulses → beam pulls low → HV latch to SPG_TRIGGER_POS
$FFTimeoutNo response (0xFFFFFFFF in receive buffer)

Maple Poll Sequence:

void maple_poll(u32 desc_addr) {
*(u32*)0xA05F6C04 = desc_addr;  // MDSTAR: set descriptor table pointer
*(u32*)0xA05F6C14 = 0x1;        // MDEN: enable Maple DMA
*(u32*)0xA05F6C18 = 0x1;        // MDST: start transfer
while (*(u32*)0xA05F6C18 & 0x1); // poll until !busy (auto-clears)
// Parse response buffers with CRC verification (XOR init 0)
}

SH-4 DMAC — Channel Control Bits + DMA Contention Matrix

CHCRx (Channel Control Register, offset +$0C/+$1C/+$2C/+$3C) Bit Layout:

BitsNameDescription
[3:0]TSTransfer size: 0=64B (Store Queue burst), 1=1B, 2=2B, 3=4B, 4=32B
[13:12]SMSource address mode: 0=fixed, 1=increment, 2=decrement
[15:14]DMDestination address mode: 0=fixed, 1=increment, 2=decrement
17IEInterrupt enable on transfer end
24DEDMA enable (per-channel)
25TETransfer end flag (set by hardware on completion)

DMAOR ($FFA00040) Bit Layout:

BitNameDescription
0DMEDMA master enable — must be 1 before any channel transfer
1NMIFNMI flag (set on NMI, must be cleared to re-enable DMA)
2AEAddress error flag
5MDPriority mode: 0=CH0 fixed highest priority, 1=round-robin

DMA Contention Matrix (PVR TA + texture upload + GD-ROM load concurrent):

ScenarioCH0 StallCH2 TextureSQ (TA)Handling
TA FIFO full16 cycles32 cycles0 (stalled)TAFOFINT IRQ → reset TA
Concurrent DMARound-robin 64B16–32 cyclesPreemptedSB_TFREM==0 stall ~32 cycles

TAFOFINT: TA FIFO overflow interrupt. When SB_TFREM (TA FIFO remaining count) reaches 0, Store Queue writes stall for ~32 cycles until space is available. If overflow persists, TAFOFINT fires and the TA must be reset via SOFTRESET bit 0.

Store Queue Recomp Mapping (TA geometry burst):

u32* sq = (u32*)0xE0000000;
for (int i = 0; i < 8; i++) sq[i] = param[i];  // fill 32 bytes
__asm__("pref @%0" : : "r"(sq));               // PREF → 32B burst to $10000000

PVR TA — Named Registers + Dual FIFO

TA Configuration Registers ($A05F8000+):

AddressNameR/WDescription
$A05F8124TA_OL_BASERWObject list base address in VRAM
$A05F8128TA_ISP_BASERWISP/TSP parameter base address
$A05F812CTA_OL_LIMITRWObject list end address (overflow → TAFOFINT)
$A05F8130TA_ISP_LIMITRWISP/TSP parameter end address
$A05F8134TA_NEXT_OPBRWNext free Object Pointer Block address
$A05F8138TA_ITP_CURRENTRWCurrent ISP/TSP parameter write pointer
$A05F813CTA_GLOB_TILE_CLIPRWGlobal tile clipping rectangle
$A05F8140TA_OBJECT_CLIPRWObject clipping rectangle
$A05F8144TA_INITWbit 31: initialize TA vertex registration
$A05F8148TA_SQ_WRITERWStore Queue write target address

Dual TA FIFO:

  • Primary: $10000000 (Store Queue target for polygon parameter submission)
  • Secondary: $10800000 (alternate FIFO for YUV texture conversion data)

END_OF_LIST: Submitting a parameter with cmd[31:29]=0 (PCW command field) triggers an END_OF_LIST interrupt (ISTNRM list-specific bits), signaling that the current display list is complete and rendering can begin via STARTRENDER.

Holly/PVR Video Output — Timing Tables + Quad-Buffer Swap

Video Output Registers ($A05F8000+):

AddressNameR/WDescription
$A05F8040VO_BORDER_COLRWBorder color RGB during blanking periods
$A05F80C8SPG_HBLANK_INTRWHBlank interrupt position
$A05F80CCSPG_VBLANK_INTRWVBlank interrupt position (configurable top/bottom scanline)
$A05F80D0SPG_HBLANKRWHorizontal sync/blank timing
$A05F80D4SPG_LOADRWSync load (scanline/refresh counts). Write restarts sync generator
$A05F80D8SPG_CONTROLRWVideo mode (interlace, NTSC/PAL, sync polarity). Write triggers re-sync + TA pipeline flush
$A05F80E0VO_STARTXRWHorizontal display start position (fine-tunes CRT centering)
$A05F80E4VO_STARTYRWVertical display start position
$A05F80E8VO_CONTROLRWbit 3 = blank_video: 1=show border color, 0=show framebuffer. Immediate display effect

Video Timing Table (DevBox verbatim defaults):

ModeSPG_LOADSPG_HBLANKSPG_VBLANKSPG_CONTROLVO_STARTX/YBorder
NTSC 640×480 prog$020C0359$007E0345$00280208$00000100$00A8/$0028$000000
PAL 640×480 prog$0270035F$008D034B$002C026C$00000180$00AE/$002D$000000
VGA/VESA 640×480$020C0359$007E0345$00280208$00000100$00A8/$0028$000000

Quad-Buffer Swap + TA Sync (under TAFOFINT):

void quad_buffer_swap_ta_sync(u32 buf[4], u32 border_rgb) {
if (TAFOFINT()) reset_ta();                  // handle TA overflow
*(u32*)0xA05F8050 = buf[idx];                // FB_R_SOF1: swap scanout buffer
*(u32*)0xA05F8040 = border_rgb;              // VO_BORDER_COL: set border
*(u32*)0xA05F80E8 |= (1<<3);                 // VO_CONTROL: blank_video=1
*(u32*)0xA05F8014 = 0x1;                     // STARTRENDER: begin ISP/TSP
while (!(*(u32*)0xA05F6900 & (1<<12)));      // wait VSYNC (ISTNRM bit 12)
idx = (idx + 1) % 4;
*(u32*)0xA05F80D8 = spg_load;                // SPG_CONTROL → re-arm TA + VPOS reset
}

Side Effects:

  • SPG_CONTROL or SPG_LOAD write → restarts sync generator + TA pipeline flush
  • blank_video=1 → display shows VO_BORDER_COL instead of framebuffer (prevents tearing

during buffer swap)

  • VO_STARTX/Y writes fine-tune CRT horizontal/vertical centering

Expanded I/O Register Dispatch Table

New entries from Maximum Depth Synthesis marked with (MDS)

AddressNameR/WSide Effects
$005F8040VO_BORDER_COLW(MDS) Set border color RGB for blanking periods
$005F80D4SPG_LOADW(MDS) Sync load config. Write restarts sync generator
$005F80D8SPG_CONTROLW(MDS) Video mode control. Write triggers re-sync + TA pipeline flush + VPOS reset
$005F80E8VO_CONTROLW(MDS) bit 3=blank_video. Immediate display blank/unblank

Combined with the 16 Final Synthesis entries (8 read + 8 write), Dreamcast now has 20 total dispatch entries (8 read + 12 write) in the Final Synthesis table, plus these 4 additional write entries = 24 total (8 read + 16 write).

Cross-Subsystem DMA Coordination

The Dreamcast's subsystems interact through multiple DMA paths that must be correctly

sequenced for recompilation

  • AICA audio loading: G2-bus DMA from main RAM to sound RAM ($00800000), coordinated

with SH-4 DMAC CH0. G2 access stalls ≤16µs during active transfer.

  • GD-ROM → main RAM: SPI controller triggers GD-ROM DMA. Completion fires ISTNRM[14],

which typically triggers Maple VBLANK poll in the game's interrupt handler.

  • TA geometry: Store Queue bursts (PREF → $10000000) use CHCR TS=0 (64-byte SQ

mode). DMAOR round-robin arbitration with MD bit. SB_TFREM monitoring prevents FIFO overflow; TAFOFINT fires if overflow occurs.

  • Framebuffer swap: Quad-buffer rotation syncs SPG timing, TA FIFO state, and VO

blanking across all video modes (NTSC/PAL/VGA). SPG_CONTROL write re-arms the TA and resets VPOS for the next frame.

Additional Verification Notes (Maximum Depth)

Expanded test approach:

  1. GD-ROM ATAPI command table — send TEST_UNIT_READY ($00), verify no-data status

response; send REQ_ERROR ($13) after forced error, verify ASC/ASCQ matches table

  1. Laser recovery — inject sense 4 / ASC $09 / ASCQ $04, verify SET_MODE ($12) issued

with laser boost parameters + 50ms delay

  1. Maple wire timing — verify SDCKA/SDCKB edge spacing matches 125ns/225ns spec;

verify CRC with init=0 over frame+payload

  1. SH-4 DMAC contention — concurrent CH0 + SQ transfer, verify SB_TFREM stall

behavior (~32 cycles when FIFO full)

  1. VO_CONTROL blank_video — set bit 3, verify border color displayed instead of

framebuffer content

  1. SPG_CONTROL write — verify sync generator restart and TA pipeline flush on write

Additional commercial game validation:

  • Jet Set Radio: Heavy TA geometry + SQ bursts with TAFOFINT recovery
  • Crazy Taxi: Continuous GD-ROM streaming + Maple polling in VBLANK handler
  • Ikaruga: Precise SPG timing for 60fps progressive scan (VGA mode)

Public sources

Production ledger

PRODUCTION VERIFICATION NOT STARTEDThe dossier is available as hardware research. No implementation result is recorded here yet.