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 ; Dereference a handle that is on the top of the stack
; ;
_Deref MAC _Deref MAC
phb ; save caller's data bank register phb ; save caller's data bank register
pha ; push high word of handle on stack pha ; push high word of handle on stack
plb ; sets B to the bank byte of the pointer plb ; sets B to the bank byte of the pointer
lda |$0002,x ; load the high word of the master pointer lda |$0002,x ; load the high word of the master pointer
pha ; and save it on the stack pha ; and save it on the stack
lda |$0000,x ; load the low word of the master pointer lda |$0000,x ; load the low word of the master pointer
tax ; and return it in X tax ; and return it in X
pla ; restore the high word in A pla ; restore the high word in A
plb ; pull the handle's high word high byte off the plb ; pull the handle's high word high byte off the
; stack ; stack
plb ; restore the caller's data bank register plb ; restore the caller's data bank register
<<< <<<
_Mul4096 mac _Mul4096 mac
xba xba
asl asl
asl asl
asl asl
asl asl
<<< <<<
_Div16 mac _Div16 mac
lsr lsr
lsr lsr
lsr lsr
lsr lsr
<<< <<<
_R0W0 mac ; Read Bank 0 / Write Bank 0 _R0W0 mac ; Read Bank 0 / Write Bank 0
ldal STATE_REG ldal STATE_REG
and #$FFCF and #$FFCF
stal STATE_REG stal STATE_REG
<<< <<<
_R0W1 mac ; Read Bank 0 / Write Bank 1 _R0W1 mac ; Read Bank 0 / Write Bank 1
ldal STATE_REG ldal STATE_REG
ora #$0010 ora #$0010
stal STATE_REG stal STATE_REG
<<< <<<
_R1W1 mac ; Read Bank 0 / Write Bank 1 _R1W1 mac ; Read Bank 0 / Write Bank 1
ldal STATE_REG ldal STATE_REG
ora #$0030 ora #$0030
stal STATE_REG stal STATE_REG
<<< <<<
_PushReg mac ; Used to save/restore registers when calling subroutines. _PushReg mac ; Used to save/restore registers when calling subroutines.
pha pha
phx phx
phy phy
<<< <<<
_PullReg mac _PullReg mac
ply ply
plx plx
pla pla
<<< <<<
_PushReg2 mac ; Variation to also save the P-register to preserve m/x _PushReg2 mac ; Variation to also save the P-register to preserve m/x
pha pha
phx phx
phy phy
php php
<<< <<<
_PullReg2 mac _PullReg2 mac
plp plp
ply ply
plx plx
pla pla
<<< <<<
jne mac jne mac
beq *+5 beq *+5
jmp ]1 jmp ]1
<<< <<<
jeq mac jeq mac
bne *+5 bne *+5
jmp ]1 jmp ]1
<<< <<<
jcc mac jcc mac
bcs *+5 bcs *+5
jmp ]1 jmp ]1
<<< <<<
jcs mac jcs mac
bcc *+5 bcc *+5
jmp ]1 jmp ]1
<<< <<<
min mac min mac
cmp ]1 cmp ]1
bcc mout bcc mout
lda ]1 lda ]1
mout <<< mout <<<
**************************************** ****************************************
* Basic Error Macro * * Basic Error Macro *
**************************************** ****************************************
_Err mac _Err mac
bcc NoErr bcc NoErr
do ]0 ; (DO if true) do ]0 ; (DO if true)
jsr PgmDeath ; this is conditionally compiled if jsr PgmDeath ; this is conditionally compiled if
str ]1 ; we pass in an error statement str ]1 ; we pass in an error statement
else ; (ELSE) else ; (ELSE)
jmp PgmDeath0 ; we just call the simpler error handler jmp PgmDeath0 ; we just call the simpler error handler
fin ; (FIN) fin ; (FIN)
NoErr eom 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 ldx :BlkX
ldy :BlkY ldy :BlkY
jsr CopyTile jsr RenderTile
lda :BlkX lda :BlkX
inc inc
@ -469,5 +469,6 @@ _UpdateBG0TileMap

View File

@ -55,6 +55,7 @@ Next equ 78
BankLoad equ 128 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 blttmp equ 192 ; 32 bytes of local cache/scratch space
tmp8 equ 224 tmp8 equ 224
@ -82,3 +83,4 @@ DIRTY_BIT_BG1_Y equ $0008
DIRTY_BIT_BG0_REFRESH equ $0010 DIRTY_BIT_BG0_REFRESH equ $0010
DIRTY_BIT_BG1_REFRESH equ $0020 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. ; CopyTileLinear -- copies the tile data from the tile bank in linear order, e.g.
; 32 consecutive bytes are copied ; 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) TILE_ID_MASK equ $01FF
asl TILE_MASK_BIT equ $1000
asl TILE_DYN_BIT equ $0800
asl TILE_VFLIP_BIT equ $0400
asl TILE_HFLIP_BIT equ $0200
tay TILE_CTRL_MASK equ $1E00
sep #$20 ; set the bank register ; On entry
lda BTableHigh,y ;
pha ; save for a few instruction ; B is set to the correct code field bank
rep #$20 ; 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 phx ; Save the tile offset
lda #40
sec
sbc 1,s
plx
asl ; there are two columns per tile, so multiple by 4 tax
asl ; asl will clear the carry bit and #TILE_ID_MASK ; Mask out the ID and save just tha
tax pha
lda Col2CodeOffset,x
clc
adc BTableLow,y
tay
plb ; set the bank txa
pla ; pop the tile ID and #TILE_CTRL_MASK ; Mask out the different modifiers
jsr :CopyTileMem0 xba
tax
jmp (:actions,x)
plx ; pop the x-register :actions dw solid,solid_hflip,solid_vflip,solid_hvflip
plb ; restore the data bank and return dw dynamic,dynamic,dynamic,dynamic
rts dw masked,masked_hflip,masked_vflip,masked_hvflip
dw dyn_masked,dyn_masked,dyn_masked,dyn_masked
; _CopyTile ; _CopyTile
; ;
@ -62,131 +74,242 @@ CopyTile
; A = Tile ID (0 - 1023) ; A = Tile ID (0 - 1023)
; Y = Base Adddress in the code field ; Y = Base Adddress in the code field
:_CopyTile cmp #$0010 _CopyTile cmp #$0000 ; Fast-path the special zero tile
bcs *+5 bne CopyTileMem
brl :FillWord
cmp #$0400
bcs *+5
brl :CopyTileMem
rts ; Tile number is too large
:TilePatterns dw $0000,$1111,$2222,$3333 FillWord0
dw $4444,$5555,$6666,$7777 sta: $0001,y
dw $8888,$9999,$AAAA,$BBBB sta: $0004,y
dw $CCCC,$DDDD,$EEEE,$FFFF 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 ; For solid tiles
lda #$B1 FillPEAOpcode
sta: $0000,y sep #$20
sta: $0003,y lda #$F4
sta $1000,y sta: $0000,y
sta $1003,y sta: $0003,y
sta $2000,y sta $1000,y
sta $2003,y sta $1003,y
sta $3000,y sta $2000,y
sta $3003,y sta $2003,y
sta $4000,y sta $3000,y
sta $4003,y sta $3003,y
sta $5000,y sta $4000,y
sta $5003,y sta $4003,y
sta $6000,y sta $5000,y
sta $6003,y sta $5003,y
sta $7000,y sta $6000,y
sta $7003,y sta $6003,y
rep #$20 sta $7000,y
sta $7003,y
rep #$20
rts
lda 3,s CopyTileMem
asl CopyTileMem0
asl asl ; Each tile takes up 64 bytes, 32 bytes for the
and #$00FF asl ; 8x8 data and 32 bytes for the 8x8 mask.
ora #$4800 asl
sta: $0004,y asl
sta $1004,y asl
sta $2004,y asl
sta $3004,y tax
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
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 ; Masked tiles
tax ;
ldal :TilePatterns,x ; 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 ; Macro to make the loop simpler. Takes three arguments
sta: $0004,y ;
sta $1001,y ; ]1 = address of tile data
sta $1004,y ; ]2 = address of tile mask
sta $2001,y ; ]3 = address of target in code field
sta $2004,y ;
sta $3001,y ; This is a relatively efficient way to handle the three different modes. Focus on this and
sta $3004,y ; then we will adjust the setup code...
sta $4001,y CopyTileMemM
sta $4004,y _X_REG equ tiletmp
sta $5001,y _Y_REG equ tiletmp+2
sta $5004,y _T_PTR equ tiletmp+4 ; Copy of the tile address pointer
sta $6001,y _BASE_ADDR equ tiletmp+6 ; Copy of BTableLow for this tile
sta $6004,y
sta $7001,y
sta $7004,y
rts
:CopyTileMem sec stx _X_REG ; Save these values as we will need to reload them
sbc #$0010 sty _Y_REG ; at certain points
:CopyTileMem0 asl ; Each tile takes up 64 bytes, 32 bytes for the
asl asl ; 8x8 data and 32 bytes for the 8x8 mask.
asl asl
asl asl
asl asl
asl asl
tax sta _T_PTR
tax
ldal tiledata+0,x ; The low word goes in the *next* instruction CopyMaskedWord tiledata+0;tiledata+32+0;$0003
sta: $0004,y CopyMaskedWord tiledata+2;tiledata+32+2;$0000
ldal tiledata+2,x CopyMaskedWord tiledata+4;tiledata+32+4;$1003
sta: $0001,y CopyMaskedWord tiledata+6;tiledata+32+6;$1000
ldal tiledata+4,x CopyMaskedWord tiledata+8;tiledata+32+8;$2003
sta $1004,y CopyMaskedWord tiledata+10;tiledata+32+10;$2000
ldal tiledata+6,x CopyMaskedWord tiledata+12;tiledata+32+12;$3003
sta $1001,y CopyMaskedWord tiledata+14;tiledata+32+14;$3000
ldal tiledata+8,x CopyMaskedWord tiledata+16;tiledata+32+16;$4003
sta $2004,y CopyMaskedWord tiledata+18;tiledata+32+18;$4000
ldal tiledata+10,x CopyMaskedWord tiledata+20;tiledata+32+20;$5003
sta $2001,y CopyMaskedWord tiledata+22;tiledata+32+22;$5000
ldal tiledata+12,x CopyMaskedWord tiledata+24;tiledata+32+24;$6003
sta $3004,y CopyMaskedWord tiledata+28;tiledata+32+26;$6000
ldal tiledata+14,x CopyMaskedWord tiledata+30;tiledata+32+28;$7003
sta $3001,y CopyMaskedWord tiledata+32;tiledata+32+30;$7000
ldal tiledata+16,x
sta $4004,y rts
ldal tiledata+18,x
sta $4001,y TilePatterns dw $0000,$1111,$2222,$3333
ldal tiledata+20,x dw $4444,$5555,$6666,$7777
sta $5004,y dw $8888,$9999,$AAAA,$BBBB
ldal tiledata+22,x dw $CCCC,$DDDD,$EEEE,$FFFF
sta $5001,y
ldal tiledata+24,x ClearTile sep #$20
sta $6004,y lda #$B1 ; This is a special case where we can set all the words to LDA (DP),y
ldal tiledata+26,x sta: $0000,y
sta $6001,y sta: $0003,y
ldal tiledata+28,x sta $1000,y
sta $7004,y sta $1003,y
ldal tiledata+30,x sta $2000,y
sta $7001,y sta $2003,y
rts 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 ; Primitives to render a dynamic tile
; ;
@ -195,49 +318,129 @@ CopyTile
; ;
; A = dynamic tile id (must be an 8-bit value) ; A = dynamic tile id (must be an 8-bit value)
:DynTile DynTile
and #$00FF and #$00FF
ora #$4800 ora #$4800
sta: $0004,y sta: $0004,y
sta $1004,y sta $1004,y
sta $2004,y sta $2004,y
sta $3004,y sta $3004,y
sta $4004,y sta $4004,y
sta $5004,y sta $5004,y
sta $6004,y sta $6004,y
sta $7004,y sta $7004,y
inc inc
inc inc
sta: $0001,y sta: $0001,y
sta $1001,y sta $1001,y
sta $2001,y sta $2001,y
sta $3001,y sta $3001,y
sta $4001,y sta $4001,y
sta $5001,y sta $5001,y
sta $6001,y sta $6001,y
sta $7001,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
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