First draft of masked tile support

Need to have the called provide a copy of the base line address to the
masked drawing code and need to verify that the JTable entries are
ordered the same way as the byte offset so the same register can be used
to load the JMP addresses and patch in the LDA (DP),y instructions.
This commit is contained in:
Lucas Scharenbroich 2021-08-13 10:05:28 -05:00
parent e3cb742626
commit 90124b04bc
4 changed files with 553 additions and 289 deletions

View File

@ -1,116 +1,174 @@
;
; Dereference a handle that is on the top of the stack
;
_Deref MAC
phb ; save caller's data bank register
pha ; push high word of handle on stack
plb ; sets B to the bank byte of the pointer
lda |$0002,x ; load the high word of the master pointer
pha ; and save it on the stack
lda |$0000,x ; load the low word of the master pointer
tax ; and return it in X
pla ; restore the high word in A
plb ; pull the handle's high word high byte off the
; stack
plb ; restore the caller's data bank register
<<<
_Deref MAC
phb ; save caller's data bank register
pha ; push high word of handle on stack
plb ; sets B to the bank byte of the pointer
lda |$0002,x ; load the high word of the master pointer
pha ; and save it on the stack
lda |$0000,x ; load the low word of the master pointer
tax ; and return it in X
pla ; restore the high word in A
plb ; pull the handle's high word high byte off the
; stack
plb ; restore the caller's data bank register
<<<
_Mul4096 mac
xba
asl
asl
asl
asl
<<<
_Mul4096 mac
xba
asl
asl
asl
asl
<<<
_Div16 mac
lsr
lsr
lsr
lsr
<<<
_Div16 mac
lsr
lsr
lsr
lsr
<<<
_R0W0 mac ; Read Bank 0 / Write Bank 0
ldal STATE_REG
and #$FFCF
stal STATE_REG
<<<
_R0W0 mac ; Read Bank 0 / Write Bank 0
ldal STATE_REG
and #$FFCF
stal STATE_REG
<<<
_R0W1 mac ; Read Bank 0 / Write Bank 1
ldal STATE_REG
ora #$0010
stal STATE_REG
<<<
_R0W1 mac ; Read Bank 0 / Write Bank 1
ldal STATE_REG
ora #$0010
stal STATE_REG
<<<
_R1W1 mac ; Read Bank 0 / Write Bank 1
ldal STATE_REG
ora #$0030
stal STATE_REG
<<<
_R1W1 mac ; Read Bank 0 / Write Bank 1
ldal STATE_REG
ora #$0030
stal STATE_REG
<<<
_PushReg mac ; Used to save/restore registers when calling subroutines.
pha
phx
phy
<<<
_PushReg mac ; Used to save/restore registers when calling subroutines.
pha
phx
phy
<<<
_PullReg mac
ply
plx
pla
<<<
_PullReg mac
ply
plx
pla
<<<
_PushReg2 mac ; Variation to also save the P-register to preserve m/x
pha
phx
phy
php
<<<
_PushReg2 mac ; Variation to also save the P-register to preserve m/x
pha
phx
phy
php
<<<
_PullReg2 mac
plp
ply
plx
pla
<<<
_PullReg2 mac
plp
ply
plx
pla
<<<
jne mac
beq *+5
jmp ]1
<<<
jne mac
beq *+5
jmp ]1
<<<
jeq mac
bne *+5
jmp ]1
<<<
jeq mac
bne *+5
jmp ]1
<<<
jcc mac
bcs *+5
jmp ]1
<<<
jcc mac
bcs *+5
jmp ]1
<<<
jcs mac
bcc *+5
jmp ]1
<<<
jcs mac
bcc *+5
jmp ]1
<<<
min mac
cmp ]1
bcc mout
lda ]1
mout <<<
min mac
cmp ]1
bcc mout
lda ]1
mout <<<
****************************************
* Basic Error Macro *
****************************************
_Err mac
bcc NoErr
do ]0 ; (DO if true)
jsr PgmDeath ; this is conditionally compiled if
str ]1 ; we pass in an error statement
else ; (ELSE)
jmp PgmDeath0 ; we just call the simpler error handler
fin ; (FIN)
NoErr eom
_Err mac
bcc NoErr
do ]0 ; (DO if true)
jsr PgmDeath ; this is conditionally compiled if
str ]1 ; we pass in an error statement
else ; (ELSE)
jmp PgmDeath0 ; we just call the simpler error handler
fin ; (FIN)
NoErr eom
; MAcros to use in the Masked Tile renderer
CopyMaskedWord MAC
ldal ]2,x ; load the mask value
bne mixed ; a non-zero value may be mixed
; This is a solid word
lda #$00F4 ; PEA instruction
sta: ]3,y
ldal ]1,x ; load the tile data
sta: ]3+1,y ; PEA operand
bra next
mixed cmp #$FFFF ; All 1's in the mask is fully transparent
beq transparent
; This is the slowest path because there is a *lot* of work to do. So much that it's
; worth it to change up the environment to optimize things a bit more.
lda #$004C ; JMP instruction
sta: ]3,y
ldx _X_REG ; Get the addressing offset
ldal JTableOffset,x ; Get the address offset and add to the base address
adc _BASE_ADDR ; of the current code field line (could be an ORA, too)
sta: ]3+1,y
tay ; This becomes the new address that we use to patch in
txa ; Get the offset and render a LDA (dp),y instruction
xba
ora #$00B1
sta: $0000,y
ldx _T_PTR ; restore the original x-register value
ldal ]1,x ; insert the tile mask and data into the exception
sta: $0003,y ; handler.
ldal ]2,x
sta: $0006,y
ldy _Y_REG ; restore original y-register value and move on
bra next
; This is a transparent word, so just show the second background layer
transparent
lda #$00B1 ; LDA (dp),y instruction
sta: ]3,y
lda _X_REG ; X is the logical tile offset (0, 2, 4, ... 82) left-to-right
ora #$4800 ; put a PHA after the offset
sta: ]3+1,y
next
eom

View File

@ -314,7 +314,7 @@ _UpdateBG0TileMap
ldx :BlkX
ldy :BlkY
jsr CopyTile
jsr RenderTile
lda :BlkX
inc
@ -469,5 +469,6 @@ _UpdateBG0TileMap

View File

@ -55,6 +55,7 @@ Next equ 78
BankLoad equ 128
tiletmp equ 186 ; 8 bytes of temp storage for the tile renderers
blttmp equ 192 ; 32 bytes of local cache/scratch space
tmp8 equ 224
@ -82,3 +83,4 @@ DIRTY_BIT_BG1_Y equ $0008
DIRTY_BIT_BG0_REFRESH equ $0010
DIRTY_BIT_BG1_REFRESH equ $0020

View File

@ -8,51 +8,63 @@
; CopyTileLinear -- copies the tile data from the tile bank in linear order, e.g.
; 32 consecutive bytes are copied
; CopyTile
; RenderTile
;
; A low-level function that copies 8x8 tiles directly into the code field space.
; A high-level function that takes a 16-bit tile descriptor and dispatched to the
; appropriate tile copy courinte based on the descritor flags
;
; Bit 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; |xx|xx|xx|MM|DD|VV|HH| | | | | | | | | |
; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
; \_______/ | | | | \________________________/
; | | | | | Tile ID (0 to 511)
; | | | | |
; | | | | +-- H : Flip tile horizontally
; | | | +----- V : Flip tile vertically
; | | +-------- D : Render as a Dynamic Tile (Tile ID < 32, V and H have no effect)
; | +----------- M : Apply tile mask
; +----------------- Reserved
;
; A = Tile ID (0 - 1023)
; X = Tile column (0 - 40)
; Y = Tile row (0 - 25)
CopyTile
phb ; save the current bank
phx ; save the original x-value
pha ; save the tile ID
tya ; lookup the address of the virtual line (y * 8)
asl
asl
asl
asl
tay
TILE_ID_MASK equ $01FF
TILE_MASK_BIT equ $1000
TILE_DYN_BIT equ $0800
TILE_VFLIP_BIT equ $0400
TILE_HFLIP_BIT equ $0200
TILE_CTRL_MASK equ $1E00
sep #$20 ; set the bank register
lda BTableHigh,y
pha ; save for a few instruction
rep #$20
; On entry
;
; B is set to the correct code field bank
; A is set to the the tile descriptor
; Y is set to the top-left address of the tile in the code field
; X is set to the tile word offset (0 through 80 in steps of 4)
;
; tmp0/tmp1 is reserved
RenderTile
bit #TILE_CTRL_MASK ; Fast path for "normal" tiles
beq _CopyTile
cmp #TILE_MASK_BIT ; Tile 0 w/mask bit set is special, too
bne *+5
brl ClearTile
phx ; Reverse the tile index since x = 0 is at the end
lda #40
sec
sbc 1,s
plx
phx ; Save the tile offset
asl ; there are two columns per tile, so multiple by 4
asl ; asl will clear the carry bit
tax
lda Col2CodeOffset,x
clc
adc BTableLow,y
tay
tax
and #TILE_ID_MASK ; Mask out the ID and save just tha
pha
plb ; set the bank
pla ; pop the tile ID
jsr :CopyTileMem0
txa
and #TILE_CTRL_MASK ; Mask out the different modifiers
xba
tax
jmp (:actions,x)
plx ; pop the x-register
plb ; restore the data bank and return
rts
:actions dw solid,solid_hflip,solid_vflip,solid_hvflip
dw dynamic,dynamic,dynamic,dynamic
dw masked,masked_hflip,masked_vflip,masked_hvflip
dw dyn_masked,dyn_masked,dyn_masked,dyn_masked
; _CopyTile
;
@ -62,131 +74,242 @@ CopyTile
; A = Tile ID (0 - 1023)
; Y = Base Adddress in the code field
:_CopyTile cmp #$0010
bcs *+5
brl :FillWord
cmp #$0400
bcs *+5
brl :CopyTileMem
rts ; Tile number is too large
_CopyTile cmp #$0000 ; Fast-path the special zero tile
bne CopyTileMem
:TilePatterns dw $0000,$1111,$2222,$3333
dw $4444,$5555,$6666,$7777
dw $8888,$9999,$AAAA,$BBBB
dw $CCCC,$DDDD,$EEEE,$FFFF
FillWord0
sta: $0001,y
sta: $0004,y
sta $1001,y
sta $1004,y
sta $2001,y
sta $2004,y
sta $3001,y
sta $3004,y
sta $4001,y
sta $4004,y
sta $5001,y
sta $5004,y
sta $6001,y
sta $6004,y
sta $7001,y
sta $7004,y ; Fall through here intentionally
:ClearTile sep #$20
lda #$B1
sta: $0000,y
sta: $0003,y
sta $1000,y
sta $1003,y
sta $2000,y
sta $2003,y
sta $3000,y
sta $3003,y
sta $4000,y
sta $4003,y
sta $5000,y
sta $5003,y
sta $6000,y
sta $6003,y
sta $7000,y
sta $7003,y
rep #$20
; For solid tiles
FillPEAOpcode
sep #$20
lda #$F4
sta: $0000,y
sta: $0003,y
sta $1000,y
sta $1003,y
sta $2000,y
sta $2003,y
sta $3000,y
sta $3003,y
sta $4000,y
sta $4003,y
sta $5000,y
sta $5003,y
sta $6000,y
sta $6003,y
sta $7000,y
sta $7003,y
rep #$20
rts
lda 3,s
asl
asl
and #$00FF
ora #$4800
sta: $0004,y
sta $1004,y
sta $2004,y
sta $3004,y
sta $4004,y
sta $5004,y
sta $6004,y
sta $7004,y
inc
inc
sta: $0001,y
sta $1001,y
sta $2001,y
sta $3001,y
sta $4001,y
sta $5001,y
sta $6001,y
sta $7001,y
rts
CopyTileMem
CopyTileMem0
asl ; Each tile takes up 64 bytes, 32 bytes for the
asl ; 8x8 data and 32 bytes for the 8x8 mask.
asl
asl
asl
asl
tax
ldal tiledata+0,x ; The low word goes in the *next* instruction
sta: $0004,y
ldal tiledata+2,x
sta: $0001,y
ldal tiledata+4,x
sta $1004,y
ldal tiledata+6,x
sta $1001,y
ldal tiledata+8,x
sta $2004,y
ldal tiledata+10,x
sta $2001,y
ldal tiledata+12,x
sta $3004,y
ldal tiledata+14,x
sta $3001,y
ldal tiledata+16,x
sta $4004,y
ldal tiledata+18,x
sta $4001,y
ldal tiledata+20,x
sta $5004,y
ldal tiledata+22,x
sta $5001,y
ldal tiledata+24,x
sta $6004,y
ldal tiledata+26,x
sta $6001,y
ldal tiledata+28,x
sta $7004,y
ldal tiledata+30,x
sta $7001,y
rts
:FillWord asl
tax
ldal :TilePatterns,x
; Masked tiles
;
; Can result in one or three different code sequences
;
; If mask === $0000, then insert PEA $DATA
; If mask === $FFFF, then insert LDA (DP),y / PHA
; Else then insert JMP and patch exception handler
;
; Because every word of the tile can lead to different opcodes, we
; do the entire setup for each word rather than breaking them up into
; 16-bit and 8-bit operations.
sta: $0001,y
sta: $0004,y
sta $1001,y
sta $1004,y
sta $2001,y
sta $2004,y
sta $3001,y
sta $3004,y
sta $4001,y
sta $4004,y
sta $5001,y
sta $5004,y
sta $6001,y
sta $6004,y
sta $7001,y
sta $7004,y
rts
; Macro to make the loop simpler. Takes three arguments
;
; ]1 = address of tile data
; ]2 = address of tile mask
; ]3 = address of target in code field
;
; This is a relatively efficient way to handle the three different modes. Focus on this and
; then we will adjust the setup code...
CopyTileMemM
_X_REG equ tiletmp
_Y_REG equ tiletmp+2
_T_PTR equ tiletmp+4 ; Copy of the tile address pointer
_BASE_ADDR equ tiletmp+6 ; Copy of BTableLow for this tile
:CopyTileMem sec
sbc #$0010
stx _X_REG ; Save these values as we will need to reload them
sty _Y_REG ; at certain points
:CopyTileMem0
asl
asl
asl
asl
asl
tax
asl ; Each tile takes up 64 bytes, 32 bytes for the
asl ; 8x8 data and 32 bytes for the 8x8 mask.
asl
asl
asl
asl
sta _T_PTR
tax
ldal tiledata+0,x ; The low word goes in the *next* instruction
sta: $0004,y
ldal tiledata+2,x
sta: $0001,y
ldal tiledata+4,x
sta $1004,y
ldal tiledata+6,x
sta $1001,y
ldal tiledata+8,x
sta $2004,y
ldal tiledata+10,x
sta $2001,y
ldal tiledata+12,x
sta $3004,y
ldal tiledata+14,x
sta $3001,y
ldal tiledata+16,x
sta $4004,y
ldal tiledata+18,x
sta $4001,y
ldal tiledata+20,x
sta $5004,y
ldal tiledata+22,x
sta $5001,y
ldal tiledata+24,x
sta $6004,y
ldal tiledata+26,x
sta $6001,y
ldal tiledata+28,x
sta $7004,y
ldal tiledata+30,x
sta $7001,y
rts
CopyMaskedWord tiledata+0;tiledata+32+0;$0003
CopyMaskedWord tiledata+2;tiledata+32+2;$0000
CopyMaskedWord tiledata+4;tiledata+32+4;$1003
CopyMaskedWord tiledata+6;tiledata+32+6;$1000
CopyMaskedWord tiledata+8;tiledata+32+8;$2003
CopyMaskedWord tiledata+10;tiledata+32+10;$2000
CopyMaskedWord tiledata+12;tiledata+32+12;$3003
CopyMaskedWord tiledata+14;tiledata+32+14;$3000
CopyMaskedWord tiledata+16;tiledata+32+16;$4003
CopyMaskedWord tiledata+18;tiledata+32+18;$4000
CopyMaskedWord tiledata+20;tiledata+32+20;$5003
CopyMaskedWord tiledata+22;tiledata+32+22;$5000
CopyMaskedWord tiledata+24;tiledata+32+24;$6003
CopyMaskedWord tiledata+28;tiledata+32+26;$6000
CopyMaskedWord tiledata+30;tiledata+32+28;$7003
CopyMaskedWord tiledata+32;tiledata+32+30;$7000
rts
TilePatterns dw $0000,$1111,$2222,$3333
dw $4444,$5555,$6666,$7777
dw $8888,$9999,$AAAA,$BBBB
dw $CCCC,$DDDD,$EEEE,$FFFF
ClearTile sep #$20
lda #$B1 ; This is a special case where we can set all the words to LDA (DP),y
sta: $0000,y
sta: $0003,y
sta $1000,y
sta $1003,y
sta $2000,y
sta $2003,y
sta $3000,y
sta $3003,y
sta $4000,y
sta $4003,y
sta $5000,y
sta $5003,y
sta $6000,y
sta $6003,y
sta $7000,y
sta $7003,y
rep #$20
txa
and #$00FF
ora #$4800
sta: $0004,y
sta $1004,y
sta $2004,y
sta $3004,y
sta $4004,y
sta $5004,y
sta $6004,y
sta $7004,y
inc
inc
sta: $0001,y
sta $1001,y
sta $2001,y
sta $3001,y
sta $4001,y
sta $5001,y
sta $6001,y
sta $7001,y
rts
; Copy a tile, but vertically flip the data
CopyTileMemV
asl ; Each tile takes up 64 bytes, 32 bytes for the
asl ; 8x8 data and 32 bytes for the 8x8 mask.
asl
asl
asl
asl
tax
ldal tiledata+0,x ; The low word goes in the *next* instruction
sta $7004,y
ldal tiledata+2,x
sta $7001,y
ldal tiledata+4,x
sta $6004,y
ldal tiledata+6,x
sta $6001,y
ldal tiledata+8,x
sta $5004,y
ldal tiledata+10,x
sta $5001,y
ldal tiledata+12,x
sta $4004,y
ldal tiledata+14,x
sta $4001,y
ldal tiledata+16,x
sta $3004,y
ldal tiledata+18,x
sta $3001,y
ldal tiledata+20,x
sta $2004,y
ldal tiledata+22,x
sta $2001,y
ldal tiledata+24,x
sta $1004,y
ldal tiledata+26,x
sta $1001,y
ldal tiledata+28,x
sta: $0004,y
ldal tiledata+30,x
sta: $0001,y
rts
; Primitives to render a dynamic tile
;
@ -195,49 +318,129 @@ CopyTile
;
; A = dynamic tile id (must be an 8-bit value)
:DynTile
and #$00FF
ora #$4800
sta: $0004,y
sta $1004,y
sta $2004,y
sta $3004,y
sta $4004,y
sta $5004,y
sta $6004,y
sta $7004,y
inc
inc
sta: $0001,y
sta $1001,y
sta $2001,y
sta $3001,y
sta $4001,y
sta $5001,y
sta $6001,y
sta $7001,y
sep #$20
lda #$B5
sta: $0000,y
sta: $0003,y
sta $1000,y
sta $1003,y
sta $2000,y
sta $2003,y
sta $3000,y
sta $3003,y
sta $4000,y
sta $4003,y
sta $5000,y
sta $5003,y
sta $6000,y
sta $6003,y
sta $7000,y
sta $7003,y
rep #$20
rts
DynTile
and #$00FF
ora #$4800
sta: $0004,y
sta $1004,y
sta $2004,y
sta $3004,y
sta $4004,y
sta $5004,y
sta $6004,y
sta $7004,y
inc
inc
sta: $0001,y
sta $1001,y
sta $2001,y
sta $3001,y
sta $4001,y
sta $5001,y
sta $6001,y
sta $7001,y
sep #$20
lda #$B5
sta: $0000,y
sta: $0003,y
sta $1000,y
sta $1003,y
sta $2000,y
sta $2003,y
sta $3000,y
sta $3003,y
sta $4000,y
sta $4003,y
sta $5000,y
sta $5003,y
sta $6000,y
sta $6003,y
sta $7000,y
sta $7003,y
rep #$20
rts
; This should never be called, because empty control value should be fast-pathed
solid
plx
pla
rts
; Not implemented yet, fallback to regular tile rendering
solid_hflip
plx
pla
brl CopyTileMem
solid_vflip
plx
pla
brl CopyTileMemV
; Not implemented, fallback to just vertical flips
solid_hvflip
plx
pla
brl CopyTileMemV
masked
plx
pla
brl CopyTileMemM
masked_hflip
masked_vflip
masked_hvflip
dynamic
dyn_masked
rts
; CopyTile
;
; A low-level function that copies 8x8 tiles directly into the code field space.
;
; A = Tile ID (0 - 1023)
; X = Tile column (0 - 40)
; Y = Tile row (0 - 25)
CopyTile
phb ; save the current bank
phx ; save the original x-value
pha ; save the tile ID
tya ; lookup the address of the virtual line (y * 8)
asl
asl
asl
asl
tay
sep #$20 ; set the bank register
lda BTableHigh,y
pha ; save for a few instruction
rep #$20
phx ; Reverse the tile index since x = 0 is at the end
lda #40
sec
sbc 1,s
plx
asl ; there are two columns per tile, so multiple by 4
asl ; asl will clear the carry bit
tax
lda Col2CodeOffset,x
clc
adc BTableLow,y
tay
plb ; set the bank
pla ; pop the tile ID
jsr CopyTileMem0
plx ; pop the x-register
plb ; restore the data bank and return
rts