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

272 lines
7.4 KiB
ArmAsm

; lenser -- Atari static-playfield slideshow viewer (GR.15 / GR.9 / GR.8).
;
; Self-booting (OS loads this to $2000, JSRs $2006). Steps through NIMAGES
; pictures stored as raw sectors -- image i at sectors BASESEC + i*SPI -- SIO-
; reading SPI sectors and showing each before advancing (key / seconds / both).
;
; DOUBLE BUFFERED so the previous slide stays on screen while the next loads (no
; blank between slides). Two RAM buffers alternate as front/back --
; buffer 0 -- bitmap $4000/$5000, colour bytes $6000
; buffer 1 -- bitmap $7000/$8000, colour bytes $9000
; both kept below $A000 so they are RAM even when the BASIC ROM is enabled. The
; display list's two LMS addresses point at the front buffer; each slide is SIO-
; read into the *back* buffer while the front (the previous picture) keeps
; displaying, then -- during a vertical blank so the change isn't torn -- the LMS
; addresses and colour registers are switched to it. ss_hi = ssbuf*$30 is the
; high-byte offset ($00 buffer 0, $30 buffer 1) added to every buffer address.
;
; The mode is fixed for the whole slideshow, chosen by build-time #defines --
; DLMODE ANTIC mode byte ($0e GR.15, $0f GR.9/GR.8)
; GPRIOR GTIA priority/mode ($00, or $40 for GR.9)
; COLORMODE colour-register layout (0 GR.15 / 1 GR.9 / 2 GR.8)
; plus WAITMODE/WAITSECS/RATE, NIMAGES, LOOPFLAG, BASESEC, SPI (see assemble.py).
colptr = $cb ; zero-page pointer to the back buffer's colours
* = $2000
boot:
.byte 0 ; flags
.byte 0 ; sector count (patched by the ATR writer)
.word $2000 ; load address
.word binit ; init address (DOSINI)
cont: ; $2006 -- OS JSRs here after loading the stub
lda #<dlist
sta $230 ; SDLSTL
lda #>dlist
sta $231 ; SDLSTH
lda #GPRIOR
sta $26f ; GPRIOR
lda #$00
sta $22f ; SDMCTL = 0 (blank before the first image only)
sta ssidx
sta ssbuf ; first slide loads into buffer 0
ssmain:
jsr sethi ; ss_hi = ssbuf * $30
jsr readimg ; SIO-load image ssidx into the back buffer
; ---- wait for a vertical blank, then flip to the back buffer ----
; (the front buffer -- the previous slide -- has stayed on screen)
lda $14
vbwait:
cmp $14
beq vbwait ; RTCLOK ticked -> we are in the vertical blank
; display-list LMS -- region 1 = base, region 2 = base + $1000
lda #$00
sta lms1
sta lms2
lda #$40
clc
adc ss_hi
sta lms1+1 ; $40 / $70
lda #$50
clc
adc ss_hi
sta lms2+1 ; $50 / $80
; colour bytes are at base + $2000
lda #$00
sta colptr
lda #$60
clc
adc ss_hi
sta colptr+1 ; $60 / $90
#if COLORMODE == 0
ldy #$00
lda (colptr),y
sta $2c8 ; COLBAK (value 0)
ldy #$01
lda (colptr),y
sta $2c4 ; COLPF0 (value 1)
ldy #$02
lda (colptr),y
sta $2c5 ; COLPF1 (value 2)
ldy #$03
lda (colptr),y
sta $2c6 ; COLPF2 (value 3)
#endif
#if COLORMODE == 1
ldy #$00
lda (colptr),y
sta $2c8 ; COLBAK = hue (GR.9)
#endif
#if COLORMODE == 2
ldy #$00
lda (colptr),y
sta $2c6 ; COLPF2 background
sta $2c8 ; COLBAK border = background
ldy #$01
lda (colptr),y
sta $2c5 ; COLPF1 foreground
#endif
lda #$22
sta $22f ; SDMCTL on (a no-op after the first slide)
jsr sswait
lda ssbuf
eor #$01
sta ssbuf ; next slide loads into the other buffer
inc ssidx
lda ssidx
cmp #NIMAGES
bcc ssmain
#if LOOPFLAG == 1
lda #$00
sta ssidx
jmp ssmain
#else
lda #$00
sta $09 ; clear BOOT? so warmstart enters BASIC
jmp $e474 ; warm-start (exit)
#endif
binit:
rts
; ss_hi = ssbuf * $30 (back-buffer high-byte offset -- $00 buffer 0, $30 buffer 1)
sethi:
ldx #$00
lda ssbuf
beq sh0
ldx #$30
sh0:
stx ss_hi
rts
; ---- SIO read SPI sectors of image ssidx into the back buffer (base+$0000) ----
readimg:
lda #<BASESEC
sta secn
lda #>BASESEC
sta secn+1
ldx ssidx
beq rsbuf
radd:
clc
lda secn
adc #SPI
sta secn
bcc ra1
inc secn+1
ra1:
dex
bne radd
rsbuf:
lda #$00
sta $0304 ; DBUFLO = $00
lda #$40
clc
adc ss_hi
sta $0305 ; DBUFHI = $40 / $70 (back buffer base)
lda #SPI
sta cnt
rloop:
lda #$31
sta $0300 ; DDEVIC = disk
lda #$01
sta $0301 ; DUNIT 1
lda #$52
sta $0302 ; DCOMND R (read)
lda #$40
sta $0303 ; DSTATS = read direction
lda #$1f
sta $0306 ; DTIMLO
lda #$80
sta $0308 ; DBYTLO = 128
lda #$00
sta $0309 ; DBYTHI
lda secn
sta $030a ; DAUX1 sector low
lda secn+1
sta $030b ; DAUX2 sector high
jsr $e459 ; SIOV
clc
lda $0304
adc #$80
sta $0304 ; buffer += 128
bcc rb1
inc $0305
rb1:
inc secn
bne rb2
inc secn+1
rb2:
dec cnt
bne rloop
rts
; ---- wait (returns; defeats attract mode via $4d) ----
sswait:
#if WAITMODE == 1
lda #$ff
sta $2fc ; clear CH
sw1:
lda #$00
sta $4d
lda $2fc
cmp #$ff
beq sw1
rts
#endif
#if WAITMODE == 2
lda #$00
sta $12
sta $13
sta $14 ; reset RTCLOK
sw2:
lda #$00
sta $4d
lda $13
cmp #>(WAITSECS*RATE)
bcc sw2
bne sw2d
lda $14
cmp #<(WAITSECS*RATE)
bcc sw2
sw2d:
rts
#endif
#if WAITMODE == 3
lda #$ff
sta $2fc
lda #$00
sta $12
sta $13
sta $14
sw3:
lda #$00
sta $4d
lda $2fc
cmp #$ff
bne sw3d ; any key ends the slide
lda $13
cmp #>(WAITSECS*RATE)
bcc sw3
bne sw3d
lda $14
cmp #<(WAITSECS*RATE)
bcc sw3
sw3d:
rts
#endif
ssidx: .byte 0
ssbuf: .byte 0 ; 0 or 1 -- which buffer the next slide loads into
ss_hi: .byte 0 ; ssbuf * $30 (back-buffer high-byte offset)
secn: .word 0
cnt: .byte 0
dlist:
.byte $70,$70,$70 ; 24 blank scan lines
.byte DLMODE+$40 ; LMS + mode
lms1:
.word $4000 ; region 1 base (patched to the front buffer)
.dsb 101,DLMODE
.byte DLMODE+$40 ; LMS + mode
lms2:
.word $5000 ; region 2 base (patched to the front buffer)
.dsb 89,DLMODE
.byte $41 ; JVB
.word dlist