Tridora-CPU/examples/sprites.s

287 lines
5.4 KiB
ArmAsm

.EQU SPRITE_HEIGHT 32 ; height in lines
.EQU SPRITE_STRIPES 4 ; width in words i.e. 8-pixel stripes
.EQU WORDS_PER_LINE 80
.EQU FB_RA $900
.EQU FB_WA $904
.EQU FB_IO $908
.EQU FB_PS $90C
.EQU FB_PD $910
.EQU FB_CTL $914
.EQU FB_SHIFTER $918
.EQU FB_SHIFTCOUNT $91C
.EQU FB_SHIFTERM $920
.EQU FB_SHIFTERSP $924
.EQU FB_MASKGEN $928
; calculate vmem address from coordinates
; args: x,y
; returns: vmem word number
CALC_VMEM_ADDR:
; only works if WORDS_PER_LINE is 80
; and pixels per word is 8
DUP
; y
SHL 2
SHL 2
SHL 2 ; * 64
SWAP
; + y
SHL 2
SHL 2 ; * 16
ADD
SWAP
; word offset = X/8
SHR
SHR
SHR
ADD
RET
; put a sprite on screen
; arg: x,y pointer to sprite data
.EQU PS_VMEM_ADDR 0
.EQU PS_SPRITE_DATA 4
.EQU PS_SPRITE_LINES 8
.EQU PS_X 12
.EQU PS_Y 16
.EQU PS_SHIFT_C 20
.EQU PS_SPILL 24
.EQU PS_STRIPE_C 28
.EQU PS_BPSAVE 32
.EQU PS_FS 36
PUTSPRITE:
FPADJ -PS_FS
STORE PS_SPRITE_DATA
STORE PS_Y
STORE PS_X
LOADREG BP
STORE PS_BPSAVE
LOADC 0
STOREREG BP
; calculate vmem address
LOAD PS_X
LOAD PS_Y
LOADCP CALC_VMEM_ADDR
CALL
STORE PS_VMEM_ADDR
LOADC SPRITE_HEIGHT
STORE PS_SPRITE_LINES
; loop over each line of the sprite
PS_LOOP1:
; set read and write address
; in the vga controller
LOAD PS_VMEM_ADDR
DUP
STORE.B FB_RA
STORE.B FB_WA
LOAD PS_SPRITE_DATA ; address of sprite data
DUP
INC 4 ; increment pointer
STORE PS_SPRITE_DATA ; and store it again
LOADI ; load word from orig. address
; ------- one word of sprite pixels on stack
STORE.B FB_SHIFTER
LOAD PS_X
STORE.B FB_SHIFTCOUNT
LOAD.B FB_SHIFTERM ; get shifted mask
NOT
LOAD.B FB_IO ; and background pixel data
AND ; remove foreground pixels
LOAD.B FB_SHIFTER ; get shifted pixels
OR ; combine with background
STORE.B FB_IO ; store into vmem
; set counter for remaining stripes
LOADC SPRITE_STRIPES - 1
STORE PS_STRIPE_C
;
; process spilled bits and next vertical stripe of sprite data
;
PS_NEXT_STRIPE:
;use spill bits from first column
LOAD.B FB_SHIFTERSP
LOAD PS_SPRITE_DATA ; address of sprite data
DUP
INC 4 ; increment pointer
STORE PS_SPRITE_DATA ; and store it again
LOADI ; load word from orig. address
STORE.B FB_SHIFTER ; store into shifter
LOAD PS_X
STORE.B FB_SHIFTCOUNT ; shift stuff
LOAD.B FB_SHIFTER ; get shifted pixels
OR ; combine with spill bits (see above)
DUP
STORE.B FB_MASKGEN ; store to mask reg to get new mask
LOAD.B FB_MASKGEN ; get mask for spill bits + shifted pixels
NOT
LOAD.B FB_IO ; get vmem data
AND ; remove foreground pixels from bg
OR ; combine with shifted pixels
STORE.B FB_IO ; write to vmem
LOAD PS_STRIPE_C ; decrement stripe count
DEC 1
DUP
STORE PS_STRIPE_C
CBRANCH.NZ PS_NEXT_STRIPE ; if non-zero, next stripe
; write spilled bits of the last stripe into next vmem word
LOAD.B FB_SHIFTERSP ; get spill bits
DUP
STORE.B FB_MASKGEN
LOAD.B FB_MASKGEN ; get sprite mask for spill bits
NOT
LOAD.B FB_IO ; load next vmem word
AND ; apply sprite mask
OR ; OR in spill bits
STORE.B FB_IO ; write to vmem
LOAD PS_SPRITE_LINES ; decrement lines count
DEC 1
DUP
CBRANCH.Z PS_L_XT ; exit if zero
STORE PS_SPRITE_LINES
; prepare next line
LOAD PS_VMEM_ADDR
LOADC WORDS_PER_LINE ; increment to next screen line
ADD
STORE PS_VMEM_ADDR
BRANCH PS_LOOP1
PS_L_XT:
DROP
LOAD PS_BPSAVE
STOREREG BP
FPADJ PS_FS
RET
; undraw a sprite, i.e. draw background data
; over a sprite location
; args: x,y, ptr to background data
.EQU UD_S_X 0
.EQU UD_S_Y 4
.EQU UD_S_PXS 8
.EQU UD_S_BGDATA 12
.EQU UD_S_OFFSET 16
.EQU UD_S_BGORIG 20
.EQU UD_STRIPE_C 24
.EQU UD_S_FS 28
UNDRAWSPRITE:
FPADJ -UD_S_FS
STORE UD_S_BGORIG
STORE UD_S_Y
STORE UD_S_X
; calculate pixel shift
LOAD UD_S_X
LOADC $7
AND
STORE UD_S_PXS
; calculate vmem offset
LOAD UD_S_X
LOAD UD_S_Y
LOADCP CALC_VMEM_ADDR
CALL
DUP
STORE UD_S_OFFSET
; calculate background data address from offset
SHL 2
LOAD UD_S_BGORIG
ADD
STORE UD_S_BGDATA
LOADC SPRITE_HEIGHT ; line count
UD_S_L1:
; store vmem offset into write addr reg
LOADCP FB_WA
LOAD UD_S_OFFSET
STOREI 4 ; ugly but fast: reuse addr
; with postincrement to
; get to FB_IO for STOREI below
; load a word of background data
LOAD UD_S_BGDATA
LOADI
; and write it to vmem
STOREI
; reuse addr from STOREI
LOADC SPRITE_STRIPES - 1 ; set remaining stripe count
STORE UD_STRIPE_C
UD_NEXT_STRIPE:
; load next word of background data
LOAD UD_S_BGDATA
INC 4
DUP
STORE UD_S_BGDATA
LOADI
STOREI ; and write it to vmem
; reuse addr from STOREI
LOAD UD_STRIPE_C ; decrease remaining stripe count
DEC 1
DUP
STORE UD_STRIPE_C
CBRANCH.NZ UD_NEXT_STRIPE ; if non-zero, next stripe
DROP ; remove addr from STOREI
; if pixel shift is zero, no spill word
LOAD UD_S_PXS
CBRANCH.Z UD_S_L2
; load next word of background data
LOADCP FB_IO
LOAD UD_S_BGDATA
INC 4
LOADI
STOREI ; and write it to vmem
DROP
UD_S_L2:
LOAD UD_S_OFFSET
LOADCP WORDS_PER_LINE
ADD
DUP
STORE UD_S_OFFSET
SHL 2
LOAD UD_S_BGORIG
ADD
STORE UD_S_BGDATA
DEC 1 ; decrement counter
DUP
CBRANCH.NZ UD_S_L1 ; check for zero
DROP ; remove counter
FPADJ UD_S_FS
RET