363 lines
6.6 KiB
ArmAsm
363 lines
6.6 KiB
ArmAsm
.EQU SPRITE_HEIGHT 16
|
|
|
|
.EQU WORDS_PER_LINE 80
|
|
.EQU FB_RA $900
|
|
.EQU FB_WA $901
|
|
.EQU FB_IO $902
|
|
.EQU FB_PS $903
|
|
|
|
; calculate mask for a word of pixels
|
|
; args: word of pixels with four bits per pixel
|
|
; returns: value that masks out all pixels that are set
|
|
CALC_MASK:
|
|
LOADC $F ; pixel mask
|
|
C_M_L0:
|
|
SWAP ; swap mask and pixels value
|
|
AND.S1.X2Y ; isolate one pixel, keep args
|
|
CBRANCH.Z C_M_L1 ; if pixel is zero, dont set mask bits
|
|
OVER ; copy current mask
|
|
OR ; or into pixels value
|
|
C_M_L1:
|
|
SWAP ; swap back, ToS is now mask bits
|
|
SHL 2 ; shift mask for next pixel to the left
|
|
SHL 2
|
|
|
|
DUP
|
|
CBRANCH.NZ C_M_L0 ; if mask is zero, we are done
|
|
DROP ; remove mask bits
|
|
NOT ; invert result
|
|
RET
|
|
|
|
; 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_FS 28
|
|
PUTSPRITE:
|
|
FPADJ -PS_FS
|
|
STORE PS_SPRITE_DATA
|
|
STORE PS_Y
|
|
STORE PS_X
|
|
|
|
; calculate vmem address
|
|
LOAD PS_X
|
|
LOAD PS_Y
|
|
LOADCP CALC_VMEM_ADDR
|
|
CALL
|
|
STORE PS_VMEM_ADDR
|
|
|
|
LOAD PS_X ; shift count = x mod 8
|
|
LOADC 7
|
|
AND
|
|
STORE PS_SHIFT_C
|
|
|
|
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
|
|
LOADC FB_RA ; read address register
|
|
LOAD PS_VMEM_ADDR
|
|
STOREI 1 ; use autoincrement to get to the next register
|
|
LOAD PS_VMEM_ADDR
|
|
STOREI
|
|
DROP
|
|
|
|
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
|
|
|
|
|
|
LOADC 0
|
|
STORE PS_SPILL
|
|
|
|
; loop to shift pixel data to right
|
|
LOAD PS_SHIFT_C ; load shift count
|
|
PS_LOOP2:
|
|
DUP ; test it for zero
|
|
CBRANCH.Z PS_LOOP2_X
|
|
|
|
SWAP ; swap count with pixels
|
|
|
|
; save the pixel that is shifted out
|
|
LOADC $F ; mask the four bits
|
|
AND.S0 ; keep original value on stack
|
|
BROT ; and move them to MSB
|
|
BROT
|
|
BROT
|
|
SHL 2
|
|
SHL 2 ; shift by 28 in total
|
|
|
|
LOAD PS_SPILL ; load spill bits
|
|
SHR ; shift by four to make space
|
|
SHR
|
|
SHR
|
|
SHR
|
|
OR ; or with orig value
|
|
STORE PS_SPILL ; store new value
|
|
|
|
SHR ; shift pixels right
|
|
SHR ; four bits per pixel
|
|
SHR
|
|
SHR
|
|
|
|
SWAP ; swap back, count now ToS
|
|
DEC 1
|
|
BRANCH PS_LOOP2
|
|
PS_LOOP2_X:
|
|
DROP ; remove shift count, shifted pixels now in ToS
|
|
|
|
DUP
|
|
LOADCP CALC_MASK ; calculate sprite mask for this word
|
|
CALL
|
|
|
|
LOADCP FB_IO ; address of the i/o register
|
|
LOADI ; read word from video mem
|
|
|
|
AND ; and word with mask
|
|
|
|
OR ; OR sprite data with original pixels
|
|
|
|
LOADCP FB_IO
|
|
SWAP
|
|
STOREI ; store result into i/o reg
|
|
DROP
|
|
|
|
;
|
|
; process spilled bits and right half of sprite data
|
|
;
|
|
|
|
; put spill bits on stack for later
|
|
LOAD PS_SPILL
|
|
|
|
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
|
|
|
|
; reset spill bits
|
|
LOADC 0
|
|
STORE PS_SPILL
|
|
|
|
; shift pixel data to right
|
|
LOAD PS_SHIFT_C ; load shift count
|
|
PS_LOOP3: ; test it for zero
|
|
DUP
|
|
CBRANCH.Z PS_LOOP3_X
|
|
|
|
SWAP ; swap count with pixels
|
|
|
|
; save the pixel that is shifted out
|
|
LOADC $F ; mask the four bits
|
|
AND.S0 ; keep original value on stack
|
|
BROT ; and move them to MSB
|
|
BROT
|
|
BROT
|
|
SHL 2
|
|
SHL 2 ; shift by 28 in total
|
|
|
|
LOAD PS_SPILL ; load spill bits
|
|
SHR ; shift by four to make space
|
|
SHR
|
|
SHR
|
|
SHR
|
|
OR ; or with orig value
|
|
STORE PS_SPILL ; store new value
|
|
|
|
SHR ; shift pixels right
|
|
SHR ; four bits per pixel
|
|
SHR
|
|
SHR
|
|
|
|
SWAP ; swap back, count now ToS
|
|
DEC 1
|
|
BRANCH PS_LOOP3
|
|
PS_LOOP3_X:
|
|
DROP ; remove shift count, shifted pixels now in ToS
|
|
|
|
OR ; or together with spill bits
|
|
|
|
DUP
|
|
LOADCP CALC_MASK ; calculate sprite mask
|
|
CALL
|
|
|
|
LOADCP FB_IO ; load original pixels
|
|
LOADI
|
|
|
|
AND ; and with mask
|
|
|
|
OR ; or together with original pixels
|
|
|
|
LOADCP FB_IO
|
|
SWAP
|
|
STOREI
|
|
DROP
|
|
|
|
; write spilled bits into next vmem word
|
|
LOAD PS_SPILL ; get spill bits
|
|
DUP
|
|
LOADCP CALC_MASK ; calculate sprite mask for spill bits
|
|
CALL
|
|
|
|
LOADCP FB_IO
|
|
LOADI ; load next vmem word
|
|
AND ; apply sprite mask
|
|
|
|
OR ; OR in spill bits
|
|
|
|
LOADCP FB_IO
|
|
SWAP ; swap pixels and addr
|
|
STOREI ; write back
|
|
DROP
|
|
|
|
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
|
|
|
|
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_S_FS 24
|
|
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 1 ; 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
|
|
|
|
; load 2nd word of background data
|
|
LOAD UD_S_BGDATA
|
|
INC 4
|
|
DUP
|
|
STORE UD_S_BGDATA
|
|
LOADI
|
|
STOREI ; and write it to vmem
|
|
DROP
|
|
|
|
; if pixel shift is zero, no 3rd word
|
|
LOAD UD_S_PXS
|
|
CBRANCH.Z UD_S_L2
|
|
|
|
; load 3rd word of background data
|
|
LOADCP FB_IO
|
|
LOAD UD_S_BGDATA
|
|
INC 4
|
|
DUP
|
|
STORE UD_S_BGDATA
|
|
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
|
|
|