Cracking Exidy Fax (1983)

How we decoded 3,584 trivia questions from a binary tree compressed into 22 ROM chips

April 5, 2026 · crack, exidy, 6502


← Archive

Exidy Fax

Exidy · 1983 · 6502 CPU · 22 ROM chips · 3,584 records across History, Sports, Entertainment, Grab Bag


The Game

Exidy Fax hit bar tops in 1983, one of the first coin-op trivia machines ever shipped to American drinking establishments, years before Greyhound Electronics, NTN, or the Merit bar-top boom. The cabinet was a table-format unit with a small color monitor under glass, four answer buttons (A/B/C/D), and a coin slot that accepted quarters (later tokens, as operators wised up to the all-night-stamina player). You’d drop in a coin, pick a category from History, Sports, Entertainment, or “Grab Bag”, pick a difficulty from easy/medium/hard, and answer ten questions per credit.

Exidy, the company, was a California outfit born in 1973 that shipped Crash (the first hit-and-killer driving game), Mouse Trap, and Venture. They were not a trivia company, they were a mainstream arcade manufacturer with a hit in Chiller and a steady output of dedicated cabinets. Fax was their attempt to capture the bar market before the format had a name. It shipped with an astonishing 4,800 questions packed into 176 KB across 22 separate ROM chips, a volume that required compression techniques nobody else in 1983 was using.

The Data

All 3,584 cracked records browse at /browse?source=exidy_fax . filterable by category and difficulty (easy / medium / hard). Cross-checked against 97 MAME-captured questions: 100% match.


How We Cracked It

The Question

And that’s why Fax sat un-extracted for forty years. Unlike every other trivia game of the era (plaintext ASCII, sometimes with a light XOR), Fax used a binary-tree Huffman-like compression with an XOR’d dictionary. The data in the ROMs looks like random bytes. The 6502 program ROM actively decompresses each question at play time by walking a tree. To read the questions, we had to reverse the decompression routine. That’s four layers deep.

Layer 1: XOR Encryption

The first barrier. Every byte in the dictionary ROM (fxd-1c.64, “bank 0”) is XOR’d with 0x56. This was discovered by disassembling the 6502 program ROM and finding the instruction at $FA12:

  $FA0E: INX
  $FA0F: JSR $F9BA      ; read raw byte from bank 0
  $FA12: EOR #$56       ; ← XOR with 0x56
  $FA14: STA $85,X      ; store decoded byte
  $FA16: BPL $FA0E      ; loop until high bit set

After XOR decoding, the first bytes of the ROM spell out HISTORY, SPORTS, ENTERTAINMENT, GRAB BAG, the four category headers. Each terminated by a byte with the high bit set (bit 7 = 1), a convention from the 6502 era where RAM was precious and a single bit could serve as both data and delimiter.

Layer 2: The 194-Word Dictionary

After the four category headers and 48 bytes of metadata, a single byte announces the dictionary size: 0xC2 (194 in decimal). What follows are 194 strings, common trivia words, each terminated by a high-bit byte:

  Raw ROM:    3C 25 21 F2   (4 bytes)
  XOR 0x56:   6A 73 77 A4
  Masked:     'y' 'e' 'a' 'r'|0x80
  Result:     "year"  (high bit on 'r' marks end)

  Dictionary sample (194 words):
   [0] year    [1] yards   [2] wrote    [3] world
   [4] won     [5] with    [6] which    [7] what
   ...
   [88] first  [99] did    [114] and    [172] In
   [194] Black [196] Battle [201] Baseball [204] Adams

The words are sorted roughly reverse-alphabetically: lowercase common words first (year, yards, wrote, world), then proper nouns (York, World, William, Washington), then numbers (100, 10, 000). These 194 words cover the most common vocabulary in 1983 bar trivia.

Layer 3: The Binary Tree

After the dictionary, at offset 0x0439 in bank 0, sits the compression engine: a binary decision tree. Every two bytes form one node:

  Node format (2 bytes, raw, no XOR):

  If byte0 < 0xFE:   Internal node
     byte0 = left child offset    (relative, in 2-byte units)
     byte1 = right child offset

  If byte0 == 0xFE:  Dictionary leaf
     byte1 = word index (0-193)
     → emit dictionary word

  If byte0 == 0xFF:  Literal/control leaf
     byte1 = ASCII character code  → emit single character
     byte1 = 0x7C                  → difficulty separator
     byte1 = 0x5C                  → end/continuation marker

The tree root is at offset 0x0439. Here are the first nodes:

  0439: 02 01   internal node (left=2, right=1)
  043B: 03 02   internal node (left=3, right=2)
  043D: 05 04   internal node (left=5, right=4)
  043F: 06 05   internal node
  0441: 01 06   internal node
  0443: FF 20   ← literal SPACE (0x20)
  0445: 08 06   internal node
  ...
  044F: FF 0D   ← literal CR (carriage return)
  0453: FF 65   ← literal 'e'
  0457: FF 61   ← literal 'a'
  045D: FF 72   ← literal 'r'

Space and e are the most common symbols, they live closest to the root, reached in the fewest bits. Rare proper nouns are deeper.

Layer 4: The Bitstream

The actual question data is a compressed bitstream spread across all 22 ROM banks (176KB). Each bit selects left (0) or right (1) at each tree node. When a leaf is reached, the symbol is emitted and the walk restarts from the root.

  Category metadata (48 bytes, 4 categories × 3 difficulties):

  HISTORY    easy:   bank 0,  $28AF, 7 bits
  HISTORY    medium: bank 1,  $3798, 1 bit
  HISTORY    hard:   bank 3,  $30EE, 4 bits
  SPORTS     easy:   bank 5,  $317A, 3 bits
  ...
  GRAB BAG   hard:   bank 19, $3DFD, 6 bits

  The "bits" value is the starting bit position within the
  first byte (consumed MSB-first: 7→6→5→...→0).

  The $F9E5 routine auto-advances through banks:
  when the address crosses $3FFF, it wraps to $2000
  and increments the bank number.

Layer 5: Difficulty Interleaving

Each question position in the bitstream contains data for all three difficulty levels, separated by FF 7C markers. The game selects one randomly and skips the others:

  [easy question + answers]  FF 7C
  [medium question + answers] FF 7C
  [hard question + answers]   FF 5C (end)

This means 3× more data per position. A question like “Alaska was purchased from what country?” at easy difficulty shares a bitstream position with a harder variant at the same topic.

Putting It Together

To decode one question, the 6502 CPU:

  1. Selects a bank and starting address from the category metadata
  2. Reads one byte from the data bank → 8 bits of navigation
  3. For each bit, follows left or right child in the tree (in bank 0)
  4. On reaching a leaf: emits a dictionary word or literal character
  5. When bits exhaust, reads the next byte (auto-advancing through banks)
  6. On FF 7C: decrements difficulty counter, skips if non-zero
  7. On FF 5C: question complete

Results

3,584 unique questions extracted across 4 categories and 3 difficulty levels. Cross-checked against 97 MAME-captured questions, 100% match.

  HISTORY        easy: 252  medium: 313  hard: 308
  SPORTS         easy: 286  medium: 299  hard: 293
  ENTERTAINMENT  easy: 276  medium: 345  hard: 295
  GRAB BAG       easy: 279  medium: 316  hard: 322

  Sample:
  [HISTORY/easy] Alaska was purchased from what country
    ✓ Russia  ✗ China / Canada / Germany

  [SPORTS/medium] Which boxer retired undefeated
    ✓ Gene Tunney  ✗ Floyd Patterson / Joe Walcott / Joe Louis

  [ENTERTAINMENT/hard] What movie star was known as "The Mellin's Baby"
    ✓ Humphrey Bogart  ✗ Paul Newman / Mickey Rooney / Clint Eastwood

The compression ratio is impressive for 1983: 194 dictionary words + a binary tree + bitstream packing achieved roughly 5:1 compression on trivia text. The same approach , Huffman-like tree coding with a domain dictionary, would not be out of place in a modern compression library.

The difficulty tier is preserved in our extraction, you can filter by easy, medium, and hard on the browse page, alongside the four categories.


Arcade Trivia Archive, data extracted from MAME ROM dumps using a custom Python decoder. Extractor: scripts/fax/fax_tree_decode.py


References


Cross-archive analyses


  1. Fax1 (1983, Exidy, Inc. (Sunnyvale, CA)) · Arcade-Museum · Flyer · MAME romset: fax ↩︎