70 lines
2.8 KiB
Python
70 lines
2.8 KiB
Python
"""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()
|