Skip to content

Register map

Canonical Atari registers + the rp-XT chiplet-extension allocation owned by xt6502. The chiplet-extension layout follows the README’s “Proposed map of register-space over and above ANTIC and C|GTIA” — all addresses cross-checked against AtariAge’s canonical hardware-register list (forums.atariage.com/topic/157241) to ensure no canonical register is shadowed.

xt6502 owns the entire page. Real-silicon mirror behaviour is preserved on $D000-$D07F; the upper half ($D080-$D0FF) is the chiplet-extension window with mirroring broken.

AddrNamePurpose
$D000HPOSP0Player 0 horizontal position (color clocks).
$D001HPOSP1Player 1 horizontal position.
$D002HPOSP2Player 2 horizontal position.
$D003HPOSP3Player 3 horizontal position.
$D004HPOSM0Missile 0 horizontal position.
$D005HPOSM1Missile 1 horizontal position.
$D006HPOSM2Missile 2 horizontal position.
$D007HPOSM3Missile 3 horizontal position.
$D008SIZEP0Player 0 size: 00=1× / 01=2× / 10=1× / 11=4×.
$D009SIZEP1Player 1 size.
$D00ASIZEP2Player 2 size.
$D00BSIZEP3Player 3 size.
$D00CSIZEMAll four missile sizes (2 bits each).
$D00DGRAFP0Player 0 shape pattern (DMA-disabled writes).
$D00EGRAFP1Player 1 shape pattern.
$D00FGRAFP2Player 2 shape pattern.
$D010GRAFP3Player 3 shape pattern.
$D011GRAFMMissile shape pattern.
$D012COLPM0Player/missile 0 colour.
$D013COLPM1Player/missile 1 colour.
$D014COLPM2Player/missile 2 colour.
$D015COLPM3Player/missile 3 colour.
$D016COLPF0Playfield 0 colour.
$D017COLPF1Playfield 1 colour.
$D018COLPF2Playfield 2 colour.
$D019COLPF3Playfield 3 colour.
$D01ACOLBKBackground / border colour.
$D01BPRIORPriority + GTIA mode select (bits 6-7).
$D01CVDELAYPer-channel vertical delay (P/M).
$D01DGRACTLPlayer/missile DMA enable + latch control.
$D01EHITCLRWrite strobe — clears collision latches.
$D01FCONSOL_WConsole-key output side / speaker bit.
AddrNamePurpose
$D000M0PFMissile 0 → playfield collision latch.
$D001M1PFMissile 1 → playfield.
$D002M2PFMissile 2 → playfield.
$D003M3PFMissile 3 → playfield.
$D004P0PFPlayer 0 → playfield.
$D005P1PFPlayer 1 → playfield.
$D006P2PFPlayer 2 → playfield.
$D007P3PFPlayer 3 → playfield.
$D008M0PLMissile 0 → player.
$D009M1PLMissile 1 → player.
$D00AM2PLMissile 2 → player.
$D00BM3PLMissile 3 → player.
$D00CP0PLPlayer 0 → player.
$D00DP1PLPlayer 1 → player.
$D00EP2PLPlayer 2 → player.
$D00FP3PLPlayer 3 → player.
$D010TRIG0Joystick trigger 0 (serial-pushed by rp-POKEY/PIA).
$D011TRIG1Joystick trigger 1.
$D012TRIG2Joystick trigger 2.
$D013TRIG3Joystick trigger 3.
$D014PALbit 0 = PAL, bit 1 = NTSC sense (serial-pushed).
$D015reservedRead 0.
$D016reservedRead 0.
$D017reservedRead 0.
$D018reservedRead 0.
$D019reservedRead 0.
$D01AreservedRead 0.
$D01BreservedRead 0.
$D01CreservedRead 0.
$D01DreservedRead 0.
$D01EreservedRead 0.
$D01FCONSOL_RConsole-key state (serial-pushed by rp-syscontroller).

Real silicon mirrors $D000-$D01F on every 32-byte boundary up to $D07F. fpga-antic preserves this mirror.

Reserved. No assignments yet — mirror behaviour does NOT apply here. Reads return 0; writes are ignored. Future GTIA-side extensions (player palette indexing, full-colour P/M) will land here; see the README’s “Future work” section.

AddrNamePurpose
$D400DMACTLDMA control. Bits: 0-1 playfield width, 2 missile DMA, 3 player DMA, 4 PM resolution (1=line, 0=2line), 5 DL DMA enable.
$D401CHACTLCharset control. Bits: 0 vertical reflect, 1 inverse video, 2 inverse blank.
$D402DLISTLDisplay-list pointer low byte.
$D403DLISTHDisplay-list pointer high byte.
$D404HSCROLHorizontal scroll, 0..15 colour clocks.
$D405VSCROLVertical scroll, 0..15 scan lines.
$D406reserved(Real ANTIC: PMBASE high byte mirror — not used in rp-XT, snoop tag handles PM region.)
$D407PMBASEPlayer/missile data page base (×256).
$D408reservedReads $FF; writes ignored.
$D409CHBASECharset RAM page base (×256).
$D40AWSYNCWait for horizontal sync (write strobe).
$D40BVCOUNTVertical line counter (read-only; bit 0 ignored, granularity = 2 scan lines).
$D40CPENHLight pen horizontal. (rp-XT stub: no lightpen — reads $FF.)
$D40DPENVLight pen vertical. (rp-XT stub: no lightpen — reads $FF.)
$D40ENMIENNMI enable: bit 6 VBI, bit 7 DLI, bit 5 RNMI.
$D40FNMIST / NMIRESRead = NMI status. Write = clear status.

Per real ANTIC (Altirra §4.1), every unassigned or write-only address in the canonical $D400-$D40F range reads back $FF — only VCOUNT ($D40B) and NMIST ($D40F) return live data. The chiplet-extension window ($D480-$D4FF) below differs: its unassigned addresses read 0.

Placeholder for a future second ANTIC instance on the same slot. Do not reuse for any other purpose.

Mirror of $D400-$D40F on every 16-byte boundary up to $D47F.

Layout per the README’s “Proposed map of register-space over and above ANTIC and C|GTIA”. Mirror behaviour does NOT apply here.

AddrNameR/WPurpose
$D480CLOCK_MULTRBus clock multiplier vs the NTSC 1.79 MHz baseline. Pushed in by rp-syscontroller over the inter-chip serial link during boot configuration; readable once $D7FF has fired.
$D481MODER/Wbit 0 MODE_SNOOP — 1 = snoop (default at /G_RST), 0 = legacy DMA. bit 1 CPU_INTERNAL — 1 = the internal SALLY drives the bus (software sets this once OS-B is loaded and locked; 0 = external CPU at boot). bit 2 reserved. bit 3 AUTO_PHI2_ON_EXTIRQ (M-PBI) — 1 = a falling edge on /EXTIRQ forces the bus clock back to phi2 (CLOCK_MULT = 1) until the PBI device deasserts /EXTIRQ. bits 4-7 are read-only PBI sense lines on read-back (bit 4 /RD4, bit 5 /RD5, bit 6 /MPD, bit 7 /EXTIRQ); writes to those bits are ignored.
$D482OUTPUT_MODER/WCompositing-mode selector (8-bit, defaults $00). HDMI scan-out is always 1920×1080@60 — the SiI9022A is configured once at boot and never re-initialised. bit 1 OUT_FULLRES — 0 = legacy ANTIC-compat (the XL framebuffer integer-scaled and centred in the 1080p frame with pillarbox/letterbox bars), 1 = native full-1920×1080 desktop (the GEM desktop + blitter + sprite engine target the full raster). bit 0 and bits 2-7 reserved. The register latches and reads back, but the plane compositor takes its geometry from build-time parameters and does not yet act on it.
$D483PAL_RR/WRed value (0..255) for the palette entry at PAL_IDX.
$D484PAL_GR/WGreen value.
$D485PAL_BR/WBlue value.
$D486PAL_IDXR/WPalette index (0..255) the next R/G/B trio targets.
$D487reserved-Reserved for extension to palette index (e.g. second palette page). Reads 0; writes ignored.
$D488DRAW_OPR/WDRAW opcode (BUS_DRAW_OP_*). M17-2. Software stages this + up to 5 args at $D489-$D492 then strobes DRAW_GO. op[7] is the fill flag for paired closed-shape primitives (RECT, OVAL, ARC) — set high to render filled instead of outline. FILL ($03) is a separate flood-fill primitive, not “RECT with op[7]=1”.
$D489DRAW_ARG0_LOR/WArg 0, low byte. (Args are little-endian 16-bit; semantics depend on DRAW_OP — for LINE: x0/y0/x1/y1/colour; for RECT (outline or fill): x/y/w/h/(colour+mode); for FILL (flood): x/y/colour, args 3-4 unused. See wire-protocol.md DRAW table.)
$D48ADRAW_ARG0_HIR/WArg 0, high byte.
$D48BDRAW_ARG1_LOR/WArg 1, low byte.
$D48CDRAW_ARG1_HIR/WArg 1, high byte.
$D48DDRAW_ARG2_LOR/WArg 2, low byte.
$D48EDRAW_ARG2_HIR/WArg 2, high byte.
$D48FDRAW_ARG3_LOR/WArg 3, low byte.
$D490DRAW_ARG3_HIR/WArg 3, high byte.
$D491DRAW_ARG4_LOR/WArg 4, low byte.
$D492DRAW_ARG4_HIR/WArg 4, high byte.
$D493DRAW_GOR/WWrite any value to commit the staged DRAW for dispatch to rp_tx. Read returns {7'h00, pending} — software MUST poll DRAW_GO[0]==0 before staging the next command (back-to-back GO writes while pending=1 are lost).
$D494DRAW_ARG5_LOR/WArg 5, low byte. Used by 7-beat opcodes — ARC’s start_angle (M18-2) and BEZIER_TO’s mid control point (M18.1).
$D495DRAW_ARG5_HIR/WArg 5, high byte.
$D496DRAW_ARG6_LOR/WArg 6, low byte. ARC’s end_angle / BEZIER_TO’s colour.
$D497DRAW_ARG6_HIR/WArg 6, high byte.
$D498DRAW_ARG7_LOR/WArg 7, low byte. Used by BEZIER (9-beat opcode) for the y-coord of the 4th control point.
$D499DRAW_ARG7_HIR/WArg 7, high byte.
$D49ADRAW_ARG8_LOR/WArg 8, low byte. BEZIER’s colour.
$D49BDRAW_ARG8_HIR/WArg 8, high byte.
$D49COS_ROM_ADDR_LOR/WChiplet OS-ROM loader (SALLY-driven; distinct from the PS/AXI sally_rom_loader). Target write-address low byte.
$D49DOS_ROM_ADDR_HIR/WTarget write-address high byte.
$D49EOS_ROM_DATAR/WWrite a byte → committed to memory at OS_ROM_ADDR, then OS_ROM_ADDR auto-increments (unless WRITE_LOCK set). Read returns the last byte written.
$D49FOS_ROM_CTLR/Wbit 0 = WRITE_LOCK: once set, further OS_ROM_DATA writes are ignored (ROM-load disabled).
$D4A0-$D4FFreserved-Future chiplet-extension registers. Reads 0; writes ignored.

The 256-entry full-RGB extended palette is exposed as the four-byte record at $D483-$D486 (R / G / B / IDX). A write to any of these four ports updates palette entry PAL_IDX with the latest R/G/B latched in the chip — order-independent. Per the README:

any change will update the palette index for all 4 parameters. This is not write-order dependent.

So programs can stream R G B IDX++ quartets in any internal order and the palette will be coherent after every write. The most common sequences are likely to be:

  • IDX, R, G, B (clear pattern; each colour fully written before IDX increments).
  • R, G, B, IDX (write the colour, then commit-by-IDX).

Both work identically.

The legacy hardware palette (COLBK / COLPF0-3 / COLPM0-3) is stored separately and indexes into the full 256-entry palette via its own small lookup; software written for canonical Atari hardware is unaffected.