graphics: dgr: animation: tmbg

a quick tmbg animation
This commit is contained in:
Vince Weaver
2025-12-16 19:58:29 -05:00
parent 9910cde56a
commit 2b87ed7e94
16 changed files with 1924 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
;=========================
; copy to 400
;=========================
; copies from page X to $400
copy_to_400_aux:
jsr setup_400
sta WRAUX
jmp do_copy_to_400
setup_400:
stx c400_smc1+2
stx c400_smc2+2
inx
stx c400_smc3+2
stx c400_smc4+2
inx
stx c400_smc5+2
stx c400_smc6+2
inx
stx c400_smc7+2
stx c400_smc8+2
lda DRAW_PAGE
clc
adc #$4
tax
stx c400_smc9+2
stx c400_smc10+2
inx
stx c400_smc11+2
stx c400_smc12+2
inx
stx c400_smc13+2
stx c400_smc14+2
inx
stx c400_smc15+2
stx c400_smc16+2
rts
copy_to_400_main:
jsr setup_400
do_copy_to_400:
ldx #119
looper1:
c400_smc1:
lda $2000,X
c400_smc9:
sta $400,X
c400_smc2:
lda $2080,X
c400_smc10:
sta $480,X
c400_smc3:
lda $2100,X
c400_smc11:
sta $500,X
c400_smc4:
lda $2180,X
c400_smc12:
sta $580,X
c400_smc5:
lda $2200,X
c400_smc13:
sta $600,X
c400_smc6:
lda $2280,X
c400_smc14:
sta $680,X
c400_smc7:
lda $2300,X
c400_smc15:
sta $700,X
c400_smc8:
lda $2380,X
c400_smc16:
sta $780,X
dex
bpl looper1
sta RDMAIN
sta WRMAIN
rts
+181
View File
@@ -0,0 +1,181 @@
include ../../../../Makefile.inc
DOS33 = ../../../../utils/dos33fs-utils/dos33
DOS33_RAW = ../../../../utils/dos33fs-utils/dos33_raw
EMPTY_DISK = ../../../../empty_disk/empty.dsk
TOKENIZE = ../../../../utils/asoft_basic-utils/tokenize_asoft
LINKER_SCRIPTS = ../../../../linker_scripts/
GENERATE_COMMON = ../generate_common
all: tmbg.dsk
tmbg.dsk: QBOOT QLOAD \
MUSIC \
music.inc qload.inc \
ANIMATION
cp $(EMPTY_DISK) tmbg.dsk
$(DOS33_RAW) tmbg.dsk 0 0 QBOOT 0 1
$(DOS33_RAW) tmbg.dsk 0 2 QBOOT 1 1
$(DOS33_RAW) tmbg.dsk 0 4 QBOOT 2 1
$(DOS33_RAW) tmbg.dsk 1 0 QLOAD 0 0
$(DOS33_RAW) tmbg.dsk 2 0 MUSIC 0 0
$(DOS33_RAW) tmbg.dsk 5 0 ANIMATION 0 0
####
ANIMATION: animation.o
ld65 -o ANIMATION animation.o -C $(LINKER_SCRIPTS)/apple2_6000.inc
animation.o: animation.s \
zp.inc ../hardware.inc qload.inc common_defines.inc \
../sound_bars.s ../change_palette.s ../patch_graphics.s \
graphics/tmbg01.aux.zx02 graphics/tmbg02.aux.zx02
ca65 -o animation.o animation.s -l animation.lst
# graphics/frame1_frame3_diff.inc graphics/frame2_frame4_diff.inc \
# graphics/frame3_frame5_diff.inc graphics/frame4_frame6_diff.inc \
# graphics/frame5_frame7_diff.inc graphics/frame6_frame8_diff.inc \
# graphics/frame7_frame1_diff.inc graphics/frame8_frame2_diff.inc \
####
QBOOT: qboot_sector.o
ld65 -o QBOOT qboot_sector.o -C $(LINKER_SCRIPTS)/apple2_800.inc
qboot_sector.o: qboot_sector.s qboot_stage2.s
ca65 -o qboot_sector.o qboot_sector.s -l qboot_sector.lst
####
QLOAD: qload.o
ld65 -o QLOAD qload.o -C $(LINKER_SCRIPTS)/apple2_1200.inc
qload.o: zp.inc ../hardware.inc common_defines.inc music.inc qload.s \
../gr_offsets.s \
../wait.s \
../wait_a_bit.s \
../gr_fast_clear.s \
../text_print.s \
../hgr_table.s \
../pt3lib/lc_detect.s \
../pt3lib/pt3_lib_detect_model.s \
../pt3lib/pt3_lib_mockingboard_detect.s \
../pt3lib/pt3_lib_mockingboard_setup.s \
../pt3lib/interrupt_handler.s \
../pt3lib/pt3_lib_mockingboard_patch.s \
../irq_wait.s \
../hgr_page_flip.s \
../hgr_clear_screen.s \
start.s
ca65 -o qload.o qload.s -l qload.lst
####
qload.inc: $(GENERATE_COMMON) QLOAD
$(GENERATE_COMMON) -a 0x1200 -s load_file qload.lst > qload.inc
$(GENERATE_COMMON) -a 0x1200 -s detect_appleii_model qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s clear_all qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s clear_all_color qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s set_normal qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s set_inverse qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait_a_bit qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait_50ms qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s move_and_print qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s detect_language_card qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s mockingboard_detect qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s clear_bottom qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s clear_bottoms qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s clear_screens qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s clear_top qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s zx02_full_decomp qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s zx_src_h qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s zx_src_l qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait_until_keypress qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s hgr_draw_sprite qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait_50xms qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s random8 qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s wait_vblank qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait_seconds qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait_for_pattern qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s wait_ticks qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s hgr_page_flip qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s gr_offsets qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s inc_base5 qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s draw_full_dni_number qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s gr_flip_page qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s do_wipe_fizzle qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s do_wipe_lr qload.lst >> qload.inc
# $(GENERATE_COMMON) -a 0x1200 -s do_wipe_center qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s hgr_clear_screen qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s hgr_page1_clearscreen qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s hgr_page2_clearscreen qload.lst >> qload.inc
$(GENERATE_COMMON) -a 0x1200 -s check_timeout qload.lst >> qload.inc
####
music.inc: $(GENERATE_COMMON) MUSIC
$(GENERATE_COMMON) -a 0xd000 -s pt3_init_song music.lst > music.inc
$(GENERATE_COMMON) -a 0xd000 -s mockingboard_init music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s reset_ay_both music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s clear_ay_both music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s mockingboard_setup_interrupt music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s mockingboard_disable_interrupt music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s mockingboard_patch music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s done_pt3_irq_handler music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s PT3_LOC music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s current_pattern_smc music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s pt3_set_pattern music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s mute_ay_both music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s unmute_ay_both music.lst >> music.inc
$(GENERATE_COMMON) -a 0xd000 -s interrupt_handler music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s copy_to_400 music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s copy_to_400_main music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s copy_to_400_aux music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s zx02_full_decomp music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s zx02_full_decomp_aux music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s zx02_full_decomp_main music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s zx_src_h music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s zx_src_l music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s hgr_vertical_scroll_down_main music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s hgr_vertical_scroll_down_aux music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s hgr_vertical_scroll_up_main music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s hgr_vertical_scroll_up_aux music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s slow_copy_main music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s slow_copy_aux music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s slow_copy_A0_main music.lst >> music.inc
# $(GENERATE_COMMON) -a 0xd000 -s slow_copy_A0_aux music.lst >> music.inc
####
MUSIC: music.o
ld65 -o MUSIC music.o -C $(LINKER_SCRIPTS)/apple2_d000.inc
music.o: music.s zp.inc \
music/alex_rostov_intro_theme.pt3 \
../pt3lib/pt3_lib_core.s \
../pt3lib/pt3_lib_mockingboard_detect.s \
../pt3lib/pt3_lib_mockingboard.inc \
../pt3lib/pt3_lib_init.s \
../pt3lib/pt3_lib_mockingboard_setup.s \
../pt3lib/pt3_lib_irq_handler.s
ca65 -o music.o music.s -l music.lst
###
../generate_common:
cd .. && make
###
clean:
rm -f *~ *.o *.lst HELLO ANIMATION QBOOT QLOAD MUSIC generate_common
rm -f qload.inc qload2.inc music.inc music2.inc
+312
View File
@@ -0,0 +1,312 @@
.include "zp.inc"
.include "../hardware.inc"
.include "qload.inc"
.include "music.inc"
.include "common_defines.inc"
;=======================================
; draw TMBG animation
;=======================================
tmbg:
bit KEYRESET ; just to be safe
;=================================
; init vars
;=================================
lda #3
sta FRAME_RATE
;=================================
; init double-lores graphics
;=================================
bit SET_GR
bit LORES
sta EIGHTYCOLON ; 80 column mode
bit FULLGR
sta CLRAN3 ; set double lores
sta EIGHTYSTOREOFF ; normal PAGE1/PAGE2 behavior
bit PAGE2 ; display page2
;========================================
; decompress frame1 to PAGE1
lda #$0
sta DRAW_PAGE
lda #<graphics_frame1_aux
sta zx_src_l+1
lda #>graphics_frame1_aux
sta zx_src_h+1
lda #$20
jsr zx02_full_decomp
; Copy $2000 to AUX $400, skipping holes
ldx #$20
jsr copy_to_400_aux
lda #<graphics_frame1_main
sta zx_src_l+1
lda #>graphics_frame1_main
sta zx_src_h+1
lda #$20
jsr zx02_full_decomp
ldx #$20
jsr copy_to_400_main
;========================================
; decompress frame2 to PAGE2
lda #$4
sta DRAW_PAGE
lda #<graphics_frame2_aux
sta zx_src_l+1
lda #>graphics_frame2_aux
sta zx_src_h+1
lda #$20
jsr zx02_full_decomp
;
ldx #$20
jsr copy_to_400_aux
;
lda #<graphics_frame2_main
sta zx_src_l+1
lda #>graphics_frame2_main
sta zx_src_h+1
lda #$20
jsr zx02_full_decomp
ldx #$20
jsr copy_to_400_main
oop:
jsr wait_until_keypress
bit PAGE1
jsr wait_until_keypress
bit PAGE2
jmp oop
;=======================
; start music
lda SOUND_STATUS
and #SOUND_MOCKINGBOARD
beq no_music
yes_music:
cli
no_music:
; so frame1 is on page1
; frame2 is on page2
; show page2 (frame2) FRAME2
; page1 1->3, fiip to page1 FRAME3
; page2 2->4, flip to page2 FRAME4
; page1 3->5, flip to page1 FRAME5
lda #0
sta DRAW_PAGE
sta WHICH
animation_loop:
; draw page1, view page2
.if 0
ldx WHICH
ldy patches_page1_h,X
lda patches_page1_l,X
tax
.endif
jsr patch_graphics
jsr draw_sound_bars
jsr wait_some
; jsr wait_until_keypress
jsr hgr_page_flip
; draw page2, view page1
.if 0
jsr wait_some
; jsr wait_until_keypress
ldx WHICH
ldy patches_page2_h,X
lda patches_page2_l,X
tax
.endif
jsr patch_graphics
jsr draw_sound_bars
jsr hgr_page_flip
inc WHICH
lda WHICH
and #$3 ; wrap at 4
sta WHICH
;=====================
; handle keyboard
lda KEYPRESS
bpl keep_going
bit KEYRESET
check_g:
cmp #'G'+$80
bne check_o
jsr make_green
jmp keep_going
check_o:
cmp #'O'+$80
bne check_plus
jsr make_orange
jmp keep_going
check_plus:
cmp #'+'+$80
bne check_minus
inc FRAME_RATE
jmp keep_going
check_minus:
cmp #'-'+$80
bne keep_going
dec FRAME_RATE ; minimum 0
bpl keep_going
lda #0
sta FRAME_RATE
beq keep_going ; bra
keep_going:
jmp animation_loop
;===================================
; wait some frames
wait_some:
lda SOUND_STATUS
and #SOUND_MOCKINGBOARD
bne wait_mockingboard
wait_nomock:
lda FRAME_RATE
jmp wait_50ms
wait_mockingboard:
lda FRAME_RATE
jmp wait_ticks
.include "../patch_graphics.s"
.include "../sound_bars.s"
graphics_frame1_aux:
.incbin "graphics/tmbg01.aux.zx02"
graphics_frame2_aux:
.incbin "graphics/tmbg02.aux.zx02"
graphics_frame1_main:
.incbin "graphics/tmbg01.main.zx02"
graphics_frame2_main:
.incbin "graphics/tmbg02.main.zx02"
.if 0
frame1_frame3_diff:
.include "graphics/frame1_frame3_diff.inc"
frame3_frame5_diff:
.include "graphics/frame3_frame5_diff.inc"
frame5_frame7_diff:
.include "graphics/frame5_frame7_diff.inc"
frame7_frame1_diff:
.include "graphics/frame7_frame1_diff.inc"
frame2_frame4_diff:
.include "graphics/frame2_frame4_diff.inc"
frame4_frame6_diff:
.include "graphics/frame4_frame6_diff.inc"
frame6_frame8_diff:
.include "graphics/frame6_frame8_diff.inc"
frame8_frame2_diff:
.include "graphics/frame8_frame2_diff.inc"
patches_page1_l:
.byte <frame1_frame3_diff
.byte <frame3_frame5_diff
.byte <frame5_frame7_diff
.byte <frame7_frame1_diff
patches_page1_h:
.byte >frame1_frame3_diff
.byte >frame3_frame5_diff
.byte >frame5_frame7_diff
.byte >frame7_frame1_diff
patches_page2_l:
.byte <frame2_frame4_diff
.byte <frame4_frame6_diff
.byte <frame6_frame8_diff
.byte <frame8_frame2_diff
patches_page2_h:
.byte >frame2_frame4_diff
.byte >frame4_frame6_diff
.byte >frame6_frame8_diff
.byte >frame8_frame2_diff
.endif
.include "../copy_400.s"
@@ -0,0 +1,79 @@
include ../../../../../Makefile.inc
ZX02 = ~/research/6502_compression/zx02.git/build/zx02 -f
PNG_TO_HGR = ../../../../../utils/hgr-utils/png2hgr
PNG_TO_DGR = ../../../../../utils/gr-utils/png2dgr
PNG_TO_DHGR_RAW = ../../../../../utils/hgr-utils/png2dhgr_raw
PNG_TO_DHGR4 = ../../../../../utils/hgr-utils/png2dhgr4
PNG2GR = ../../../../../utils/gr-utils/png2gr
HGR_SPRITE = ../../../../../utils/hgr-utils/hgr_make_sprite
LINKER_SCRIPTS = ../../../../../linker_scripts/
PNG_TO_HGR_DIFF = ../../../../../utils/hgr-utils/png2hgr_diff
all: \
tmbg01.aux.zx02 tmbg01.main.zx02 \
tmbg02.aux.zx02 tmbg02.main.zx02
# frame1_frame3_diff.inc frame3_frame5_diff.inc \
# frame5_frame7_diff.inc frame7_frame1_diff.inc \
# frame2_frame4_diff.inc frame4_frame6_diff.inc \
# frame6_frame8_diff.inc frame8_frame2_diff.inc
####
frame1_frame3_diff.inc: a2_frame0001.png a2_frame0003.png
$(PNG_TO_HGR_DIFF) a2_frame0001.png a2_frame0003.png > frame1_frame3_diff.inc
frame3_frame5_diff.inc: a2_frame0003.png a2_frame0005.png
$(PNG_TO_HGR_DIFF) a2_frame0003.png a2_frame0005.png > frame3_frame5_diff.inc
frame5_frame7_diff.inc: a2_frame0005.png a2_frame0007.png
$(PNG_TO_HGR_DIFF) a2_frame0005.png a2_frame0007.png > frame5_frame7_diff.inc
frame7_frame1_diff.inc: a2_frame0007.png a2_frame0001.png
$(PNG_TO_HGR_DIFF) a2_frame0007.png a2_frame0001.png > frame7_frame1_diff.inc
frame2_frame4_diff.inc: a2_frame0002.png a2_frame0004.png
$(PNG_TO_HGR_DIFF) a2_frame0002.png a2_frame0004.png > frame2_frame4_diff.inc
frame4_frame6_diff.inc: a2_frame0004.png a2_frame0006.png
$(PNG_TO_HGR_DIFF) a2_frame0004.png a2_frame0006.png > frame4_frame6_diff.inc
frame6_frame8_diff.inc: a2_frame0006.png a2_frame0008.png
$(PNG_TO_HGR_DIFF) a2_frame0006.png a2_frame0008.png > frame6_frame8_diff.inc
frame8_frame2_diff.inc: a2_frame0008.png a2_frame0002.png
$(PNG_TO_HGR_DIFF) a2_frame0008.png a2_frame0002.png > frame8_frame2_diff.inc
####
tmbg01.aux.zx02: tmbg01.aux
$(ZX02) tmbg01.aux tmbg01.aux.zx02
tmbg01.main.zx02: tmbg01.main
$(ZX02) tmbg01.main tmbg01.main.zx02
tmbg01.aux: tmbg01.png
$(PNG_TO_DGR) tmbg01.png tmbg01
####
tmbg02.aux.zx02: tmbg02.aux
$(ZX02) tmbg02.aux tmbg02.aux.zx02
tmbg02.main.zx02: tmbg02.main
$(ZX02) tmbg02.main tmbg02.main.zx02
tmbg02.aux: tmbg02.png
$(PNG_TO_DGR) tmbg02.png tmbg02
####
clean:
rm -f *~ *.zx02 *.lst *.o *.hgr *_diff.inc
Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B

+32
View File
@@ -0,0 +1,32 @@
; Music player for animations
; by Vince `deater` Weaver vince@deater.net
.include "../hardware.inc"
.include "zp.inc"
;.include "qload.inc"
.include "common_defines.inc"
music_lib:
PT3_ENABLE_APPLE_IIC = 1
; urgh to keep interrupt_handler from starting at $C4
; which broke auto-patcher
; pt3 player
; .include "../pt3lib/pt3_lib_detect_model.s"
.include "../pt3lib/pt3_lib_mockingboard_patch.s"
.include "../pt3lib/pt3_lib_core.s"
.include "../pt3lib/pt3_lib_init.s"
.include "../pt3lib/pt3_lib_mockingboard_setup.s"
.include "../pt3lib/interrupt_handler.s"
.include "../pt3lib/pt3_lib_mockingboard_detect.s"
; only load one music track, self modify to make other
.align $100
PT3_LOC:
.incbin "music/alex_rostov_intro_theme.pt3"
+244
View File
@@ -0,0 +1,244 @@
; fast seek/multi-read
; copyright (c) Peter Ferrie 2015-16
; Paramaters for loading QLOAD
sectors = 14 ; user-defined
firsttrk = 1 ; user-defined, first track to read
firstsec = 0 ; user-defined, first sector to read
address = $12 ; user-defined
entry = $1200 ; user-defined
version = 1
;memory usage:
;256 bytes ($200-2ff) static table
grouped = $200
; stay away from interrupt vectors at $3fe !!!
;106 bytes ($300-369) static table
preshift = $300
zvalue = $fd ; only during init
znibble = $fe ; only during init
zmask = $ff ; only during init
WHICH_SLOT = $DA
; $26/$27 sector read location (ROM)
; $3D sector number (ROM)
; at entry (at least on AppleWin) A=1, X=60 (slot<<4), Y=0
; qkumba says cffa cards leave Y at $10
; 26/27 = 00/09
; 3D = 1
; For Disk II booting, the firmware loads track0/sector0
; to $800 and then jumps to $801
.org $800
.byte 1 ; number of sectors for ROM to load
boot_entry:
; this code loads two sectors up to $10/$11
; assume A=1 coming in here
lsr ; check sector number
; A=0, carry=1
tay ; Y=0
adc #$0f ; A=$10 (destintation)
sta $27 ; set or update address as needed
cmp #$12
; 10 11 12 (1 1 1)
; be, bf, c0 (1011 1011 1100)
; so if hit $c000 we are done
beq done_load_2 ; branch if loaded 2
inc $3d ; increment sector (faster to find)
; call to the read routine in proper slot
; using rts to jump indirect to
; $CX5C
; this routine reads sector in $3D on track in $41
; to address in $26/$27
; when it's done it jumps back to $801
stx WHICH_SLOT ; save for later
txa ; x is slot# << 4
lsr
lsr
lsr
lsr
ora #$c0 ; slot to PROM base
pha
lda #$5b ;read-1
pha
rts ; return used to call $CX5C in DISK II ROM
done_load_2:
; patch self modifying code for Q6L read
txa
ora #$8c ; slot to Q6L
; Q6L?
; if slot 6, after this A is $EC
; Y should be 2 here
patch_loop:
iny
ldx patchtbl-3, Y
sta code_begin, X ; replace placeholders with Q6L
; BE02 = EC? lda c0ec
; so sets to c08c (Q6L)
bne patch_loop
; patch self-modifying code for turning motor off
and #$f8 ; MOTOROFF (c088) -> c0e8
sta slotpatch7+1
; patch self-modifying code for turning motor on
clc
adc #1 ; MOTORON (c089) -> c0e9
sta slotpatch9+1
; patch self-modifying code for phase off
eor #9 ; PHASEOFF (c080)
sta slotpatch8+1
ldx #$3f
stx zmask
inx
ldy #$7f
bne skip_ahead ; branch always
; pad with zeros until $839
; $839 is the entry point
; adjusts address at $8FE to be entry point
; jumps to boot 2
;.res $839-*
; lda #>(entry-1)
; pha
; lda #<(entry-1)
; pha
; jsr preread
; jmp $1000 ; stage2 entry point
patchtbl:
.byte <(slotpatch1+1), <(slotpatch2+1), <(slotpatch3+1)
.byte <(slotpatch4+1), <(slotpatch5+1), <(slotpatch6+1)
indextbl: ;the 0 also terminates the patchtbl list!
.byte 0, 2, 1, 3
;construct denibbilisation table
;pre-shifted for interleave read
skip_ahead:
loopaa:
sty znibble
tya
asl
bit znibble
beq loopz
ora znibble
eor #$ff
and #$7e
loopa:
bcs loopz
lsr
bne loopa
dex
txa
asl
asl
sta preshift-$16, Y
loopz:
dey
bne loopaa
;construct 2-bit group table
sty zvalue
loopbb:
lsr zmask
lsr zmask
loopb:
lda indextbl, X
sta grouped, Y
inc zvalue
lda zvalue
and zmask
bne loopy
inx
txa
and #3
tax
loopy:
iny
iny
iny
iny
cpy #3
bcs loopb
iny
cpy #3
bcc loopbb
lda #>(entry-1)
pha
lda #<(entry-1)
pha
jsr preread
; seek backward support
; sty startsec+1
; sta tmpadr+1
; stx total+1
jmp seekread
preread:
;copy post-read if necessary
;push post-read address here
; pla
; tax
; pla
; tay
; lda #>(postread-1)
; pha
; lda #<(postread-1)
; pha
; tya
; pha
; txa
; pha
lda #<(firsttrk*2)
sta phase+1
ldx #sectors
lda #address
ldy #firstsec
rts
end_code:
.res $8fe-*
; traditionally, entry point to jump to at end of loading
; $1000 in this case
;*=$8fe
.byte $10, $00
.include "qboot_stage2.s"
+382
View File
@@ -0,0 +1,382 @@
; the following lives on sectors $0E and $0D
; why?
; request sector 2 and 4, and the interleave is
; beneath apple dos (3-23)
; Physical (firmware) : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
; DOS33 mapping : 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15
; Beneath Apple DOS
; p86 (dos reference)
;
;WAIT = $FCA8 ;; delay 1/2(26+27A+5A^2) us
WAIT = norom_wait
.org $1000
code_begin:
.byte version
readnib:
slotpatch1: ; smc
lda $c0d1 ; gets set to C08C (Q6L) read
bpl readnib
rts
;fill address array for one track
seekread:
sty startsec+1
sta tmpadr+1
stx total+1
inittrk:
sec
lda #$10
sbc startsec+1
cmp total+1
bcs it_skip
tax
it_skip:
stx partial1
stx partial2
jsr seek
startsec:
ldy #$d1
tmpadr:
tmpadr_loop:
lda #$d1
sta addrtbl, y
inc tmpadr+1
iny
dec partial1
bne tmpadr_loop
;====================================
; read a sector
;====================================
; first address field
;====================================
; starts with $D5 $AA $96
; then XX YY volume
; then XX YY track
; then XX YY sector
; then XX YY checksum
; then ends with $DE $AA $EB
;====================================
; data field
;====================================
; starts with $D5 $AA $AD
; 342 bytes of data
; XX checksum
; ends with $DE $AA $EB
read:
outer_read:
jsr readnib
inner_read:
cmp #$d5 ; look for $D5 part of addr field
bne outer_read
jsr readnib ; look for $D5 $AA
cmp #$aa
bne inner_read
; look for $D5 $AA $AD
tay ; we need Y=#$AA later
jsr readnib
eor #$ad ; zero A if match
beq check_mode
; if not #$AD, then #$96 is assumed
; so in address field
ldy #2 ; volume, track, sector
another:
jsr readnib
rol ; set carry
sta sector+1
jsr readnib
and sector+1
dey
bpl another
tay
ldx addrtbl, Y ; fetch corresponding address
beq read ; done?
sta sector+1 ; store index for later
stx adrpatch1+2
stx adrpatch8+2
stx adrpatch2+2
stx adrpatch3+2
stx adrpatch5+2
stx adrpatch7+2
inx
stx adrpatch9+2
dex
dex
stx adrpatch4+2
stx adrpatch6+2
ldy #$fe
loop2:
adrpatch1:
lda $d102, Y
pha
iny
bne loop2
branch_read:
bcs read ; branch always
check_mode:
cpx #0
beq read ; loop if not expecting #$AD
loop33:
sta tmpval+1 ; zero rolling checksum
slotpatch2:
loop4:
ldx $c0d1
bpl loop4
lda preshift-$96, X
adrpatch2:
sta $d102, Y ; store 2-bit array
tmpval:
eor #$d1
iny
bne loop33
ldy #$aa
slotpatch3:
loop5:
ldx $c0d1
bpl loop5
eor preshift-$96, X
adrpatch3:
ldx $d102, Y ; bit2tbl
eor grouped+2, X ; first 86 nibbles use group bits 0-1
adrpatch4:
sta $d156, y
iny
bne loop5
and #$fc
ldy #$aa
slotpatch4:
loop6:
ldx $c0d1
bpl loop6
eor preshift-$96, X
adrpatch5:
ldx $d102, Y ; bit2tbl
eor grouped+1, X ; second 86 nibbles use group bits 2-3
adrpatch6:
sta $d1ac, Y
iny
bne loop6
and #$fc
ldx #$ac
slotpatch5:
loop7:
ldy $c0d1
bpl loop7
eor preshift-$96, Y
adrpatch7:
ldy $d100, X ; bit2tbl
eor grouped, Y ; last 84 nibbles use group bits 4-5
adrpatch8:
sta $d100, x
inx
bne loop7
and #$fc
slotpatch6:
loop8:
ldy $c0d1
bpl loop8
eor preshift-$96, Y
cmp #1 ; carry = !zero
ldy #1
loop9:
pla
adrpatch9:
sta $d100, Y
dey
bpl loop9
branch_read2:
bcs branch_read ; branch if checksum failure
sector:
ldy #$d1
txa
sta addrtbl, Y ; zero corresponding address
dec total+1
dec partial2 ; adjust remaining count
; (faster than looping over array)
sec
bne branch_read2 ; read all requested sectors in one track
sta startsec+1 ; this was missing from original code
; leading to trouble on wrap around
; it not starting at sector0
total:
ldx #$d1
beq driveoff
inc phase+1
inc phase+1 ; update current track
jmp inittrk
driveoff:
slotpatch7:
lda $c0d1
seekret:
rts
seek:
ldx #0
stx step+1
copy_cur:
curtrk:
lda #0
sta tmpval+1
sec
phase:
sbc #$d1
beq seekret
; if seek backwards
bcs sback
eor #$ff
inc curtrk+1
bcc ssback
sback:
adc #$fe
dec curtrk+1
ssback:
cmp step+1
bcc loop10
step:
lda #$d1
loop10:
cmp #8
bcs loop11
tay
sec
loop11:
lda curtrk+1
ldx step1, Y
bne loop12
loopmmm:
clc
lda tmpval+1
ldx step2, Y
loop12:
stx sector+1
and #3
rol
tax
slotpatch8:
sta $c0d1, X
loopmm:
ldx #$13
loopm:
dex
bne loopm
dec sector+1
bne loopmm
lsr
bcs loopmmm
inc step+1
bne copy_cur
step1: .byte 1, $30, $28, $24, $20, $1e, $1d, $1c
step2: .byte $70, $2c, $26, $22, $1f, $1e, $1d, $1c
addrtbl: .res 16
partial1: .byte $00
partial2: .byte $00
code_end:
;==========================
; enable drive motor
;==========================
driveon:
slotpatch9:
lda $c0d1
; wait 1s
ldx #6
wait_1s:
lda #255
jsr WAIT
dex
bne wait_1s
rts
load_new:
jsr driveon
lda load_track
asl ; track to start*2
sta phase+1
lda load_sector
tay ; sector to start
lda load_length ; length
tax
lda load_address ; address to load
jsr seekread
rts
load_address:
.byte $00
load_track:
.byte $00
load_sector:
.byte $00
load_length:
.byte $00
; copy of ROM wait
; because we might disable ROM
norom_wait:
sec
wait2:
pha
wait3:
sbc #$01
bne wait3
pla
sbc #$01
bne wait2
rts
wait_end:
+110
View File
@@ -0,0 +1,110 @@
; Loader
.include "zp.inc"
.include "../hardware.inc"
.include "music.inc"
.include "common_defines.inc"
.include "qboot.inc"
qload_start:
; init the write code
; lda WHICH_SLOT
; jsr popwr_init
; first time entry
; start by loading text title
; lda #0 ; load ZW engine
; sta WHICH_LOAD
lda #1
sta CURRENT_DISK ; current disk number
; jsr load_file
jmp star_lady_start
; jmp $2000 ; jump to ZW
;====================================
; loads file specified by WHICH_LOAD
;====================================
load_file:
ldx WHICH_LOAD
; lda which_disk_array,X
; cmp CURRENT_DISK
; bne change_disk
load_file_no_diskcheck:
lda load_address_array,X
sta load_address
lda track_array,X
sta load_track
lda sector_array,X
sta load_sector
lda length_array,X
sta load_length
jsr load_new
rts
which_disk_array:
.byte 1,1,1 ; ???, MUSIC, ANIMATION
load_address_array:
.byte $D0,$D0,$60 ; ???, MUSIC, ANIMATION
start_address:
.byte $D0,$D0,$60 ; ???, MUSIC, ANIMATION
;aux_dest:
; .byte $D0,$D0,$40 ; ???, MUSIC, ANIMATION
track_array:
.byte 2,2,5 ; ???, MUSIC, ANIMATION
sector_array:
.byte 0,0,0 ; ???, MUSIC, ANIMATION
length_array:
.byte 48,40,48 ; ???, MUSIC, ANIMATION
PT3_ENABLE_APPLE_IIC = 1
.include "../wait.s"
.include "../pt3lib/lc_detect.s"
.include "../wait_a_bit.s"
.include "../gr_fast_clear.s"
.include "../text_print.s"
.include "../gr_offsets.s"
.include "../pt3lib/pt3_lib_detect_model.s"
.include "../pt3lib/pt3_lib_mockingboard_detect.s"
.include "../hgr_table.s"
; .include "random8.s"
; .include "vblank.s"
.include "../irq_wait.s"
.include "../hgr_page_flip.s"
.include "../wait_keypress.s"
.include "../zx02_optim.s"
.include "../pt3lib/gs_interrupt.s"
.include "../pt3lib/hardware_detect.s"
.include "../hgr_clear_screen.s"
.include "start.s"
qload_end:
.assert (>qload_end - >qload_start) < $e , error, "loader too big"
+166
View File
@@ -0,0 +1,166 @@
; star_lady startup
;
; by deater (Vince Weaver) <vince@deater.net>
;.include "zp.inc"
;.include "hardware.inc"
;.include "qload.inc"
;.include "music.inc"
DEBUG=0
star_lady_start:
;=====================
; initializations
;=====================
bit PAGE1
bit KEYRESET
jsr hardware_detect
lda APPLEII_MODEL
sta message_type_offset
; init vars
lda #0
sta DRAW_PAGE
;=====================
; clear text screen
lda #$A0
jsr clear_top_a
jsr clear_bottom
; print start message
jsr set_normal
lda #<start_message
sta OUTL
lda #>start_message
sta OUTH
jsr move_and_print_list
;===============================
; pause at warning if not e/c/gs
lda APPLEII_MODEL
cmp #'e'
beq good_to_go
cmp #'g'
beq good_to_go
cmp #'c'
beq good_to_go
jsr wait_until_keypress
good_to_go:
;=========================================
;=========================================
; start loading the demo
;=========================================
;=========================================
;==================================
; load music into the language card
; into $D000 set 1
;==================================
; read/write RAM, use $d000 bank1
bit $C083
bit $C083
lda #PART_MUSIC ; load MUSIC from disk
sta WHICH_LOAD
jsr load_file
lda #0
sta DONE_PLAYING
lda #1
sta LOOP
; patch mockingboard
lda SOUND_STATUS
beq skip_mbp1
jsr mockingboard_patch ; patch to work in slots other than 4?
skip_mbp1:
;=======================
; Set up 50Hz interrupt
;========================
jsr mockingboard_init
jsr mockingboard_setup_interrupt
;============================
; Init the Mockingboard
;============================
jsr reset_ay_both
jsr clear_ay_both
;==================
; init song
;==================
jsr pt3_init_song
dont_enable_mc:
skip_all_checks:
jsr hgr_make_tables
;=======================
;=======================
; Run ANIMATION
;=======================
;=======================
; load from disk
sei
lda #PART_ANIMATION ; Load bucket
sta WHICH_LOAD
jsr load_file
; Run Animation
; cli ; start music
jsr $6000
blah:
jmp blah
start_message: ;01234567890123456789012345678901234567890
.byte 0,0,"LOADING STAR_LADY 2025 V1.0",0
.byte 0,1,"REQUIRES APPLE II, MOCKINGBOARD",0
.byte 0,3,"SYSTEM DETECTED: APPLE II"
message_type_offset:
.byte " ",0
.byte 0,10,"MUSIC: INTRO THEME BY ALEX ROSTOV",0
.byte 0,12,"GRAPHICS BY @REDLOT_TO",0
.byte 0,16,"FAST DISK LOAD BY QKUMBA",0
.byte 0,17,"ZX02 DECOMPRESSION BY DMSC",0
.byte 0,18,"EVERYTHING ELSE BY DEATER",0
.byte 10,20," ______",0
.byte 10,21,"A \/\/\/ PRODUCTION",0
.byte $FF
;load_message:
; .byte 16,22, "LOADING",0
+167
View File
@@ -0,0 +1,167 @@
;==================
;==================
; Zero Page Usage
;==================
;==================
; ZX0 decompression addresses
ZX0_src = $00
ZX0_dst = $02
offset = $04
bitr = $06
pntr = $07
WHICH_LOAD = $09
CURRENT_DISK = $0A
; Zero page monitor routines addresses
; We don't use the monitor but we use some of these anyway
WNDLFT = $20
WNDWDTH = $21
WNDTOP = $22
WNDBTM = $23
CH = $24
CV = $25
GBASL = $26
GBASH = $27
BASL = $28
BASH = $29
H2 = $2C
V2 = $2D
MASK = $2E
COLOR = $30
;INVFLG = $32
WIPEL = $3C ; used by input for wipes?
WIPEH = $3D
WHICH_TRACK = $54
;==========================
; $60-$6F
;==========================
DISP_PAGE = $6E
DRAW_PAGE = $6F
;================================================
; $B0 ... $BF for common things, don't mess with
;================================================
FRAME = $B8
FRAMEL = $B8
FRAMEH = $B9
WHICH_SLOT = $BA ; from boot sector
SECOND_COUNTDOWN= $BB
BTC_L = $BC
BTC_H = $BD ; audio
; Used when sprite drawing
CURSOR_X = $BE
CURSOR_Y = $BF
;==============================================
; $C0-$CF available
;==============================================
; woz
BALL_STATE = $C0 ; C0..C7
BALL_OFFSET = $C8 ; C8..CF
; four-color/plasma
XPOS = $C8
YPOS = $C9
AUXOUTL = $CA
AUXOUTH = $CB
MAIN1 = $CC
AUX1 = $CD
MAIN0 = $CE
AUX0 = $CF
; repack
CURRENT_COL = $CC ; dhgr_repack
CURRENT_ROW = $CD ; dhgr_repack
;==============================================
; $D0-$DB can re-use in each file
;==============================================
; repack
REPACK_TMP = $D0 ; $D0...$D7
; start/font fall
TEXT_Y = $D2
; intro: scrolling
SCROLL_COUNT = $D0
INDEX = $D1
DEST_OFFSET = $D2
SRC_OFFSET = $D3
LENGTH = $D4
; woz
ROW = $D0 ; martymation
FAKE_HGR_PAGE = $D1
FAKE_HGR_BITS = $D2
FAKE_HGR_SHAPE = $D3
FAKE_HGR_SHAPE2 = $D4
WHICH_BALL = $D5
ORBITS = $D6
NEXT_BALL = $D7
ERASE_COUNT = $D8
BALL_X = $D9
; four color
CURRENT = $D0
LEFT = $D1
XSTART = $D2
XEND = $D3
COLORSG = $D4
COLORSF = $D5
COLORSE = $D6
COLORSD = $D7
COLORSC = $D8
COLORSB = $D9
COLORSA = $DA
ODD = $DB
; Plasma
COMPT1 = $D0
COMPT2 = $D1
PARAM1 = $D2
PARAM2 = $D3
PARAM3 = $D4
PARAM4 = $D5
COUNT = $D6
;
TEMP_VOL = $D9
WHICH = $DA
FRAME_RATE = $DB
;==============================================
; $DC-$DF we use for in/out pointers
;==============================================
INL = $DC
INH = $DD
OUTL = $DE
OUTH = $DF
;==========================
; $E0-$FD for PT3 Player
;==========================
.include "../pt3lib/pt3_lib_zp.inc"
+154
View File
@@ -0,0 +1,154 @@
Maximing Compression of Apple II Hi-res Images
I have the somewhat niche probem of trying to fit as many Apple II
hi-res images into RAM (and disk) at a time. Uncompressed these images
are 8k (well, you can get away with 8184 bytes without any trouble
for reasons we'll discuss later).
Background
~~~~~~~~~~
I won't go too much into the wacky world of Apple II graphics,
you can read more on that here. For our purposes the important part
is that you can think of it as a 280x192 monochrome image with 7-bits
per byte that typically is used to generate NTSC artifact color
(the top bit shifts the pixel slightly to essentially choose another
palette, blue/orange vs purple/green).
You might think 280x192, at 7bpp, it should be 40 byte by 192 image fitting
nicely in a linear 7.5k. Alas, no, and you can probably blame Woz for it.
The first part is to avoid crossing page boundaries there are "holes"
in the memory map. After each three rows (120 bytes) 8 bytes are left
unused to pad things out to a nice power of 2.
The final issue is that complex interleaving goes on so rows are not
contiguous in memory. This is for various reasons, possibly to save
a few chips on the motherboard. (In addition the addresses are all over
the place on the actual RAM chips to make the "free" DRAM refresh but
that's hard to notice unless you're logic-probing the address lines).
For example, in PAGE1 of hi-res memory starting at $2000 (on 6502 processors
you use $ to indicate hexadecimal) you get something like this:
$2000: Row0 Row64 Row 128, 8-bytes padding
$2080: Row8 Row72 Row 136, 8 bytes padding
...
and after 1k of this, you then start over with
$2400: Row1 Row65 Row129, 8 bytes padding
This leads to the "venetian blind" effect often seen when loading HGR
graphics linearly.
Compression
~~~~~~~~~~~
I won't go into too many details here, there are a lot of 6502 compression
algorithms that have various tradeoffs between code size, compression
ratio, and speed. I've settled on ZX02 for now which is a nice compromise
and has low code size which I like because often I am doing size coding.
Extra-Compression
~~~~~~~~~~~~~~~~~
It turns out though that while compressing the interleaved graphics works
pretty well, you can get a bit more compression if you de-interlace first.
With some examples (you can see a video here):
zx02 de-interlace+zx02
Kerrek 1 951 808 (-143)
(video game) 12% 10%
Christmas 2572 2402 (-170)
(fancy writing) 31% 29%
riven maglev 3423 3263 (-160)
(hand converted bitmap) 42% 40%
Ice3 5176 5094 (-82)
(iipix converted bitmap) 63% 62%
So you can save rouchly 100 or so bytes per image, depending on the entropy
in the original image. Does this matter? I definitely have had projects
where every byte counts and if you have more than 10 or so images it can
add up.
The Algorithm
~~~~~~~~~~~~~
The nice thing about this algorithm is you can do it in-place so you don't
have to have 8k free to do this.
It's two steps
1. Add in the 8-byte memory holes every 128 bytes
2. Sort the lines to the proper location (via what is essentially
a selection sort)
The Cost
~~~~~~~~
Code Size
=========
So this isn't free. How expensive is it to do this?
The current code I have, the zx02 compression is
2a5-217=142 bytes
On top of this, the de-interlace code (which I have not optimized at all)
uses an 188 byte lookup table, the total space is
19f-3c = 355 bytes. So currently you'd need to have 4 images before it
is a net win.
This assumes that we already have 384 bytes of hi/lo hires lookup tables
already in memory for other reasons. Usually you do if you're doing hires
work with any sort of speed.
Time Overhead
=============
For the ice3 case which is a bit of a worst case for zx02
zx02 decompression time: $1417 - $6028 (the rts in zx02 used multiple)
0x68176 cycles = 426538 = ~417ms = ~ 25 frames
add-back-holes: $60A2
0x1d8c7 = 121031 = ~118ms = ~ 7 frames
de-interlace: $60E2 = 39a78+4EE= $39f66 = 237414 = 232ms = ~14 frames
As a reminder, an NTSC Apple II updates the screen at 60Hz which is
approximately 16.7ms.
Note the Apple II runs the 6502 at approximately 1.023 MHz (it's complicated).
The zx02 compression routine is the one optimized by qkumba.
Other Uses
~~~~~~~~~~
I originally thought of doing this when doing my double-hires
Monstersplash demo for Demosplash 2025. Double-hires has its own issues
that make compression harder (the graphics are spread across two memory banks
and the pixels alternate between them in complex ways) so the deinterlace
is more of a win.
I would like to see if this would help much on lo-res or double-lores.
There are some scenes from the Rewind2 and Second Reality that are space
constained.
I also think it might be of use in various of my games like Myst demake
or Peasant's Quest demake.
Questions
~~~~~~~~~~
Q. Could you just modify ZX02 to be apple-ii hires aware?
A. Maybe? The problem is compression algorithms like this will grab
into the already-decompressed output data for patterns and so if you
are scattering it around it makes life more difficult.