"""CoCo 3 GIME hi-res viewer (Motorola 6809 machine code, Program Pak ROM). Autostarts from the cartridge at $C000 in CoCo-compatible mode, then switches the GIME into a native graphics mode. Because turning on GIME mode (writing $FF90) can change the memory map under the running code, the setup runs in two stages: 1. At $C000 (cart ROM): mask interrupts, copy the 15360-byte image down to RAM at $4000, program the GIME palette + mode/geometry/video-base registers (these are safe while still in legacy mode), then plant a tiny stub in RAM. 2. Jump to the RAM stub, which writes $FF90 (COCO=0 -> GIME graphics on) and idles. Running from RAM means the map change can't pull the code out from under us. The GIME shows a LINEAR 80-byte x 192-row screen from physical video base $14000, which is exactly where CPU $4000 lives with the MMU disabled. """ from __future__ import annotations from ..coco.mc6809 import Asm CART_BASE = 0xC000 IMG_CPU = 0x4000 # image copied here (RAM, visible to GIME video) IMG_LEN = 15360 # 80 bytes/row * 192 rows IMG_END = IMG_CPU + IMG_LEN # $7C00 STUB_CPU = 0x3E00 # tiny "enable GIME + idle" stub (RAM) # physical video base for CPU $4000 with the MMU disabled. CoCo 3 maps the 64K # CPU space to blocks $38-$3F (bank+0x38); on the 512K machine bank 2 ($4000) is # block $3A = physical $74000. base = FF9D<<11 | FF9E<<3. FF9D = 0xE8 # $74000 >> 11 FF9E = 0x00 def build(data_src: int, cres: int, inks, border: int) -> bytes: """data_src: cart address of the image bytes; cres: GIME colour-resolution bits (0=2col, 1=4col, 2=16col); inks: pen->6-bit-colour list; border: 6-bit.""" a = Asm(CART_BASE) a.orcc(0x50) # mask IRQ + FIRQ # copy the image from cart ROM down to RAM at $4000 a.ldx_imm(data_src) a.ldu_imm(IMG_CPU) a.label("copy") a.lda_postinc("x") a.sta_postinc("u") a.cmpu_imm(IMG_END) a.bne("copy") # GIME palette: 16 pen registers $FFB0-$FFBF (unused pens -> 0) for pen in range(16): a.lda_imm(inks[pen] if pen < len(inks) else 0) a.sta_ext(0xFFB0 + pen) a.lda_imm(border & 0x3F) a.sta_ext(0xFF9A) # border colour a.lda_imm(0x80) a.sta_ext(0xFF98) # VMODE: graphics, 1 line/row a.lda_imm(0x14 | (cres & 0x03)) a.sta_ext(0xFF99) # VRES: 192 lines, 80 bytes/row, CRES a.lda_imm(FF9D) a.sta_ext(0xFF9D) # video base hi a.lda_imm(FF9E) a.sta_ext(0xFF9E) # video base lo # plant the RAM stub: lda #0 ; sta $FF90 ; bra * (enable GIME, then idle) for off, byte in enumerate((0x86, 0x00, 0xB7, 0xFF, 0x90, 0x20, 0xFE)): a.lda_imm(byte) a.sta_ext(STUB_CPU + off) a.jmp_ext(STUB_CPU) return a.resolve()