8bitlenser/lenser/viewer/cart.s
2026-07-03 19:35:35 -07:00

177 lines
4.8 KiB
ArmAsm

; lenser -- C64 cartridge viewer (runs from ROM at $8000), fully self-contained.
;
; Unlike the disk viewer (a PRG at $0801 with the picture appended), this runs
; from a 16K cartridge. It copies the image data block -- appended after this
; code in ROM -- down to $2000 (same layout the disk viewer wants, bitmap at
; $2000, screen $3F40, and for multicolor colram $4328 + bg $4710), programs the
; VIC, and holds the picture. It uses NO KERNAL/IRQ services (a 16K cart hides
; BASIC and the autostart entry runs before the KERNAL fully initialises), so it
; polls the hardware directly -- CIA1 for the keyboard, the raster for timing.
;
; #defines set by viewer/assemble.py --
; MCMODE 0 = hires, 1 = multicolor
; NPAGES number of 256-byte pages of image data to copy
; WAITMODE 0 forever / 1 until a key / 2 about WAITSECS seconds
; WAITSECS, RATE (frames per second, 50 PAL / 60 NTSC)
;
; assembled by viewer/assemble.py via xa
* = $8000
.word cold ; cold-start vector
.word cold ; NMI / warm vector
.byte $c3,$c2,$cd,$38,$30 ; CBM80 autostart signature
SRC = $fb
DST = $fd
CNT = $02 ; 16-bit frame countdown (seconds mode)
cold:
sei
ldx #$ff
txs
cld
; map the standard memory layout so BOTH halves of the 16K cart are
; visible -- ROML $8000-$9FFF and ROMH $A000-$BFFF (needs HIRAM=1) -- plus
; I/O at $D000. Set the data latch ($01) BEFORE the DDR ($00): on a cart
; cold-start the latch may be low while the DDR is all-inputs (so the port
; reads the correct map via pull-ups). Enabling the DDR first would drive
; that low latch onto the port, bank ROML out, and crash the next fetch
; (this is exactly what failed in VICE).
lda #$37
sta $01 ; LORAM+HIRAM+CHAREN = ROML, ROMH, I/O, KERNAL
lda #$2f
sta $00 ; now enable the port outputs
; VIC bank 0 ($0000-$3FFF) so the VIC sees our bitmap at $2000
lda #$3f
sta $dd02 ; CIA2 port A bits 0-5 = output
lda #$c7
sta $dd00 ; bank 0 (bits 0-1 = 11)
lda #$0b
sta $d011 ; blank during setup
; ---- copy NPAGES of image data from ROM (datasrc) to $2000 ----
lda #<datasrc
sta SRC
lda #>datasrc
sta SRC+1
lda #$00
sta DST
lda #$20
sta DST+1
ldx #NPAGES
ldy #$00
dcopy:
lda (SRC),y
sta (DST),y
iny
bne dcopy
inc SRC+1
inc DST+1
dex
bne dcopy
; ---- copy screen RAM $3F40 -> $0400 ----
lda #$40
sta SRC
lda #$3f
sta SRC+1
lda #$00
sta DST
lda #$04
sta DST+1
jsr copy1024
#if MCMODE == 1
; ---- copy colour RAM $4328 -> $D800 ----
lda #$28
sta SRC
lda #$43
sta SRC+1
lda #$00
sta DST
lda #$d8
sta DST+1
jsr copy1024
#endif
; ---- program the VIC-II ----
lda #$00
sta $d020 ; border black
#if MCMODE == 1
lda $4710
sta $d021 ; background colour
lda #$d8
sta $d016 ; multicolor on
#endif
#if MCMODE == 0
lda #$c8
sta $d016 ; hires
#endif
lda #$18
sta $d018 ; screen $0400, bitmap $2000
lda #$3b
sta $d011 ; bitmap mode, display on
; ---- hold the picture ----
#if WAITMODE == 0
forever:
jmp forever
#endif
#if WAITMODE == 1
lda #$ff
sta $dc02 ; CIA1 port A = output (column select)
lda #$00
sta $dc03 ; CIA1 port B = input (row read)
sta $dc00 ; drive all keyboard columns low
kwait:
lda $dc01 ; rows; $FF = no key, any key pulls a row low
cmp #$ff
beq kwait
jmp $fce2 ; reset (a 16K cart can't return to BASIC)
#endif
#if WAITMODE == 2
lda #<(WAITSECS*RATE)
sta CNT
lda #>(WAITSECS*RATE)
sta CNT+1
sloop:
sw1:
lda $d012
cmp #$fa
bne sw1 ; wait until raster reaches line 250
sw2:
lda $d012
cmp #$fa
beq sw2 ; wait until it leaves -> one frame elapsed
lda CNT
bne sdec
dec CNT+1
sdec:
dec CNT
lda CNT
ora CNT+1
bne sloop
jmp $fce2 ; reset
#endif
copy1024:
ldx #4
ldy #0
c1k:
lda (SRC),y
sta (DST),y
iny
bne c1k
inc SRC+1
inc DST+1
dex
bne c1k
rts
datasrc:
; image data block appended here by the packager