; lenser -- slideshow viewer (self-contained code; pictures are separate files) ; ; Boots first on the disk (LOAD"*",8,1 then RUN) and steps through NIMAGES ; picture files named "00".."NN", each a PRG that KERNAL-loads to $2000 -- ; $2000 bitmap 8000 (always) ; $3F40 screen 1000 (always -> copied to the buffer's video matrix) ; $4328 colram 1000 (multicolor only -> $D800) ; $4710 background 1 (multicolor only -> $D021) ; The per-image byte in ss_modes selects hires(0) vs multicolor(1) setup. mono ; uses the hires path. WAITMODE (viewer/wait.i) selects key / seconds / both. ; ; DOUBLE BUFFERED so the previous slide stays on screen while the next loads ; (no blank between slides). Two VIC banks alternate as front/back buffer: ; buffer 0 -- VIC bank 0, bitmap $2000, video matrix $0400 ($DD00 bits %11) ; buffer 1 -- VIC bank 1, bitmap $6000, video matrix $4400 ($DD00 bits %10) ; Both use $D018=$18 (matrix at bank+$0400, bitmap at bank+$2000); only the ; $DD00 bank bits differ, so the swap is a single write. Each slide is KERNAL- ; loaded into the *back* buffer (secondary address 0, so the file's $2000 header ; is ignored and it lands at the buffer's base) while the front buffer -- the ; previous picture -- stays displayed; then a bank flip makes it the front. ; ss_hi = ss_buf*$40 is the high-byte offset ($00 buffer 0, $40 buffer 1) added ; to every buffer-relative address. Colour RAM ($D800) is shared, so for a ; multicolor slide it is copied at the swap (a hires slide needs none, and swaps ; perfectly cleanly). ; ; assembled by viewer/assemble.py via xa; the ss_modes table is appended after ; this file by the generated wrapper, and NIMAGES / LOOPFLAG / WAITMODE etc. are ; #defined there. ; BASIC autostart, SYS 2061 * = $0801 .word basicend .word 10 .byte $9e .byte "2061" .byte 0 basicend: .word 0 ; ML begins at $080D SRC = $fb DST = $fd start: lda #$00 sta $9d ; suppress KERNAL LOAD messages sta ss_idx ; start at the first image sta ss_buf ; first slide loads into buffer 0 sta $d020 ; border black (once) lda #$0b sta $d011 ; display off -- the only blank, before slide 0 mainloop: jsr name_build ; ss_name = "NN" from ss_idx jsr setup_hi ; ss_hi = ss_buf * $40 lda #$ff sta $cc ; cursor off (blink can't corrupt $D800) ; ---- KERNAL LOAD "NN" into the BACK buffer ($2000 or $6000) ---- ; secondary address 0 -> the file's $2000 header is ignored and the data ; is loaded to the address passed in .X/.Y, so one data file can serve ; either buffer. The front buffer stays displayed throughout. lda #2 ldx #ss_name jsr $ffbd ; SETNAM lda #1 ldx #8 ldy #0 ; SA 0 -> load to .X/.Y address jsr $ffba ; SETLFS ldx #$00 ; load address low = $00 lda #$20 clc adc ss_hi tay ; load address high = $20 + ss_hi lda #0 ; 0 = load (not verify) jsr $ffd5 ; LOAD ; ---- copy screen RAM (base+$1F40) -> this buffer's video matrix ---- ; (into the still-hidden back buffer, so it is invisible) lda #$40 sta SRC lda #$3f clc adc ss_hi sta SRC+1 ; SRC = $3F40 / $7F40 lda #$00 sta DST lda #$04 clc adc ss_hi sta DST+1 ; DST = $0400 / $4400 jsr copy1024 ; ---- per-image mode -- 0 = hires/mono, 1 = multicolor ---- ldx ss_idx lda ss_modes,x beq ss_hires ; multicolor -- colour RAM (base+$2328) -> $D800, background from base+$2710 lda #$28 sta SRC lda #$43 clc adc ss_hi sta SRC+1 ; SRC = $4328 / $8328 lda #$00 sta DST lda #$d8 sta DST+1 jsr copy1024 lda #$10 sta SRC lda #$47 clc adc ss_hi sta SRC+1 ; SRC = $4710 / $8710 ldy #$00 lda (SRC),y sta $d021 ; background colour jsr flip_bank ; make the back buffer the front lda #$d8 sta $d016 ; multicolor on jmp ss_on ss_hires: jsr flip_bank ; make the back buffer the front lda #$c8 sta $d016 ; hires (multicolor off) ss_on: lda #$18 sta $d018 ; matrix bank+$0400, bitmap bank+$2000 lda #$3b sta $d011 ; bitmap mode, display on lda ss_buf eor #$01 sta ss_buf ; next slide loads into the other buffer #include "wait.i" ; ---- advance to the next image ---- inc ss_idx lda ss_idx cmp #NIMAGES bcc ss_go ; still more images #if LOOPFLAG == 1 lda #$00 sta ss_idx ; wrap around forever ss_go: jmp mainloop #else jmp ss_end ; done -> restore and return to BASIC ss_go: jmp mainloop ss_end: #endif ; ---- restore text mode and return to BASIC ---- lda $dd00 ora #$03 sta $dd00 ; VIC bank 0 lda #$1b sta $d011 lda #$c8 sta $d016 lda #$15 sta $d018 lda #$0e sta $d020 ; default border (light blue) lda #$06 sta $d021 ; default background (blue) lda #$00 sta $cc jsr $e544 ; clear screen rts ; ss_hi = ss_buf * $40 (high-byte offset for the current back buffer) setup_hi: ldy #$00 lda ss_buf beq sh_set ldy #$40 sh_set: sty ss_hi rts ; point VIC at the current buffer's bank (buffer 0 -> bank 0, buffer 1 -> bank 1) flip_bank: lda ss_buf bne fb_one lda $dd00 ora #$03 sta $dd00 ; bank 0 ($0000-$3FFF) rts fb_one: lda $dd00 and #$fc ora #$02 sta $dd00 ; bank 1 ($4000-$7FFF) rts ; build the 2-char filename "NN" from ss_idx (0..99) name_build: lda ss_idx ldx #$2f sec ss_ten: inx sbc #10 bcs ss_ten adc #10 ; remainder 0..9 (carry was clear on exit) ora #$30 sta ss_name+1 ; ones digit (PETSCII) txa sta ss_name ; tens digit (PETSCII) rts ; copy 1024 bytes from (SRC) to (DST) copy1024: ldx #4 ldy #0 cploop: lda (SRC),y sta (DST),y iny bne cploop inc SRC+1 inc DST+1 dex bne cploop rts ss_idx: .byte 0 ss_buf: .byte 0 ; 0 or 1 -- which buffer the next slide loads into ss_hi: .byte 0 ; ss_buf * $40 (buffer high-byte offset) ss_name: .byte $30,$30 ; "00", rebuilt each slide from ss_idx ; ss_modes table (.byte per image) appended by viewer/assemble.py's wrapper