mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2025-02-12 14:31:00 +00:00
Transition to fixed snippets
This commit is contained in:
parent
c14f3c7283
commit
dd9ced08f1
@ -61,7 +61,7 @@ Scale equ 56
|
||||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
@ -49,7 +49,7 @@ appTmp2 equ 32
|
||||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
@ -60,12 +60,14 @@ appTmp2 equ 32
|
||||
|
||||
; Initialize the graphics screen playfield
|
||||
|
||||
pea #320
|
||||
pea #160
|
||||
pea #200
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset
|
||||
|
||||
pea #0
|
||||
pea #511
|
||||
pea #^tiledata
|
||||
pea #tiledata
|
||||
_GTELoadTileSet
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,17 +14,17 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run build && npm run build:image && npm run gsport",
|
||||
"gsport": "%npm_package_config_gsport%",
|
||||
"debug": "%npm_package_config_crossrunner% GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"gsport": "cross-var $npm_package_config_gsport",
|
||||
"debug": "cross-var $npm_package_config_crossrunner GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"build:all": "npm run build:tiles && npm run build:map && npm run build:tool && npm run build:sys16 && npm run build:image",
|
||||
"build:map": "node %npm_package_config_tiled2iigs% ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build:map": "cross-var node $npm_package_config_tiled2iigs ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --var-name tiledata --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --var-name tiledata --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros App.s",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../../src/Master.s",
|
||||
"build:image": "build-image.bat %npm_package_config_cadius%",
|
||||
"build:background": "node %npm_package_config_png2iigs% ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
"build:tool": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros ../../../src/Master.s",
|
||||
"build:image": "cross-var build-image.bat $npm_package_config_cadius",
|
||||
"build:background": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -37,6 +37,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/lscharen/iigs-game-engine#readme",
|
||||
"devDependencies": {
|
||||
"cross-var": "^1.1.0",
|
||||
"pngjs": "^6.0.0",
|
||||
"string-builder": "^0.1.8",
|
||||
"watch": "latest",
|
||||
|
@ -60,7 +60,7 @@ SpriteCount equ 54
|
||||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
@ -75,12 +75,14 @@ SpriteCount equ 54
|
||||
|
||||
; Initialize the graphics screen playfield
|
||||
|
||||
pea #320
|
||||
pea #160
|
||||
pea #200
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset
|
||||
|
||||
pea #0
|
||||
pea #511
|
||||
pea #^tiledata
|
||||
pea #tiledata
|
||||
_GTELoadTileSet
|
||||
@ -141,6 +143,8 @@ SpriteCount equ 54
|
||||
|
||||
; Create the sprites
|
||||
|
||||
HERO_SIZE equ {SPRITE_16X16}
|
||||
HERO_FLAGS equ HERO_SIZE ; no extra H/V bits for now
|
||||
HERO_FRAME_1 equ {SPRITE_16X16+1}
|
||||
HERO_VBUFF_1 equ VBUFF_SPRITE_START+0*VBUFF_SPRITE_STEP
|
||||
HERO_FRAME_2 equ {SPRITE_16X16+7}
|
||||
@ -168,31 +172,23 @@ HERO_SLOT_2 equ 2
|
||||
pea HERO_VBUFF_4
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
pea HERO_FRAME_1
|
||||
pea HERO_SLOT_1 ; Put the player in slot 1
|
||||
pea HERO_FLAGS
|
||||
pea HERO_VBUFF_1
|
||||
pei PlayerX
|
||||
pei PlayerY
|
||||
pea HERO_SLOT_1 ; Put the player in slot 1
|
||||
_GTEAddSprite
|
||||
|
||||
pea HERO_SLOT_1
|
||||
pea $0000
|
||||
pea HERO_VBUFF_1 ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
pea HERO_FRAME_2
|
||||
pea HERO_SLOT_2
|
||||
pea HERO_FLAGS
|
||||
pea HERO_VBUFF_2
|
||||
pei PlayerX
|
||||
lda PlayerY
|
||||
clc
|
||||
adc #16
|
||||
pha
|
||||
pea HERO_SLOT_2 ; Put the player in slot 1
|
||||
_GTEAddSprite
|
||||
|
||||
pea HERO_SLOT_2
|
||||
pea $0000
|
||||
pea HERO_VBUFF_3 ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
EvtLoop
|
||||
pha
|
||||
_GTEReadControl
|
||||
|
@ -14,17 +14,17 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run build && npm run build:image && npm run gsport",
|
||||
"gsport": "%npm_package_config_gsport%",
|
||||
"debug": "%npm_package_config_crossrunner% GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"gsport": "cross-var $npm_package_config_gsport",
|
||||
"debug": "cross-var $npm_package_config_crossrunner GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"build:all": "npm run build:tiles && npm run build:map && npm run build:tool && npm run build:sys16 && npm run build:image",
|
||||
"build:map": "node %npm_package_config_tiled2iigs% ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build:map": "cross-var node $npm_package_config_tiled2iigs ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros App.s",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../../src/Master.s",
|
||||
"build:image": "build-image.bat %npm_package_config_cadius%",
|
||||
"build:background": "node %npm_package_config_png2iigs% ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
"build:tool": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros ../../../src/Master.s",
|
||||
"build:image": "cross-var build-image.bat $npm_package_config_cadius",
|
||||
"build:background": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -37,6 +37,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/lscharen/iigs-game-engine#readme",
|
||||
"devDependencies": {
|
||||
"cross-var": "^1.1.0",
|
||||
"pngjs": "^6.0.0",
|
||||
"string-builder": "^0.1.8",
|
||||
"watch": "latest",
|
||||
|
@ -166,216 +166,3 @@ ScriptStep MAC
|
||||
dw ]1,]2,]3,]4
|
||||
FIN
|
||||
<<<
|
||||
|
||||
; A specialized CopyMaskedWord macro that draws a tile from a direct page workspace. Used
|
||||
; to render fringe tiles and sprite tiles when BG1 is active. If there is no second background,
|
||||
; then one should use the optimized functions which assumes a PEA opcode and only
|
||||
; needs to copy data words
|
||||
;
|
||||
; ]1 : tiledata direct page address , the tilemask direct page address is tiledata + 32
|
||||
; ]2 : code field offset
|
||||
CopyMaskedWordD MAC
|
||||
lda ]1+32 ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
lda ]1 ; load the tile data
|
||||
sta: ]2+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.
|
||||
;
|
||||
; Need to fill in the first 10 bytes of the JMP handler with the following code sequence
|
||||
;
|
||||
; lda (00),y
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
|
||||
lda #$004C ; JMP instruction
|
||||
sta: ]2,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
|
||||
adc #{]2&$F000} ; adjust for the current row offset
|
||||
sta: ]2+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
|
||||
|
||||
sep #$20
|
||||
sta: $0001,y ; LDA (00),y operand
|
||||
lda #$B1
|
||||
sta: $0000,y ; LDA (00),y opcode
|
||||
lda #$29
|
||||
sta: $0002,y ; AND #$0000 opcode
|
||||
lda #$09
|
||||
sta: $0005,y ; ORA #$0000 opcode
|
||||
rep #$20
|
||||
|
||||
lda ]1+32 ; insert the tile mask and data into the exception
|
||||
sta: $0003,y ; handler.
|
||||
lda ]1
|
||||
sta: $0006,y
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,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: ]2,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: ]2+1,y
|
||||
next
|
||||
eom
|
||||
|
||||
; Macros to use in the Masked Tile renderer
|
||||
;
|
||||
; ]1 : tiledata offset
|
||||
; ]2 : tilemask offset
|
||||
; ]3 : code field offset
|
||||
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.
|
||||
;
|
||||
; Need to fill in the first 8 bytes of the JMP handler with the following code sequence
|
||||
;
|
||||
; lda (00),y
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
|
||||
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
|
||||
ora _BASE_ADDR ; of the current code field row (2 rows per bank) $0000 or $8000
|
||||
ora #{]3&$7000} ; adjust for the current line offset within the row
|
||||
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
|
||||
|
||||
sep #$20
|
||||
sta: $0001,y ; LDA (00),y operand
|
||||
lda #$B1
|
||||
sta: $0000,y ; LDA (00),y opcode
|
||||
lda #$29
|
||||
sta: $0002,y ; AND #$0000 opcode
|
||||
lda #$09
|
||||
sta: $0005,y ; ORA #$0000 opcode
|
||||
rep #$20
|
||||
|
||||
ldx _T_PTR ; restore the original x-register value
|
||||
ldal ]2,x ; insert the tile mask and data into the exception
|
||||
sta: $0003,y ; handler.
|
||||
ldal ]1,x
|
||||
sta: $0006,y
|
||||
|
||||
; Copy the top 9 bytes down. We have 23 bytes of space and are only using 8. Since 9 + 8 = 17 < 23, we
|
||||
; can save 3 cycles per word by eliminating the BRA instruction
|
||||
|
||||
; lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
; sta: $0008,y
|
||||
|
||||
lda: $0017,y
|
||||
sta: $0008,y
|
||||
lda: $0019,y
|
||||
sta: $000A,y
|
||||
lda: $001B,y
|
||||
sta: $000C,y
|
||||
lda: $001D,y
|
||||
sta: $000E,y
|
||||
lda: $001E,y
|
||||
sta: $000F,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
|
||||
|
||||
; Large code blocks that can be used in sprite blitters
|
||||
; ]1: line number
|
||||
OneSpriteToCodeField mac
|
||||
lda blttmp+{]1*4}
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]1*$1000},y
|
||||
|
||||
lda blttmp+{]1*4}+2
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]1*$1000},y
|
||||
eom
|
||||
|
||||
TwoSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
||||
ThreeSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
@ -58,8 +58,8 @@ _Render
|
||||
jsr _UpdateBG0TileMap ; and the tile maps. These subroutines build up a list of tiles
|
||||
; jsr _UpdateBG1TileMap ; that need to be updated in the code field
|
||||
|
||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||
|
||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||
jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||
|
||||
lda #RENDER_BG1_ROTATION
|
||||
|
@ -268,7 +268,7 @@ _SetNormalTileProcs
|
||||
brl :pickDynProc
|
||||
|
||||
:pickTwoLyrProc ldy #TwoLyrProcs
|
||||
pla ; pull of the proc index
|
||||
pla ; pull off the proc index
|
||||
jmp _SetTileProcs
|
||||
|
||||
; Specialized check for when the engine is in "Fast" mode. If is a simple decision tree based on whether
|
||||
|
@ -25,6 +25,12 @@ ENABLE_INT equ enable_int-base ; offset that re-enable inte
|
||||
LINES_PER_BANK equ 16
|
||||
SNIPPET_BASE equ snippets-base
|
||||
|
||||
; offsets from each snippet base address for the different entry points
|
||||
|
||||
SNIPPET_ENTRY_1 equ 0 ; two layer + dynamic tile + sprite
|
||||
SNIPPET_ENTRY_2 equ 4 ; (two layer | dynamic tile) + sprite
|
||||
SNIPPET_ENTRY_3 equ 18 ; two layer + dynamic tile (no sprite)
|
||||
|
||||
; Locations that need the page offset added
|
||||
PagePatches da {long_0-base+2}
|
||||
da {long_1-base+2}
|
||||
@ -43,9 +49,9 @@ PagePatches da {long_0-base+2}
|
||||
; da {jmp_rtn_2-base+2}
|
||||
|
||||
]index equ 0
|
||||
lup 82 ; All the snippet addresses. The two JMP
|
||||
da {snippets-base+{]index*32}+31} ; instructions are at the end of each of
|
||||
da {snippets-base+{]index*32}+28} ; the 32-byte buffers
|
||||
lup 82 ; Patch anything that needs updating within the snippets
|
||||
da {snippets-base+{]index*32}+17}
|
||||
da {snippets-base+{]index*32}+28}
|
||||
]index equ ]index+1
|
||||
--^
|
||||
PagePatchNum equ *-PagePatches
|
||||
@ -232,88 +238,93 @@ epilogue_1 tsc
|
||||
; its passed state, because having the carry bit clear prevents evaluation of
|
||||
; the V bit.
|
||||
;
|
||||
; The snippet code is fixed to allow fast updates and the entry point is chosen based on the
|
||||
; EngineMode during initializations
|
||||
; Version 2: In order to improve performance, especially for two-layer tiles + sprites, the
|
||||
; snippet code was revised to have a fixed structure so that the constant DATA and
|
||||
; MASK values always exist in the same location, regarless of the tile type. The
|
||||
; tradeoff is that there is a different entry point into the snippet based on the
|
||||
; tile type, but that is significantly cheaper to lookup and patch into the code
|
||||
; field JMP instruction than it is to rebuild 20+ bytes of code each time.
|
||||
;
|
||||
; _snippet
|
||||
; lda (00),y ; Entry point for mixed dyn & bg1. Set opcode below.
|
||||
; and 80,x
|
||||
; lda (00),y ; Entry point for BG1 or Dyn. Change opcode.
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; _2 bcs _alt
|
||||
; There are different snippet templates + offset tables based on the EngineMode
|
||||
;
|
||||
; EngineMode
|
||||
;
|
||||
; ENGINE_MODE_TWO_LAYER NO
|
||||
; ENGINE_MODE_DYN_TILES NO
|
||||
;
|
||||
; Snippet Template
|
||||
; None.
|
||||
;
|
||||
; ENGINE_MODE_TWO_LAYER YES
|
||||
; ENGINE_MODE_DYN_TILES NO
|
||||
;
|
||||
; Snippet Template
|
||||
;
|
||||
; ds 4
|
||||
; lda (00),y <-- Single Entry Point
|
||||
; and #MASK <-- Mask is always at byte 8
|
||||
; ora #DATA <-- Data is always at byte 11
|
||||
; bcs _alt
|
||||
; pha
|
||||
; jmp NEXT
|
||||
; _alt jmp RTN
|
||||
;
|
||||
; ENGINE_MODE_TWO_LAYER NO
|
||||
; ENGINE_MODE_DYN_TILES YES
|
||||
;
|
||||
; Snippet Template
|
||||
;
|
||||
; ds 4
|
||||
; lda 00,x <-- Single Entry Point
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bcs _alt
|
||||
; pha
|
||||
; jmp NEXT
|
||||
; _alt jmp RTN
|
||||
;
|
||||
; ENGINE_MODE_TWO_LAYER YES
|
||||
; ENGINE_MODE_DYN_TILES YES
|
||||
;
|
||||
; Snippet Template
|
||||
;
|
||||
; lda (00),y <-- Entry Point 1
|
||||
; and $80,x
|
||||
; ora $00,x <-- Entry Point 2 (Change this word to "lda (00),y" or "lda 00,x", or "ora 00,x" depending on combination)
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bcs _alt
|
||||
; _16bit pha
|
||||
; jmp NEXT
|
||||
; lda (00),y <--- Entry Point 3 (sneak this in here to avoid extra branch)
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bcc _16bit
|
||||
; _alt jmp RTN (29 bytes)
|
||||
;
|
||||
; Note that the code that's assembled in these snippets is just a template. Every routine that utilizes
|
||||
; an exception handler *MUST* patch up the routines. There are different routines based on the Engine Mode.
|
||||
;
|
||||
; The LDA (00),y opcodes have a fixed operand, but the dynamic tile instructions are determined by the
|
||||
; dynamic tile id and must be set each time.
|
||||
|
||||
; Snippet Samples:
|
||||
;
|
||||
; Standard Two-level Mix (23 bytes)
|
||||
;
|
||||
; Optimal = 18 cycles (LDA/AND/ORA/PHA/JMP)
|
||||
; 16-bit write = 20 cycles
|
||||
; 8-bit low = 28 cycles
|
||||
; 8-bit high = 27 cycles
|
||||
;
|
||||
; start lda (00),y ; 6
|
||||
; and #MASK ; 3
|
||||
; ora #DATA ; 3 = 12 cycles to load the data
|
||||
; bcs alt_exit ; 2/3
|
||||
; pha ; 4
|
||||
; out jmp next ; 3 Fast-path completes in 5 additional cycles
|
||||
; alt_exit jmp jmp_rtn ; 3
|
||||
;
|
||||
;
|
||||
; For dynamic masked tiles, we re-write bytes 2 - 8 as this, which mostly
|
||||
; avoids an execution speed pentaly for having to fill in the two extra bytes
|
||||
; with an instruction
|
||||
;
|
||||
; start lda (00),y ; 6
|
||||
; and $80,x ; 5
|
||||
; ora $00,x ; 5 = 16 cycles to load the data
|
||||
; bcs alt_exit ; 2/3
|
||||
; pha
|
||||
; ...
|
||||
;
|
||||
; A theoretical exception handler that performed a full 3-level blend would be
|
||||
;
|
||||
; start lda 0,s
|
||||
; and [00],y
|
||||
; ora (00),y
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bcs alt_exit
|
||||
; pha ; 4
|
||||
; out brl next ; 4 Fast-path completes in 5 additional cycles
|
||||
;
|
||||
; alt_exit bvs r_edge ; 2/3
|
||||
; clc ; 2
|
||||
; brl l_jmp_rtn ; 3
|
||||
; r_edge rep #$41
|
||||
; brl r_jmp_rtn ; 3
|
||||
|
||||
; Each snippet is provided 32 bytes of space. The constant code is filled in from the end and
|
||||
; it is the responsibility of the code that fills in the hander to create valid program in the
|
||||
; first 23 bytes are available to be manipulated.
|
||||
;
|
||||
; Note that the code that's assembled in the first bytes of these snippets is just an example. Every
|
||||
; routine that created an exception handler *MUST* write a full set of instructions since there is
|
||||
; no guarantee of what was written previously.
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
]index equ 0
|
||||
snippets lup 82
|
||||
ds 2 ; space for all exception handlers
|
||||
and #$0000 ; the mask operand will be set when the tile is drawn
|
||||
ora #$0000 ; the data operand will be set when the tile is drawn
|
||||
ds 15 ; extra padding
|
||||
|
||||
bcs :byte ; if C = 0, just push the data and return
|
||||
pha ; 1 byte
|
||||
jmp loop+3+{3*]index}-base ; 3 bytes
|
||||
:byte jmp jmp_rtn-base ; 3 bytes
|
||||
lda ({{81-]index}*2}),y ; 0: Pre-set the LDA (XX),y instructions
|
||||
and $80,x ; 2: The direct page instructions are placeholders and get overwritten
|
||||
ora $00,x ; 4: This gets patched out often
|
||||
and #$0000 ; 6: the mask operand will be set when the tile is drawn
|
||||
ora #$0000 ; 9: the data operand will be set when the tile is drawn
|
||||
bcs :byte ; 12: if C = 0, just push the data and return
|
||||
:word pha ; 14:
|
||||
jmp loop+3+{3*]index}-base ; 15: Return address offset within the code field
|
||||
lda ({{81-]index}*2}),y ; 18: Pre-set the LDA (XX),y instructions
|
||||
and $80,x ; 20:
|
||||
ora $00,x ; 22:
|
||||
bcc :word ; 24:
|
||||
:byte jmp jmp_rtn-base ; 26:
|
||||
ds 3 ; 29: Padding to make a full 32 bytes
|
||||
]index equ ]index+1
|
||||
--^
|
||||
top
|
@ -72,7 +72,7 @@ Counter equ tmp3
|
||||
rts
|
||||
|
||||
|
||||
; Patch an 8-bit or 16-bit valueS into the bank. These are a set up unrolled loops to
|
||||
; Patch an 8-bit or 16-bit valueS into the bank. These are set up as unrolled loops to
|
||||
; quickly patch in a constant value, or a value from an array into a given set of
|
||||
; templates.
|
||||
;
|
||||
|
@ -459,8 +459,76 @@ CopyMaskedDWord MAC
|
||||
sta: $0004,x ; ORA $00,x
|
||||
lda #$0F80 ; branch to the prologue (BRA *+17)
|
||||
sta: $0006,x
|
||||
|
||||
; Version 2 only needs to set the JMP address to Entry Point 3
|
||||
; lda _JTBL_CACHE
|
||||
; ora #{{]1}&$7000} ; adjust for the current row offset
|
||||
; sta: {]1}+1,y
|
||||
|
||||
eom
|
||||
|
||||
; Version 2 will set the JMP to Entry Point 1 and set the Opcode at Entry Point 2 to a ora $00,x. Also
|
||||
; the mask transparency check can be performed earlier.
|
||||
;
|
||||
; lda #$004C ; JMP to handler
|
||||
; sta: {]2},y
|
||||
; lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
; ora #{]2&$7000} ; adjust for the current row offset
|
||||
; sta: {]2}+1,y
|
||||
; tax ; This becomes the new address that we use to patch in
|
||||
; lda OP_CACHE_2 ; switch from AND to ORA instruction cached in setup
|
||||
; sta: $0004,x ; ORA $00,x
|
||||
|
||||
CopyDynMaskedSpriteWord2 MAC
|
||||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code and eliminate the constant AND/ORA instructions.
|
||||
|
||||
lda tmp_sprite_mask+{]1} ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: {]2},y
|
||||
|
||||
lda tmp_sprite_data+{]1} ; load the sprite data
|
||||
sta: {]2}+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
; We will always do a JMP to the exception handler, but the entry point changes depending on
|
||||
; whether the mask is transparent or not
|
||||
mixed
|
||||
cmp #$FFFF
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE2
|
||||
sta: $0004,x ; ORA $00,x
|
||||
|
||||
lda tmp_sprite_mask+{]1}
|
||||
sta: $0007,x
|
||||
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $000A,x
|
||||
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data overlaid on layer 2
|
||||
transparent
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000}.ENTRY_POINT_2 ; adjust for the current row offset and OR in the offset since snippets are 32-byte aligned
|
||||
sta: {]2}+1,y
|
||||
|
||||
next
|
||||
eom
|
||||
|
||||
; Masked renderer for a masked dynamic tile with sprite data overlaid.
|
||||
;
|
||||
@ -479,7 +547,7 @@ CopyDynMaskedSpriteWord MAC
|
||||
; bra *+15
|
||||
;
|
||||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code and eliminate the constanct AND/ORA instructions.
|
||||
; code and eliminate the constant AND/ORA instructions.
|
||||
|
||||
lda tmp_sprite_mask+{]1} ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
@ -493,6 +561,7 @@ CopyDynMaskedSpriteWord MAC
|
||||
|
||||
; We will always do a JMP to the exception handler, so set that up, then check for sprite
|
||||
; transparency
|
||||
|
||||
mixed
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
|
@ -7,8 +7,8 @@
|
||||
; GenericUnderSlow : Places the TileStore's tile on top of tmp_sprite_data
|
||||
|
||||
ConstTile0Slow
|
||||
jsr FillPEAOpcode
|
||||
jmp ConstTile0Fast
|
||||
jsr FillPEAOpcode ; Could these be slightly faster to do PEA ConstTile0Fast-1 ; JMP FillPEAOpcode?
|
||||
jmp ConstTile0Fast ; Currently it's 6 + 6 + 3 + 6, improved would be 5 + 3 + 6 + 6 = 1 cycle saved. :(
|
||||
|
||||
SpriteOverASlow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
@ -79,12 +79,6 @@ FillPEAOpcode
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; This is a stub; will be removed eventually
|
||||
_FillPEAOpcode
|
||||
jsr FillPEAOpcode
|
||||
plb ; Restore the TileStore bank
|
||||
rts
|
||||
|
||||
CopyTileASlow
|
||||
tax
|
||||
jsr FillPEAOpcode
|
||||
|
@ -50,6 +50,7 @@ Tile0TwoLyr
|
||||
SpriteOver0TwoLyr
|
||||
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2 ; Offset into the second entry point
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
@ -95,6 +96,7 @@ SpriteOver0TwoLyr
|
||||
|
||||
TmpTileDataToCodeField
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
@ -143,6 +145,7 @@ _TmpTileDataToCodeField
|
||||
; Copy a tile into the tile data buffer and then render to the code field
|
||||
CopyTileATwoLyr
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
@ -170,6 +173,7 @@ CopyTileATwoLyr
|
||||
|
||||
CopyTileVTwoLyr
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
@ -348,22 +352,14 @@ mixed cmp #$FFFF ; All 1's in the mask is fully transparent
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda #$29
|
||||
sta: $0002,x ; AND #$0000 opcode
|
||||
lda #$09
|
||||
sta: $0005,x ; ORA #$0000 opcode
|
||||
|
||||
lda _OP_CACHE ; Get the LDA (dp),y instruction for this column
|
||||
sta: $0000,x
|
||||
|
||||
lda {]1}+32 ; insert the tile mask and data into the exception
|
||||
sta: $0003,x ; handler.
|
||||
lda {]1}+32 ; insert the tile mask and data into the exception
|
||||
sta: $0003,x ; handler.
|
||||
lda {]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,x
|
||||
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the second background layer
|
||||
|
Loading…
x
Reference in New Issue
Block a user