Cracking GEI T3 Compression (1986)
Reverse-engineering a Z80 bit-packing scheme to unlock 50,816 questions from GEI Series 8-18 and the gt103 variant pack
April 10, 2026 · crack, gei, greyhound, z80
GEI T3 Compression (Series 8+)
Greyhound Electronics · 1986+ · Z80 @ 4 MHz · TRIV3D ROM board · 50,816 records across 60+ category chips
The Cabinet
In 1986, Greyhound Electronics changed how their trivia ROMs stored questions. The earlier Series 1-7 chips held plaintext ASCII, readable in any hex editor. Series 8 shipped with a new compressed format, T3, and the data looked like noise.
Whether the switch was driven by anti-cloning, by storage efficiency (T3 packs three times as many questions into twice the storage), or both, isn’t documented in any source I’ve found. The later T4/T5/T8 boards did add a PAL chip dongle gating decode on a hardware signature, which suggests anti-tampering became a concern at some point. Either way the technical effect was the same. No readable text, Shannon entropy of 7.4 bits per byte, and the format stayed uncracked for 40 years.
The T3 format shipped on the same Z80 hardware family as the earlier “UT” plaintext series, same Toms River cabinet, same five EPROM sockets, same subscription model. The only thing that changed was the encoding inside each chip and the addition of a PAL-chip dongle on later boards (T4 / T5 / T8) to gate decoding on a hardware signature.
The Data
All 50,816 cracked records browse at /browse?source=gei , Series 8 through 18, the gt103 variant pack, plus the T5/T8 sister formats. (Series A and B shipped on the earlier plaintext “UT” format and live with the Greyhound Electronics post .)
- Extractor:
scripts/gei/extract.py - T3 decompressor:
scripts/gei/format.py
How We Cracked It
The T3 ROM
A T3 ROM still announces itself. The first two bytes are T3, followed by the category name in plaintext:
0000: 54 33 53 50 4F 52 54 53 FF 1E 02 T3SPORTS...
After the 0xFF delimiter: a 2-byte little-endian question count (here 0x021E = 542 questions), then a pointer table, 542 entries of 2-byte addresses, same structure as Series 1-7. The pointers are self-consistent: the first data pointer matches the end of the pointer table.
But the question data is opaque:
046E: C0 25 09 5D 00 0D CE 57 7E 7A 1E 38 81 4E A0 50
047E: 24 11 4F 00 42 56 DC 3D 49 3E 2E 1D 85 06 85 7E
No ASCII. No obvious repeating patterns. Records average 56 bytes, too short for plaintext questions with three answers.
The Attack
Step 1: Capture Decoded Output
The Z80 firmware knows how to decode these questions, it does it every time a player drops a quarter. So we let it.
A MAME Lua script automated gameplay: insert coin, select category, wait for the question to render, then read the decoded text buffer at address $4090. The game’s own CPU did the decompression for us.
-- Read decoded question from game's text buffer
for i = 0, 255 do
local b = space:read_u8(0x4090 + i)
if b == 0x04 then break end -- end marker
...
end
67 unique decoded questions captured, each with full text and three answers. Now we had known plaintext.
Step 2: Find the ROM Pointer
Knowing the decoded text is useless without knowing which ROM record produced it. We needed the address.
Dumping RAM from $4000-$4070 alongside each decoded question revealed that address $4037 held a 16-bit pointer into the question ROM, the address of the current record’s data. Cross-referencing these pointers against the ROM’s pointer table confirmed the match. We now had 19 confirmed pairs: exact ROM bytes mapped to exact decoded text.
Step 3: The Numbers Don’t Add Up
First observation: the math was wrong for every simple encoding we tried.
One confirmed pair, “HOW MANY SETS ARE IN A FULL-LENGTH MEN’S CHAMPIONSHIP TENNIS MATCH” with answers “FIVE”, “THREE”, “SEVEN”, decoded to 88 intermediate character values. The ROM record was 46 bytes. That’s 4.18 bits per character. Not 8 (plaintext), not 5 (5-bit packing), not 4 (nibbles). Nothing clean.
Worse, different questions had different ratios, 2.6 to 5.7 bits per character. A fixed-width encoding was impossible.
Step 4: Disassemble the Decompressor
The answer was in the firmware. Cross-referencing references to the $4090 buffer and the $4037 ROM pointer led to Z80 code at $2D00-$2D75, the decompression loop.
The code reads two bytes from ROM, extracts three 5-bit values through a sequence of shifts and masks, writes them to the buffer in a shuffled order (positions 0, 2, 1), then checks the high bit for a separator flag. When four separators have been emitted, decompression is complete.
The Algorithm
Each 2-byte word packs three 5-bit values into 15 bits. The 16th bit is a field separator flag.
byte2 byte1
┌───┬───────────┬─────┐ ┌─────┬───────────┐
│ F │ value 1 │v3 hi│ │v3 lo│ value 2 │
│ 7 │ 6 5 4 3 2 │ 1 0 │ │ 7 6 5│ 4 3 2 1 0 │
└───┴───────────┴─────┘ └─────┴───────────┘
value1 = (byte2 >> 2) & 0x1F
value3 = (byte2 & 3) << 3 | (byte1 >> 5)
value2 = byte1 & 0x1F
flag = byte2 >> 7
Three characters per word. The third value straddles the byte boundary, its high 2 bits come from byte2’s low bits, its low 3 bits from byte1’s high bits.
After decompression, a second routine at $2D76 converts 5-bit values to displayable characters:
0x00 → space
0x01-0x1A → A-Z (letter mode) or special chars (digit mode)
0x1C → newline
0x1E → toggle letter/digit mode
0x1F → field separator
In letter mode, values map to ASCII via +0x40. In digit mode, +0x20, so the same value 0x12 produces R in letter mode and 2 in digit mode. A 0x1E byte toggles between them. This lets numbers and punctuation share the same 5-bit value space as letters.
Why the Ratios Varied
The variable bits-per-character ratio that initially confused us comes from three sources:
Mode toggles: Every digit, quote, or comma costs an extra 0x1E byte. “1984” needs a toggle in, four digits, and a toggle out, 6 values for 4 displayed characters.
The separator flag: Field separators (between question and answers) consume zero data bits when they align with the flag bit. A word that happens to be the last in a field gets its flag set for free.
Short answers: “FIVE” is 4 characters + separator = 5 values in ~4 bytes. “AUSTRALIAN FOOTBALL” is 19 characters in ~13 bytes. The overhead is amortized differently.
The Content
50,816 questions across 60+ category chips spanning Series 8 through 18 plus the compilation and gt103 variant packs:
Series 8: 2,666 questions (Science, General, Sports, Entertainment, Adult Sex)
Series 8a: 522 questions (Potpourri)
Series 9: 1,776 questions (Facts, Rock-N-Roll, Television, USA Trivia)
Series 10: 1,859 questions (New Entertainment, New General, New Sports, New TV Mash)
Series 11: 2,321 questions (Aerospace, Cars & Women, General Facts, Rich & Famous, TV Music)
Series 11a: 426 questions (Gay Times)
Series 11b: 2,226 questions (Adult Sex 3)
Series 12: 2,198 questions (Cops & Robbers, Famous Quotes, New Science 2, Rock Music, Vices)
Series 12a: 2,263 questions (NFL Football)
Series 14: 2,448 questions (Famous Couples, Horrors, The Sixties, TV Comedies, War & Peace)
Series 14a: 2,360 questions (Adult Sex 5)
Series 15: 2,169 questions (Entertainment 2, Facts 2, New Science 3, NFL Football)
Series 18: 2,572 questions (Adult Sex 9, Entertainment 3, More Sports, Super Trivia, This Is Music)
gt103 vars: 8,422 questions (History-Geog, NFL Football, Soccer, Adult Sex 2-5, alternate sets)
Other: 16,588 questions (Multi-Game, GT507 UK, Quiz / Quiz 211 / Quizvid (Italian),
Sex Appeal, Sex Trivia 1-2, Sports Authority)
Sample questions:
[aerospace] How many astronauts have set foot on the moon since the space program started
✓ Twelve ✗ Six / Eight
[vices] What did "Madame Moustache" serve to suckers she fleeced in her saloon
✓ Champagne ✗ Cocaine / Opium
[famous_quotes] "Good is not good when better is expected"
✓ Vin Lombardi ✗ Babe Ruth / Joe Namath
[cops_&_robbers] During the 1930's, who did a remarkable job of littering the streets of Chicago
✓ Al Capone ✗ Baby Face Nelson / John Dillinger
[horrors] Who directed the 1983 sequel "Psycho II"
✓ Richard Franklin ✗ Alfred Hitchcock / Anthony Perkins
[gay_times] In what year did England reduce the penalty for male homosexual acts from death
✓ 1861 ✗ 1901 / 1921
The categories are peak 1986: Vices, Cops & Robbers, Cars & Women, Gay Times. GEI knew their audience, the after-work bar crowd, and the content reflects it. No corporate focus groups. No sensitivity reads. Just a concrete factory in New Jersey shipping EPROMs.
T5 and T8: Same Algorithm, Different Header
The T3 decompressor also cracks GEI’s T5 and T8 format ROMs. These use
identical 5-bit word packing, the version byte in the header changes, and
an 8-byte PAL signature (00 FF 01 FD 05 F5 15 D5) is inserted after the
version tag, but the question data is bit-for-bit the same encoding.
Sports Authority (T8, 1987): 3,933 questions across 9 sport-specific banks, Premiere Baseball, Basketball, Football, Hockey, Auto Racing, Assorted Sports, Super Bowl, and two Series II expansions.
Multi-Game (T5, 1986): 2,200 questions from the multi-game compilation board, Adult Sex, Entertainment, Facts, NFL Football alongside card and slot games on the same PCB.
T4: Series 15, 18, and Beyond
Series 15 and 18 use a T4 format header with an 8-byte PAL signature at
bytes $02-$09. The Z80 firmware checks this signature against values
from a PAL chip on the TRIV3D ROM board, a hardware dongle to prevent
ROM piracy.
The signature check only gates loading. Once past it, the question data uses the same 5-bit word packing as T3. Our extractor skips the signature bytes and decodes directly, yielding 2,309 questions from Series 15 (Entertainment 2, Facts 2, New Science 3, NFL Football) and 2,572 from Series 18 (Adult Sex 9, Entertainment 3, More Sports, Super Trivia, This Is Music).
The findout (Italian market) and quiz211 ROMs also use T4 headers.
Quiz 211, an Italian-language trivia set, was decoded the same way, 1,047
questions in Italian, the only non-English content in the archive.
Arcade Trivia Archive, data extracted from MAME ROM dumps using a custom Python decoder.
References
Related
More cracks
Cross-archive analyses
GEI T3 compression family1 (1984-1991, Greyhound Electronics) · Arcade-Museum · MAME romset:
gtsers8+↩︎