Difference between revisions of "7800 HSC Technical Reference"

From 8BitDev.org - Atari 7800 Development Wiki
Jump to: navigation, search
(Created page with "= Atari 7800 High Score Cartridge (HSC) Technical Reference & Integration Guide = The '''Atari 7800 High Score Cartridge (HSC)''' is an expansion peripheral that provides non...")
 
Line 1: Line 1:
−
= Atari 7800 High Score Cartridge (HSC) Technical Reference & Integration Guide =
+
= Atari 7800 High Score Cartridge (HSC) Technical Reference =
  
 
The '''Atari 7800 High Score Cartridge (HSC)''' is an expansion peripheral that provides non-volatile battery-backed RAM (NVRAM) and a standardized high-score interface for Atari 7800 games. It connects via a pass-through architecture: the HSC plugs into the 7800 cartridge slot, and the game cartridge plugs into the top of the HSC.
 
The '''Atari 7800 High Score Cartridge (HSC)''' is an expansion peripheral that provides non-volatile battery-backed RAM (NVRAM) and a standardized high-score interface for Atari 7800 games. It connects via a pass-through architecture: the HSC plugs into the 7800 cartridge slot, and the game cartridge plugs into the top of the HSC.
Line 99: Line 99:
 
|}
 
|}
  
−
*(Note: Some disassemblies mislabel the vector at <code>$3FEE</code> as <code>$3FFE</code>. The physical address is <code>$3FEE</code>.)*
 
  
 
=== Calling Conventions ===
 
=== Calling Conventions ===

Revision as of 12:29, 1 October 2026

Atari 7800 High Score Cartridge (HSC) Technical Reference

The Atari 7800 High Score Cartridge (HSC) is an expansion peripheral that provides non-volatile battery-backed RAM (NVRAM) and a standardized high-score interface for Atari 7800 games. It connects via a pass-through architecture: the HSC plugs into the 7800 cartridge slot, and the game cartridge plugs into the top of the HSC.

System Architecture & Memory Map

Hardware Memory Map

Address Range Size Device Description
$1000–$17FF 2 KB Battery-Backed SRAM 2048 bytes of non-volatile storage (directories, scores, owner name).
$3000–$3FFF 4 KB HSC ROM High score BIOS, display list builders, font tiles, and API jump vectors.

Zero-Page Footprint ($80–$BC)

The HSC uses zero-page locations $80 through $BC (61 bytes total) for calculations, string manipulations, and pointers.

  • Automatic Zero-Page Preservation: Upon entry, the HSC backs up the caller's zero-page range $80–$BC into the game-provided RAM workspace at UserRAM + $13 through UserRAM + $4F.
  • Restoration on Exit: Prior to executing RTS, the HSC completely restores $80–$BC from the backup area.
  • $94/$95 Preservation: Locations $94 and $95 are saved to and restored from dedicated NVRAM scratchpad bytes ($1000 and $1001).

Dual-Page RAM Requirement (512 Contiguous Bytes)

When calling any HSC function, the game must provide a page-aligned 512-byte RAM workspace spanning two contiguous 256-byte pages: Page N and Page N+1.

Memory Layout of the 512-Byte Workspace:

Page N ($xx00 - $xxFF):
+-----------------------------------+ $xx00
|  18-Byte Argument Block ($00-$11) |
+-----------------------------------+ $xx12
|  HSC Internal Scratch ($12)       |
+-----------------------------------+ $xx13
|  Zero-Page Backup Area ($13-$4F)  | <- Holds saved ZP $80-$BC (61 bytes)
+-----------------------------------+ $xx50
|  Formatted Display Workspace      | <- Initials and score string buffer
+-----------------------------------+ $xxFF

Page N+1 ($xx00 + 1 page):
+-----------------------------------+ $(xx+1)00
|  MARIA Display Lists (DL)         | <- HSC writes screen graphics DLs here
+-----------------------------------+ $(xx+1)87
|  MARIA Display List List (DLL)    | <- DPPL=$87, DPPH=(Page N + 1)
+-----------------------------------+ $(xx+1)FF

CRITICAL ARCHITECTURAL WARNING:
The calling game must reserve both Page N and Page N+1. When the HSC renders score tables or the interactive initials screen, it points MARIA's Display List List pointer directly into Page N+1 (DPPH = Page N + 1, DPPL = $87). If only 256 bytes are allocated, the HSC display builder will overwrite program variables located in the subsequent page.

Cartridge Detection & Handshake

To verify that the High Score Cartridge is physically installed before invoking API routines, inspect the two signature bytes located in the HSC font table:

; ==============================================================================
; DetectHSC: Checks for HSC ROM presence
; Returns: Carry Flag Set (1) = HSC Present; Carry Flag Clear (0) = HSC Absent
; ==============================================================================
DetectHSC:
    LDA $3900               ; First signature byte in Font Row 6
    CMP #$C6
    BNE .HscNotFound
    LDA $3904               ; Second signature byte in Font Row 6
    CMP #$FE
    BNE .HscNotFound
    SEC                     ; HSC confirmed present
    RTS
.HscNotFound:
    CLC                     ; HSC not detected
    RTS

Public Vector Table & API Specification

The HSC exports seven primary functions via a jump table located at $3FEB–$3FFD.

Vector Address Routine Name Description
$3FEB HSCSETRS Configures MARIA registers (CTRL, CHARBASE, and P0C2–P4C2) for HSC font display.
$3FEE HSCCPYFM Raw copy: transfers 25 bytes of score data from Cart NVRAM to the pointer in ($8F).
$3FF1 HSCCPYTO Raw copy: transfers 25 bytes of score data from ($8F) into Cart NVRAM.
$3FF4 HSCENTER2 Headless entry: enters score without initials screen (initials passed in buffer).
$3FF7 HSCSTAT Status/rank query: allocates slot if missing; checks if score qualifies.
$3FFA HSCATRCT Attract mode: renders and cycles high score tables for each difficulty level.
$3FFD HSCENTER Interactive entry: checks rank, displays initials screen, shifts table, and saves.


Calling Conventions

All HSC API routines require the following register state upon entry:

  • Y Register: Must contain the Page Number (High Byte) of the argument block (e.g., LDY #$25 for $2500).
  • X Register: Must be set to #$00.
  • Interrupts & Decimal Flag: Handled automatically by HSCInitRoutine (executes SEI and CLD).
  • Stack Note: HSCInitRoutine pushes temporary frame marker bytes ($3C, $2B) to the stack. Routines called via standard JSR will return cleanly via RTS.

User Argument Block Specification (Page N)

The argument block resides at Page N + $00 through Page N + $11 (18 bytes).

Offset Size Field Name Description
+$00 1 ArgGameID1 Game ID byte 1 (Unique Atari Cart ID, e.g., $8B for Joust).
+$01 1 ArgGameID2 Game ID byte 2 (e.g., $23 for Joust).
+$02 1 ArgGameDifficulty Bits 7–2: Difficulty setting (masked with $FC).
Bits 1–0: Active controller index (0 = Player 1, 1 = Player 2).
+$03 1 ArgGameController Controller driver: $00/$01 = Standard Joystick; $02 = Custom Routine.
+$04 2 ArgGameNamePtr Pointer (16-bit Lo/Hi) to Watkins-encoded Game Title string (or custom driver).
+$06 2 ArgDifficultyNamePtr Pointer (16-bit Lo/Hi) to Watkins-encoded Difficulty text string.
+$08 2 ArgGameScorePtr Pointer (16-bit Lo/Hi) to 4-byte packed BCD score data in game RAM.
+$0A 2 ArgLogoDllPtr Pointer (16-bit Lo/Hi) to Game Logo Display List List (DLL), or 0 if using text title.
+$0C 2 ArgSoundRoutinePtr Pointer (16-bit Lo/Hi) to sound callback executed during attract wait loops.
+$0E 1 ArgHSDisplayTime Attract mode screen display timer multiplier.
+$0F 4 Returned Status Rank and checksum status bytes returned by HSCSTAT (offsets +$0F–$12).
+$13 61 ZP Preservation Area Scratchpad reserved for HSC to save/restore Zero-Page $80–$BC.

Field Specifications

ArgGameDifficulty (Offset +$02)
Bits 7..2 represent the game difficulty index. The HSC maintains separate 5-score tables for each difficulty level. Bits 1..0 specify which player's controller is polled during initials entry and attract screen skipping.
ArgGameController (Offset +$03)
When set to $00 or $01, the HSC directly reads the RIOT and TIA registers (SWCHA, INPT4, INPT5). When set to $02, the HSC executes an indirect jump to (ArgGameNamePtr) to poll custom controllers.
ArgGameScorePtr (Offsets +$08, +$09)
Pointer to a 4-byte (8-digit) packed BCD score in Big-Endian order:
1,234,560 points = $01, $23, $45, $60
Maximum score value: 16,777,215 ($16 $77 $72 $15 in BCD). Values higher than this will be clamped to $FFFFFF.
ArgSoundRoutinePtr (Offsets +$0C, +$0D)
Pointer to the game's audio driver. During attract mode display and initials entry loops, the HSC executes JSR (ArgSoundRoutineLo) once per frame.
Returned Rank Status (Offset +$05 on return from HSCSTAT)
* $01–$05: The submitted score qualifies for 1st through 5th place.
* $FF: The submitted score did not qualify.

Data Representations & Internal Encodings

Watkins Character Set & Font Map

The HSC does not use ASCII. Text strings must use the proprietary Watkins encoding matching the internal font table at $3900–$3F00.

Hex Dec Glyph Hex Dec Glyph Hex Dec Glyph
$00 0 A $0F 15 P $1E 30 ' (Apostrophe)
$01 1 B $10 16 Q $1F 31 ← (Left / Erase)
$02 2 C $11 17 R $20 32 █ (Block Cursor)
$03 3 D $12 18 S $21 33 0
$04 4 E $13 19 T $22 34 1
$05 5 F $14 20 U $23 35 2
$06 6 G $15 21 V $24 36 3
$07 7 H $16 22 W $25 37 4
$08 8 I $17 23 X $26 38 5
$09 9 J $18 24 Y $27 39 6
$0A 10 K $19 25 Z $28 40 7
$0B 11 L $1A 26 . (Period) $29 41 8
$0C 12 M $1B 27 : (Colon) $2A 42 9
$0D 13 N $1C 28 - (Hyphen) $2B 43 ? (Question Mark)
$0E 14 O $1D 29 (Space)

DASM Watkins macro:

    mac WATKINS
        dc.b {1}-"A"
    endm

15-Bit Packed Initials Format

Initials consist of three 5-bit characters ($00–$1F) packed into 2 consecutive bytes:

Character 0: C0 [4..0]
Character 1: C1 [4..0]
Character 2: C2 [4..0]

Byte 0: [ C1.4 | C1.3 | C1.2 | C0.4 | C0.3 | C0.2 | C0.1 | C0.0 ]
Byte 1: [ C1.1 | C1.0 |   0  | C2.4 | C2.3 | C2.2 | C2.1 | C2.0 ]

Packing Algorithm

; Inputs: Initials in ZP buffer (z98) at offsets 0, 1, 2
; Outputs: A = Packed Byte 0, Y = Packed Byte 1
PackInitials:
    LDY #$01
    LDA (z98),Y         ; Character 1
    AND #$1C            ; Mask bits 4, 3, 2
    ASL
    ASL
    ASL                 ; Shift to bits 7, 6, 5
    DEY
    ORA (z98),Y         ; Combine with Character 0 (bits 4..0)
    PHA                 ; Save Byte 0
    INY
    LDA (z98),Y         ; Character 1
    AND #$03            ; Mask bits 1, 0
    CLC
    ROR
    ROR
    ROR                 ; Rotate bits 1, 0 into bits 7, 6
    INY
    ORA (z98),Y         ; Combine with Character 2 (bits 4..0)
    TAY                 ; Y = Byte 1
    PLA                 ; A = Byte 0
    RTS

Unpacking Algorithm

; Inputs: A = Byte 0, X = Byte 1
; Outputs: A = Char 0, X = Char 1, Y = Char 2
UnpackInitials:
    PHA
    AND #$E0            ; Mask bits 7..5 of Byte 0
    LSR
    LSR
    LSR
    STA zB1             ; zB1 = C1 bits 4..2
    TXA
    AND #$1F
    TAY                 ; Y = Char 2 (bits 4..0 of Byte 1)
    TXA
    AND #$C0            ; Mask bits 7..6 of Byte 1
    CLC
    ROL
    ROL
    ROL                 ; Rotate to bits 1..0
    ORA zB1
    TAX                 ; X = Char 1
    PLA
    AND #$1F            ; A = Char 0
    RTS
  • Default Initials: The placeholder initials "..." (Period, Period, Period = 26, 26, 26 / $1A, $1A, $1A) pack into Byte 0 = $DA, Byte 1 = $9A.

Score Conversion: BCD to 24-Bit Binary

While games supply a 4-byte packed BCD score pointer, the HSC converts the score into a 24-bit binary integer for ranking and Cart NVRAM storage:

  1. Unpack and Multiply: Routine e3AA8 converts the 4-byte BCD digits into a 24-bit unsigned binary integer stored across three zero-page registers: zAD (LSB), zAE (MID), and zAF (MSB).
  2. NVRAM Storage: The score is saved as a little-endian 24-bit integer occupying 3 bytes:
    • Offset +0: Initials Byte 0
    • Offset +1: Initials Byte 1
    • Offset +2: Score LSB (bits 0–7)
    • Offset +3: Score MID (bits 8–15)
    • Offset +4: Score MSB (bits 16–23)
  3. Display Formatting: When drawing score tables, routine e37BC converts the 24-bit binary integer back into decimal characters using a table of powers of 10 ($989680 = 10,000,000 down to $000001 = 1).

Cartridge NVRAM Layout ($1000–$17FF)

Address Range Size Field Identifier Description
$1000–$1001 2 CartRAMSaveZ94/Z95 Storage for caller's zero-page $94/$95.
$1002–$1006 5 CartRAMMagic Magic bytes ($68, $83, $AA, $55, $9C).
$1007 1 CartRAMEntryID ID of entry point currently executing.
$1008–$1027 32 CartRAMOwnerName Cartridge owner string (Watkins encoding).
$1028 1 CartRAMOwnerNameLength Length of owner name string.
$1029–$106D 69 CartRAMGameID1Table Game ID 1 table (up to 69 game configurations).
$106E–$10B2 69 CartRAMGameID2Table Game ID 2 table.
$10B3–$10F7 69 CartRAMGameDifficultyTable Game Difficulty table (difficulty masked with $FC).
$10F8–$113C 69 CartRAMGameIndexTable LRU aging table (prefilled with $7F).
$113D–$17F9 1725 Score Data Blocks 69 tables × 25 bytes (5 scores per table).
$17FA–$17FE 5 CartRAMTempScore Scratch buffer used when shifting scores down.
$17FF 1 Unused Unused byte.

Directory Lookup & LRU Allocation

  • Capacity: Up to 69 distinct (Game ID 1 + Game ID 2 + Difficulty) entries.
  • Lookup: HSCInitRoutine searches backwards (indices 68 down to 0) for matching ID and difficulty bytes.
  • LRU Eviction: If all 69 slots are occupied and a new game or difficulty is registered, the slot with the highest aging index in CartRAMGameIndexTable is purged and replaced.
  • Table Address Formula:
<math>\text{TableAddress} = \$113D + (\text{SlotIndex} \times 25)</math>
  • Each 25-byte block stores 5 entries of 5 bytes each, ordered from 1st place (offset +$00) to 5th place (offset +$14).

7800 Assembly Integration Example

Argument Block Template

; ==============================================================================
; ROM Argument Template
; ==============================================================================
HscRomTemplate:
    .byte $8B, $23          ; Game ID 1 and 2
    .byte $00               ; Difficulty (Bits 7..2) | Controller (Bits 1..0)
    .byte $00               ; Controller Type: $00 = Standard Joystick
    .word HscTitleText      ; Pointer to Watkins Game Name string
    .word HscDiffText       ; Pointer to Watkins Difficulty string
    .word GameScoreBcd      ; Pointer to 4-byte packed BCD score in RAM
    .word 0                 ; Logo DLL Pointer (0 = Use standard text title)
    .word GameSoundCallback ; Sound playback callback routine
    .byte $04               ; Display Duration Multiplier (Attract speed)

HscTitleText:
    WATKINS "M"
    WATKINS "Y"
    .byte $1D               ; Watkins space
    WATKINS "G"
    WATKINS "A"
    WATKINS "M"
    WATKINS "E"
    .byte $1D

HscDiffText:
    WATKINS "E"
    WATKINS "A"
    WATKINS "S"
    WATKINS "Y"
    .byte $1D

Attract Mode Screen Display

; ==============================================================================
; ShowHighScores: Displays high score table during attract loop
; ==============================================================================
ShowHighScores:
    JSR DetectHSC
    BCC .ExitNoHsc          ; Skip if HSC is not present

    ; Copy configuration template to Page N RAM ($2500)
    LDX #14
.CopyArgs:
    LDA HscRomTemplate,X
    STA $2500,X
    DEX
    BPL .CopyArgs

    ; Set desired difficulty (Bits 7..2)
    LDA CurrentDifficulty   ; e.g., 0, 1, 2
    ASL
    ASL
    STA $2502

    ; Call HSC Attract Mode Vector
    LDX #$00
    LDY #$25                ; Y = Page $25 ($2500 argument block)
    JSR $3FFA               ; HSCATRCT

    ; Restore game video registers and display list pointers
    JSR RestoreGameScreen
.ExitNoHsc:
    RTS

Game Over Score Submission

; ==============================================================================
; SubmitScore: Checks rank qualification and launches initials entry screen
; ==============================================================================
SubmitScore:
    JSR DetectHSC
    BCC .ExitNoHsc

    ; Setup argument block at $2500
    LDX #14
.SetupArgs:
    LDA HscRomTemplate,X
    STA $2500,X
    DEX
    BPL .SetupArgs

    LDA CurrentDifficulty
    ASL
    ASL
    STA $2502

    ; Check if score qualifies
    LDX #$00
    LDY #$25
    JSR $3FF7               ; HSCSTAT

    LDA $2505               ; Read returned rank
    CMP #$FF                ; $FF = Did not qualify
    BEQ .DidNotQualify

    ; Score qualifies! Run interactive initials entry screen and save
    LDX #$00
    LDY #$25
    JSR $3FFD               ; HSCENTER

    JSR RestoreGameScreen
.DidNotQualify:
.ExitNoHsc:
    RTS