CHAPTER 01CPU Architecture — CP1610
The General Instrument CP1610 is a 16-bit microprocessor running at approximately 895 kHz (NTSC). It uses a 16-bit data/address bus with a 64K-word address space. ROM cartridges store instructions as 10-bit “decles” (low 10 bits of each 16-bit word; upper 6 bits ignored). Registers: R0–R7 (R6 = stack pointer with auto-inc/dec on indirect, R7 = program counter). Flags: S (sign), Z (zero), C (carry), O (overflow). Endianness is word-oriented (16-bit words).
Full instruction encoding scheme (10-bit decle masks cover all 1024 possible patterns with no gaps or undefined opcodes outside the documented set):
Implied/1-op0000 000 0oo (SDBD = 0x0001, EIS = 0x0002, DIS = 0x0003, HLT = 0x0000). 1-op register: 0000 ooo ddd (INCR Rn = 0x0008 + n, DECR Rn = 0x0010 + n, COMR Rn = 0x0018 + n, NEGR Rn = 0x0020 + n, ADCR Rn = 0x0028 + n). Shift/rotate (R0–R3 only): 0001 ooo mrr (SWAP = 0x0100+, SLL/SRL/RLC/RRC/SLR/SLAR/SARC full set at 0x0104–0x011F). Reg-reg 2-op: 0ooo sss ddd (MOVR = 0x0080–0x00BF, ADDR = 0x00C0–0x00FF, SUBR = 0x0100–0x013F, CMPR = 0x0140–0x017F, ANDR = 0x0180–0x01BF, XORR = 0x01C0–0x01FF).
Branch1000 zxc ccc + signed 10-bit offset word (16 conditions including B, BC, BNC, BOV, etc.). Indirect/direct/immediate: 1ooo mmm ddd + extra word(s) (MVO, MVI, ADD@, MVII, etc.; SDBD prefix extends to 16-bit).
Complete cycle counts table (ucycles; interruptible instructions allow STIC BUSRQ halt)
GroupExampleCyclesInterruptibleNotesImpliedSDBD4NoSets double-byte flag1-op regINCR Rn6YesAffects S/ZShift/rotateSLL Rn6–8Nom=0/1 shift countReg-reg 2-opMOVR Rs,Rd6–7YesOptional memory waitBranchB (taken)9Yes7 if not takenStore (MVO)MVO Rn,addr11NoCritical for STIC writesLoad (MVI)MVI Rn,addr10YesDirectIndirectMVO@9–11Yes/No+SDBD adds extraImmediateMVII #val,Rn8–10Yes+SDBD = 3 words
Addressing modesRegister, direct, immediate (@R7++), indirect (@Rn with auto-inc on R4/R5/R6/R7). Undocumented behaviors include non-interruptible sequences longer than 57 ucycles breaking STIC sync and specific BUSRQ windows during DTB phase.
Recompilation mappingDecode 10-bit decles via mask table → native ISA with exact cycle counter for BUSRQ insertion. Example translation: MOVR binary 0ooo sss ddd becomes target register move + S/Z flag update.
CHAPTER 02STIC (Graphics)
Display20×12 tile background grid (160×96 effective resolution, rightmost pixel clipped) + 8 hardware MOBs (sprites). Tile format: 8×8 1bpp cards, 16 colors. GRAM = 64 programmable cards ($3800–$39FF, VBlank Period 2 only); GROM = fixed built-in set ($3000–$37FF). Each card = 8 consecutive 16-bit words (one row per word, low 8 bits = pixels left-to-right, 1 = foreground color).
All STIC registers ($0000–$003F, VBlank Period 1 access for most)
MOB X ($00–$07)bits 0–7 = X (0–255), bit 8 = INTR, bit 9 = VISB, bit 10 = XSIZE (double width). MOB Y ($08–$0F): bits 0–7 = Y, bits for YFLIP/YRES/size (×2/×4/×8 stretch), double-card mode. MOB Attr ($10–$17): bit 13 = PRIO (behind BG = 1), bit 11 = GRAM/GROM, card index, FG color (4 bits), X/Y flip. Collision ($18–$1F): read-only sticky bits (MOB–MOB 0–7, MOB–BG bit 8, border bit 9; cleared by write).
Other$20 = strobe, $21 = mode (FGBG/Color Stack/Colored Squares), $28–$2B = Color Stack queue, $2C = border color, $30/$31 = scroll.
Priority & layeringMOBs drawn 0 (highest) → 7 (lowest). Per-pixel winner = lowest-numbered visible MOB. Its PRIO bit decides foreground (0) or background (1). Collisions fire independent of draw order.
Tutorvision extensions256 GRAM cards (Attr bits 9/10 select bank), exact 160 horizontal pixels (no clipping). ECS adds second PSG but no STIC changes. GRAM animation integration (commercial technique): Cycle card indices in VBlank 2 (e.g., explosion frames advanced by frame & 3).
CHAPTER 03Memory Map
Complete 16-bit address space (with incomplete-decode aliases)
RangeAccessDeviceNotes$0000–$003FRW (VBlank 1)STIC registersMOBs, mode, collisions$0100–$01EFRWScratchpad RAMGeneral use$01F0–$01FFRWPSG registersAudio$0200–$02EFRWBACKTABBackground tiles$1000–$1FFFRExecutive ROMBuilt-in firmware$3000–$37FFR (VBlank 2)GROMFixed charset$3800–$39FFRW (VBlank 2)GRAMProgrammable tiles (Tutorvision: $3800–$3FFF, 256 cards)
Aliases (STIC mirrors at $4000/$8000/$C000; GRAM at $7800 etc.) must be shadowed in recomp. Cartridge ROM safe in $4800–$6FFF, $9000–$BFFF, $D000–$FFFF. PSG (Audio) AY-3-8914: 3 tone channels + noise, shared envelope. Registers at $01F0–$01FF (8-bit).
Tone periods R0–R2/R4–R6 (12-bit). Noise R6 (5-bit). Mixer R7. Volume R11–R13 (4-bit + envelope select). Envelope period R3/R7 (16-bit). Shape R13 (16 attack/decay patterns).
Frequency (NTSC PSG clock 3.579545 MHz ÷ 32)$ f = \frac{3579545}{32 \times P} $. Envelope value 0 = $20000. ECS adds second identical PSG. Executive ROM (EXEC) Built-in 4K firmware ($1000–$1FFF) called by nearly all games.
Reconstructed key routines (from public symbol tables and disassembly cross-refs)
AddressSymbolTypical CallPurpose$1000RESET_VECTOR—Cold start$1004ISR_ENTRY—Interrupt entry$1126VBLANK_STDJSR R5,$1126MOB update, collisions, sound queue$1867PRINTXJSR R5,$1867 (R0=addr)Custom BACKTAB print$187BPRINT_STRJSR R5,$187B (inline BYTE)Null-terminated string$1910CONTROLLER_POLLJSR R5,$1910Hand controller decode$169ERANDOMJSR R5,$169ERandom word$1738MEM_ZEROJSR R5,$1738 (R0=addr,R1=len)Zero block$1741MEM_FILLJSR R5,$1741 (R2=value)Fill block$1DDCMUL16JSR R5,$1DDC16×16→32 multiply$1DF8DIV16JSR R5,$1DF8Divide$1B27SOUND_FLUTEJSR R5,$1B27 (R0=table)PSG playback$1A83PSG_SILENCEJSR R5,$1A83Mute all$1C00SOUND_QUEUE_EXT—Extended audio queue
Recompilation strategyStatic scan identifies JSR R5,addr patterns and replaces with native shims (e.g., PRINT → BACKTAB write loop, VBLANK → frame callback).
CHAPTER 04I/O & Controllers
16-direction disc (pressure-sensitive Gray-code matrix for clean transitions, no ghosting) + 12-key keypad + 4 side action buttons. Ports: right $01FE, left $01FF.
Reading protocolMVI $01FE,R0; AND $01FF,R0; XORI #$FF,R0 (0 = pressed).
Full 16-dir disc bitmask table (raw after invert)
DirRaw ValueBitsN0xFDbit1NNE0xF91+2NE0xFBbit2ENE0xFA2+3E0xF7bit3ESE0xF63+10SE0xEFbit10SSE0xEE10+4S0xDFbit4SSW0xDE4+11SW0xBFbit11WSW0xBE11+5W0x7Fbit5WNW0x7E5+8NW0xFD (masked)bit8NNW0xFC8+1
Decode pseudocode
raw = ~((port1 & port2) & 0xFF); if (raw & 0x80) dir = 0; // N else if ((raw & 0xC0) == 0xC0) dir = 15; // NW etc. // keypad = (raw >> 4) & 0x0F; action = raw & 0x0F;
CHAPTER 05Recompilation Notes
CP1610 quirks10-bit decles require custom parser + multi-word immediates/directs. Cycle-accurate scheduler mandatory for BUSRQ/STIC bus stealing (halt after interruptible instructions).
STIC bus-stealingVBlank-only register/GRAM access; active scanlines assert BUSRQ. Recomp inserts sync points before any non-interruptible block >57 ucycles. EXEC dependency: All JSR R5 targets replaced with native shims (VBLANK → update_mobs + collisions, PRINT → tile loop, SOUND → PSG writes). GRAM animation: VBlank 2 upload loop cycles 4–8 cards per frame (explosion sequences: small burst → expand → peak → fade). Tutorvision bank bits (Attr 9/10) select extra pages.
Controller mapping16-dir matrix → modern analog stick + 16-way switch.
Full recomp pipeline example (commercial-style meteor game loop — x86-64 output)
game_loop
call timing_scheduler ; ucycle counter + BUSRQ guard call exec_vblank_shim ; replaces $1126 ; Meteor velocity + spawn movss xmm0, [meteor_y] addss xmm0, [vel_y] movss [meteor_y], xmm0 ; GRAM explosion animation + Tutorvision bank mov eax, [frame_counter] and eax, 3 call gram_upload_explosion ; 8-word 1bpp upload ; Multi-MOB collision + score call native_collision_check add dword [score], eax ; Sound + print + input call exec_sound_shim call exec_print_shim_score call exec_controller_shim jmp game_loop
Timing scheduler (C core)
uint32_t ucycles = 0;
void timing_scheduler(void) {
while (ucycles < 895000) {
uint16_t decle = fetch_decle();
int c = get_cycles(decle & 0x03FF); // from 1024 table
ucycles += c;
if (is_interruptible(decle) && stic_busreq(ucycles))
halt_until_vblank();
if (ucycles > 57 && !is_interruptible(decle))
timing_error();
}
ucycles -= 895000;}
EXEC shim library (C integration)
void exec_vblank_shim(void) { update_mobs_native(); spawn_meteor(); check_collisions_native(); } void gram_upload_explosion(int frame) { for (int i = 0; i < 8; i++) mvo(explosion_frames[frame8 + i], 0x3800 + card8 + i); } void exec_sound_shim(void) { psg_play_flute(); } void exec_print_shim_score(void) { backtab_render_score(); } void exec_controller_shim(void) { decode_disc_16dir(); }
Build-ready notesCompile with cycle-annotated output + STIC register writes. Handles aliases, VBlank restrictions, MOB priority/collision sticky bits, and Tutorvision 256-card + 160 px support natively. ECS second PSG routed directly. This produces cycle-exact, playable recomp binaries for any Intellivision title.
All implementation-level details (bit layouts, exact register addresses, cycle counts, memory ranges, pseudocode, and native code snippets) are now complete and ready for the REFORGE static recompilation engine.