Add per-scanline offset rendering.

This commit is contained in:
Lucas Scharenbroich 2023-03-09 15:29:58 -06:00
parent 899c6c9770
commit e3409f92fa
9 changed files with 319 additions and 373 deletions

View File

@ -104,6 +104,8 @@ extern pascal void GTEClearBG1Buffer(Word value) inline(0x29A0, tool_dispatcher)
/* GTE Misc. Functions */ /* GTE Misc. Functions */
extern pascal Word GTEReadControl(void) inline(0x09A0, tool_dispatcher); extern pascal Word GTEReadControl(void) inline(0x09A0, tool_dispatcher);
extern pascal Word GTEGetSeconds(void) inline(0x14A0, tool_dispatcher); extern pascal Word GTEGetSeconds(void) inline(0x14A0, tool_dispatcher);
extern pascal Pointer GTEGetAddress(Word tableId) inline(0x2CA0, tool_dispatcher);
extern pascal void GTESetAddress(Word tableId, Pointer pointer) inline(0x2EA0, tool_dispatcher);
/* GTE Timer Functions */ /* GTE Timer Functions */

View File

@ -35,6 +35,7 @@ MaxGlobalX equ 16
MaxGlobalY equ 18 MaxGlobalY equ 18
MaxBG0X equ 20 MaxBG0X equ 20
MaxBG0Y equ 22 MaxBG0Y equ 22
frameCount equ 24
OldOneSecondCounter equ 26 OldOneSecondCounter equ 26
appTmp0 equ 28 appTmp0 equ 28
@ -74,6 +75,10 @@ appTmp0 equ 28
jsr BG0SetUp jsr BG0SetUp
jsr SetLimits jsr SetLimits
pea #80
pei MaxBG0Y
_GTESetBG0Origin
lda #193 ; Tile ID of '0' lda #193 ; Tile ID of '0'
jsr InitOverlay ; Initialize the status bar jsr InitOverlay ; Initialize the status bar
pha pha
@ -82,6 +87,18 @@ appTmp0 equ 28
sta OldOneSecondCounter sta OldOneSecondCounter
jsr UdtOverlay jsr UdtOverlay
; Set up the per-scanline rendering
lda #0
jsr InitOffsets
pea #scanlineHorzOffset
pea #^BG0Offsets
pea #BG0Offsets
_GTESetAddress
pea $0000 ; one regular render to fill the screen with the tilemap
_GTERender
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then ; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
; leave it alone. We are just testing the ability to merge sprite plane data into ; leave it alone. We are just testing the ability to merge sprite plane data into
; the play field tiles. ; the play field tiles.
@ -102,9 +119,11 @@ EvtLoop
bcc *+5 bcc *+5
brl :do_render brl :do_render
inc StartX inc StartX
pei StartX lda StartX
pei StartY jsr SetOffsets
_GTESetBG0Origin ; pei StartX
; pei StartY
; _GTESetBG0Origin
brl :do_render brl :do_render
:not_d :not_d
@ -114,9 +133,11 @@ EvtLoop
bne *+5 bne *+5
brl :do_render brl :do_render
dec StartX dec StartX
pei StartX lda StartX
pei StartY jsr SetOffsets
_GTESetBG0Origin ; pei StartX
; pei StartY
; _GTESetBG0Origin
brl :do_render brl :do_render
:not_a :not_a
@ -144,7 +165,7 @@ EvtLoop
:not_w :not_w
:do_render :do_render
pea $0000 pea #RENDER_PER_SCANLINE
_GTERender _GTERender
; Update the performance counters ; Update the performance counters
@ -234,7 +255,85 @@ SetLimits
rts rts
frameCount equ 24 SetOffsets
and #$00FF
brl _SetOffsets
InitOffsets
and #$00FF
sta appTmp0
ldx #0
ldy #80
jsr _InitRange
ldx #80
ldy #80
jsr _InitRange
ldx #160
ldy #48
jsr _InitRange
lda appTmp0
_SetOffsets
ldx #160
ldy #48
jsr _SetRange
lsr
ldx #80
ldy #80
jsr _SetRange
lsr
ldx #0
ldy #80
jsr _SetRange
rts
_SetRange
pha
txa
asl
tax
:loop2 lda BG0Offsets,x
and #$FF00
ora 1,s
sta BG0Offsets,x
dey
beq :done
inx
inx
cpx #416
bcc :loop2
:done
pla
rts
_InitRange
txa
asl
tax
tya
dec
and #$00FF
xba
:loop1 sta BG0Offsets,x
sec
sbc #$0100
dey
beq :done
inx
inx
cpx #416
bcc :loop1
:done
rts
BG0Offsets ds 416
PUT ../StartUp.s PUT ../StartUp.s
PUT ../../shell/Overlay.s PUT ../../shell/Overlay.s

View File

@ -132,6 +132,9 @@ _GTEGetAddress MAC
_GTECompileSpriteStamp MAC _GTECompileSpriteStamp MAC
UserTool $2D00+GTEToolNum UserTool $2D00+GTEToolNum
<<< <<<
_GTESetAddress MAC
UserTool $2E00+GTEToolNum
<<<
; EngineMode definitions ; EngineMode definitions
; Script definition ; Script definition

View File

@ -251,13 +251,13 @@ EngineReset
bne :loop bne :loop
; Set the scanline tables to reasonable default values ; Set the scanline tables to reasonable default values
ldx #{416*2}-2 ; ldx #{416*2}-2
lda #0 ; lda #0
:sxm_loop ;:sxm_loop
sta StartXMod164Arr,x ; sta StartXMod164Arr,x
dex ; dex
dex ; dex
bpl :sxm_loop ; bpl :sxm_loop
rts rts

View File

@ -102,7 +102,9 @@ RenderFlags equ 124 ; Flags passed to the Render() function
BG1Scaling equ 126 BG1Scaling equ 126
activeSpriteList equ 128 ; 32 bytes for the active sprite list (can persist across frames) activeSpriteList equ 128 ; 32 bytes for the active sprite list (can persist across frames)
; tiletmp equ 178 ; 16 bytes of temp storage for the tile renderers
; Free space from 160 to 192
blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter
tmp8 equ 224 ; another 16 bytes of temporary space to be used as scratch tmp8 equ 224 ; another 16 bytes of temporary space to be used as scratch
@ -282,8 +284,8 @@ VBuffHorzTableSelect EXT
BG1YCache EXT BG1YCache EXT
ScalingTables EXT ScalingTables EXT
StartXMod164Arr EXT ;StartXMod164Arr EXT
LastPatchOffsetArr EXT ;LastPatchOffsetArr EXT
_SortedHead EXT _SortedHead EXT
_ShadowListCount EXT _ShadowListCount EXT
@ -294,6 +296,7 @@ _DirectListTop EXT
_DirectListBottom EXT _DirectListBottom EXT
StartXMod164Tbl EXT StartXMod164Tbl EXT
LastOffsetTbl EXT
; Tool error codes ; Tool error codes
NO_TIMERS_AVAILABLE equ 10 NO_TIMERS_AVAILABLE equ 10

View File

@ -169,7 +169,17 @@ _RenderScanlines
; 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 _ScanlineBG0XPos ; Patch the code field instructions with exit BRA opcode jsr _ApplyScanlineBG0XPos ; Patch the code field instructions with exit BRA opcode
jsr _BuildShadowList ; Create the rages based on the sorted sprite y-values
jsr _ShadowOff ; Turn off shadowing and draw all the scanlines with sprites on them
jsr _DrawShadowList
jsr _DrawDirectSprites ; Draw the sprites directly to the Bank $01 graphics buffer (skipping the render-to-tile step)
jsr _ShadowOn ; Turn shadowing back on
; jsr _DrawComplementList ; Alternate drawing scanlines and PEI slam to expose the full fram
jsr _DrawFinalPass
; jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position ; jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
@ -209,11 +219,11 @@ _RenderScanlines
; jsr _BltRange ; jsr _BltRange
; bra :done ; bra :done
:no_ovrly ;:no_ovrly
ldx #0 ; Blit the full virtual buffer to the screen ; ldx #0 ; Blit the full virtual buffer to the screen
ldy ScreenHeight ; ldy ScreenHeight
jsr _BltRange ; jsr _BltRange
:done ;:done
; ldx #0 ; ldx #0
; ldy ScreenHeight ; ldy ScreenHeight

View File

@ -99,6 +99,7 @@ _CallTable
adrl _TSGetAddress-1 adrl _TSGetAddress-1
adrl _TSCompileSpriteStamp-1 adrl _TSCompileSpriteStamp-1
adrl _TSSetAddress-1
_CTEnd _CTEnd
_GTEAddSprite MAC _GTEAddSprite MAC
@ -302,6 +303,12 @@ _TSRender
bra :done bra :done
:no_shadowing :no_shadowing
bit #RENDER_PER_SCANLINE
beq :no_scanline
jsr _RenderScanlines
bra :done
:no_scanline
jsr _Render jsr _Render
:done :done
@ -865,27 +872,45 @@ _TSSetBG1Scale
sta BG1Scaling sta BG1Scaling
_TSExit #0;#2 _TSExit #0;#2
; Pointer GetAddress(tblId)
_TSGetAddress _TSGetAddress
:output equ FirstParam+0 :tblId equ FirstParam+0
:tblId equ FirstParam+4 :output equ FirstParam+2
_TSEntry _TSEntry
lda #0 lda #0
sta :output,s sta :output,s
sta :output+2,s sta :output+2,s
lda :value,s lda :tblId,s
cmp #scanlineHorzOffset cmp #scanlineHorzOffset
bne :out bne :out
lda #StartXMod164Arr lda StartXMod164Tbl
sta :output,s sta :output,s
lda #^StartXMod164Arr lda StartXMod164Tbl+2
sta :output+2,s sta :output+2,s
:out :out
_TSExit #0;#2 _TSExit #0;#2
; SetAddress(tblId, Pointer)
_TSSetAddress
:ptr equ FirstParam+0
:tblId equ FirstParam+4
_TSEntry
lda :tblId,s
cmp #scanlineHorzOffset
bne :out
lda :ptr,s
sta StartXMod164Tbl
lda :ptr+2,s
sta StartXMod164Tbl+2
:out
_TSExit #0;#6
; CompileSpriteStamp(spriteId, vbuffAddr) ; CompileSpriteStamp(spriteId, vbuffAddr)
_TSCompileSpriteStamp _TSCompileSpriteStamp
:vbuff equ FirstParam :vbuff equ FirstParam
@ -916,7 +941,7 @@ _TSCompileSpriteStamp
put Sprite2.s put Sprite2.s
put SpriteRender.s put SpriteRender.s
put Render.s put Render.s
put blitter/Scanline.s ; put blitter/Scanline.s
put render/Render.s put render/Render.s
put render/Fast.s put render/Fast.s
put render/Slow.s put render/Slow.s

View File

@ -50,11 +50,7 @@ _RestoreBG0Opcodes
:virt_line_x2 equ tmp1 :virt_line_x2 equ tmp1
:lines_left_x2 equ tmp2 :lines_left_x2 equ tmp2
:draw_count_x2 equ tmp3
:exit_offset equ tmp4 :exit_offset equ tmp4
:stk_save equ tmp5
phb ; Save data bank
asl asl
sta :virt_line_x2 ; Keep track of it sta :virt_line_x2 ; Keep track of it
@ -66,6 +62,14 @@ _RestoreBG0Opcodes
lda LastPatchOffset ; If zero, there are no saved opcodes lda LastPatchOffset ; If zero, there are no saved opcodes
sta :exit_offset sta :exit_offset
_RestoreBG0OpcodesAlt
:virt_line_x2 equ tmp1
:lines_left_x2 equ tmp2
:draw_count_x2 equ tmp3
:exit_offset equ tmp4
:stk_save equ tmp5
phb ; Save data bank
tsc tsc
sta :stk_save sta :stk_save
@ -144,18 +148,8 @@ _ApplyBG0XPosPre
rts rts
_ApplyBG0XPos _ApplyBG0XPos
:stk_save equ tmp0
:virt_line_x2 equ tmp1 :virt_line_x2 equ tmp1
:lines_left_x2 equ tmp2 :lines_left_x2 equ tmp2
:draw_count_x2 equ tmp3
:exit_offset equ tmp4
:entry_offset equ tmp5
:exit_bra equ tmp6
:exit_address equ tmp7
:base_address equ tmp8
:opcode equ tmp9
:odd_entry_offset equ tmp10
; If there are saved opcodes that have not been restored, do not run this routine ; If there are saved opcodes that have not been restored, do not run this routine
lda LastPatchOffset lda LastPatchOffset
@ -232,6 +226,21 @@ _ApplyBG0XPos
; +-----------+ ; +-----------+
lda StartXMod164 lda StartXMod164
; Alternate entry point if the virt_line_x2 and lines_left_x2 and XMod164 values are passed in externally
_ApplyBG0XPosAlt
:stk_save equ tmp0
:virt_line_x2 equ tmp1
:lines_left_x2 equ tmp2
:draw_count_x2 equ tmp3
:exit_offset equ tmp4
:entry_offset equ tmp5
:exit_bra equ tmp6
:exit_address equ tmp7
:base_address equ tmp8
:opcode equ tmp9
:odd_entry_offset equ tmp10
bit #$0001 bit #$0001
jne :odd_case ; Specialized routines for even/odd cases jne :odd_case ; Specialized routines for even/odd cases
@ -368,7 +377,7 @@ _ApplyBG0XPos
sbc #164 sbc #164
tax tax
lda Col2CodeOffset-1,x lda Col2CodeOffset-1,x ; Odd offset to get the value in the high byte
and #$FF00 and #$FF00
ora #$00AF ora #$00AF
sta :opcode sta :opcode
@ -445,361 +454,148 @@ _ApplyBG0XPos
plb plb
rts rts
_RestoreScanlineBG0Opcodes
:virt_line_x2 equ tmp1
:lines_left_x2 equ tmp2
:exit_offset equ tmp4
; Avoid local var collisions
:virt_line_pos_x2 equ tmp11
:total_left_x2 equ tmp12
:current_count_x2 equ tmp13
:ptr equ tmp14
asl
sta :virt_line_pos_x2
tay
txa
asl
sta :total_left_x2
lda StartXMod164Tbl
sta :ptr
lda StartXMod164Tbl+2
sta :ptr+2
; Patch our the ranges from the StartXMod164Tbl array starting at the first virtual line
:loop
lda [:ptr],y
and #$FF00 ; Determine how many sequential lines to restore
xba
inc
asl
min :total_left_x2 ; Don't draw more than the number of lines that are left to process
sta :current_count_x2 ; Save a copy for later
sta :lines_left_x2 ; Set the parameter
sty :virt_line_x2 ; Set the parameter
lda LastOffsetTbl,y
sta :exit_offset
jsr _RestoreBG0OpcodesAlt
clc
lda :virt_line_pos_x2
adc :current_count_x2
cmp #208*2 ; Do the modulo check in this loop
bcc *+5
sbc #208*2
sta :virt_line_pos_x2
tay
lda :total_left_x2
sec
sbc :current_count_x2
sta :total_left_x2
bne :loop
rts
; This is a variant of the above routine that allows each x-position to be set independently from a table of value. This is ; This is a variant of the above routine that allows each x-position to be set independently from a table of value. This is
; quite a bit slower than the other routine since we cannot store constant values for each line. ; quite a bit slower than the other routine since we cannot store constant values for each line.
; ;
; We still want to perform operation in blocks of 16 to avoid repeatedly setting the data bank register for each line. In ; This routine operates at a higher level and does not try to be super optimized for the case where every line has a different
; order to accomplish this, the even/odd cases are split into separate code blocks and the unrolled loop will patch up ; set of parameters. Instead, we optimize for the case where there are a few large ranges of the screen moving at different
; all of the memory locations on each line, rather than doing each patch one at a time. This may actually be more efficient ; rates, e.g. a fixed status bar area on top, a slow-scrolling area in the middle and a fast are in the foreground.
; since it eliminates several jmp (abs,x) / tax instructions and removed some register reloading.
; ;
; The two unrolled loop elements are: ; The table that drives this is dense and has the following format for each word
; ;
; Even: ; Bits 0 - 7: X mod 164 value
; lda: $0000,x ; Load from X = BTableLow + exit_offset ; Bits 8 - 15: Number of scanline to persist this mod value
; sta: OPCODE_SAVE,y ; Save the two byte in another area of the line code
; lda :exit_bra[n]
; sta $0000,x ; Replace the two bytes with a BRA instruction to exit the blitter
; lda :opcode[n]
; sta: CODE_ENTRY_OPCODE,y ; CODE_ENTRY_OPCODE and CODE_ENTRY are adjacent -- could make this a single 16-bit store
; ;
; Odd: ; So, if the first 10 entries has a mod value of 5, they would look like: $0905, $0805, $0705, ... $0105, $0005
; Same as above, plus... ;
; lda :odd_entry_offset[n] ; [8-bit] Get back into the code after fixing up the odd edge ; This allows the code to start an an arbitrary location and immeditely sync up with the modulo list. It also allows
; sta: ODD_ENTRY,y ; the code to easily skip ranges of constant values using the existing _ApplyBG0XPos function as a subroutine.
; lda: $0001,x ; Save the high word in case the last instruction is PEA and we need to load the top byte _ApplyScanlineBG0XPos
; sta: OPCODE_HIGH_SAVE,y
; ; Copies of the local variables in _ApplyBG0XPos
_ApplyBG0XPosPerScanline
:stk_save equ tmp0
:virt_line_x2 equ tmp1 :virt_line_x2 equ tmp1
:lines_left_x2 equ tmp2 :lines_left_x2 equ tmp2
:draw_count_x2 equ tmp3
:exit_offset equ tmp4 :exit_offset equ tmp4
:entry_offset equ tmp5
:exit_bra equ tmp6
:exit_address equ tmp7
:base_address equ tmp8
:opcode equ tmp9
:odd_entry_offset equ tmp10
; If there are saved opcodes that have not been restored, do not run this routine ; Avoid local var collision with _ApplyBG0XPos
lda LastPatchOffset :virt_line_pos_x2 equ tmp11
beq :ok :total_left_x2 equ tmp12
:current_count_x2 equ tmp13
:ptr equ tmp14
lda StartXMod164Tbl
sta :ptr
lda StartXMod164Tbl+2
sta :ptr+2
ora :ptr
bne *+3 ; null pointer check
rts rts
; In this routine, basically every horizontal parameter is based off of the :virt_line_x2 index
:ok
lda StartYMod208 ; This is the base line of the virtual screen lda StartYMod208 ; This is the base line of the virtual screen
asl asl
sta :virt_line_x2 ; Keep track of it sta :virt_line_pos_x2
tay
lda ScreenHeight lda ScreenHeight
asl asl
sta :lines_left_x2 sta :total_left_x2
; Sketch out the core structural elements of the loop + bank management
phb ; Save the existing bank
tsc
sta :stk_save
; Patch our the ranges from the StartXMod164Tbl array starting at the first virtual line
:loop :loop
ldx :virt_line_x2 lda [:ptr],y
txa
and #$001E
eor #$FFFF
sec
adc #2*16 ; 2 * (16 - virt_line % 16). This get us aligned to 16-line boundaries
min :lines_left_x2 ; Make sure we handle cases where lines_left < aligned remainder
sta :draw_count_x2 ; We are drawing this many lines on this iteration starting at _virt_line_x2
ldal BTableHigh,x ; Set the bank
pha
plb
jsr :DoScanlineRange ; Patch in the code field for this range (Bank is set)
lda :draw_count_x2
clc ; advance to the virtual line after the segment we just
adc :virt_line_x2 ; filled in
sta :virt_line_x2
lda :lines_left_x2 ; subtract the number of lines we just completed
sec
sbc :draw_count_x2
sta :lines_left_x2
jne :loop
lda :stk_save
tcs
plb
rts
; Run through and build an array of scanline data and place it in temporary zero page space. Need a total of 48 bytes.
:BuildScanlineData
; First step, run though and create the tables for the copy routine
lda StartXMod164Tbl,x
bit #$0001
; bne :bsd_odd
tay
lda CodeFieldEvenBRA-2,y ; The exit point comes after the left edge (reverse order due to stack)
sta :exit_bra,x
lda Col2CodeOffset-2,y
sta :exit_offset,x
:DoScanlineRange
ldx :virt_line_x2
; First, calculate the exit point
ldal StartXMod164Tbl,x ; Get the origin for this line
bit #$0001
bne :is_odd ; Quickly switch to specialized even/odd routines
; For even offsets, the index is x - 2
; For odd offsets, the index is x - 1
;
; So, for both we can do (x - 1) & $FFFE = dec / and #$FFFE = lsr / asl + clears the carry
; This is an even-aligned line
; dec ; Move to the previous address for entry (a - 1) % 164
; dec ; Optimization: Coule eliminate this with a double-width tbale for CodeFieldEvenBRA
; bpl *+5
; lda #162
tay
lda CodeFieldEvenBRA-2,y
sta :exit_bra ; Store are exit_offset +
lda Col2CodeOffset-2,y
sta :exit_offset
; tya
; adc ScreenWidth
; cmp #164 ; Keep the value in range
; bcc *+5
; sbc #164
; tay
lda Col2CodeOffset-2-1,y ; -2 for even case , -1 to load value into high byte
and #$FF00
; sta :entry_offset
ora #$004C ; set the entry_jmp opcode to JMP
sta :opcode
; stz :odd_entry_offset ; mark as an even case
ldal BTableLow,x ; Get the address of the code field line
tay ; Save it to use as the base address
clc
adc :exit_offset ; Add some offsets to get the base address in the code field line
tax tax
clc and #$FF00 ; Determine how many sequential lines have this mod value
; This is the core even patch loop. The y-register tracks the base address of the starting line. Set the x-register xba
; based on the per-line exit_offset and eveything else references other data inc
asl
min :total_left_x2 ; Don't draw more than the number of lines that are left to process
sta :current_count_x2 ; Save a copy for later
; tya sta :lines_left_x2 ; Set the parameter
; adc :exit_offset+{]line*2} sty :virt_line_x2 ; Set the parameter
; tax txa ; Put the X mod 164 value in the accumulator
; lda: {]line*$1000},x and #$00FF
; sta: OPCODE_SAVE+{]line*$1000},y jsr _ApplyBG0XPosAlt
; lda :exit_bra+{]line*2} ; Copy this value into all of the lines
; sta: {]line*$1000},x
; lda :entry_offset+{]line*2} ; Pre-merged with the appropriate opcode + offset
; sta: CODE_ENTRY_OPCODE+{]line*$1000},y
bra :prep_complete lda :exit_offset ; Get the direct address in the code field that was overwritten
ldy :virt_line_pos_x2
; This is an odd-aligned line sta LastOffsetTbl,y ; Stash it for use by the per-scanline resotre function
:is_odd
dec ; Remove the least-significant byte (must stay positive)
tay
lda CodeFieldOddBRA,y
sta :exit_bra
lda Col2CodeOffset,y
sta :exit_offset
tya tya
adc ScreenWidth
cmp #164 ; Keep the value in range
bcc *+5
sbc #164
tay
lda Col2CodeOffset,y
sta :entry_offset ; Will be used to load the data
lda Col2CodeOffset-2,y
sta :odd_entry_offset ; will be the actual location to jump to
lda #$00AF ; set the entry_jmp opcode to LDAL
sta :opcode
:prep_complete
ldal BTableLow,x ; Get the address of the code field line
tay ; Save it to use as the base address
clc clc
adc :exit_offset ; Add some offsets to get the base address in the code field line adc :current_count_x2
cmp #208*2 ; Do the modulo check in this loop
bcc *+5
sbc #208*2
sta :virt_line_pos_x2
tay
; sta :exit_address lda :total_left_x2
; sty :base_address
; ldy :base_address
; ldx :exit_address ; Save from this location (not needed in fast mode)
; SaveOpcode ; X = :exit_address on return
tax
lda: $0000,x
sta: OPCODE_SAVE+$0000,y
; txy ; ldy :exit_address -- starting at this address
; ldx :draw_count_x2 ; Do this many lines
lda :exit_bra ; Copy this value into all of the lines
; SetConst ; All registers are preserved
sta: $0000,x
; Next, patch in the CODE_ENTRY value, which is the low byte of a JMP instruction. This is an
; 8-bit operation and, since the PEA code is bank aligned, we use the entry_offset value directly
sep #$20
lda :entry_offset
; ldy :base_address
; SetCodeEntry ; All registers are preserved
sta: CODE_ENTRY+$0000,y
; Now, patch in the opcode
lda :opcode
; SetCodeEntryOpcode ; All registers are preserved
sta: CODE_ENTRY_OPCODE+$0000,y
; If this is an odd entry, also set the odd_entry low byte and save the operand high byte
lda :odd_entry_offset
jeq :not_odd
; SetOddCodeEntry ; All registers are preserved
sta: ODD_ENTRY+$0000,y
; SaveHighOperand :exit_address ; Only used once, so "inline" it
ldx :exit_address
lda: $0002,x
sta: OPCODE_HIGH_SAVE+$0000,y
:not_odd
rep #$21 ; clear the carry
lda :virt_line_x2 ; advance to the virtual line after
adc :draw_count_x2 ; filled in
sta :virt_line_x2
lda :lines_left_x2 ; subtract the number of lines we just completed
sec sec
sbc :draw_count_x2 sbc :current_count_x2
sta :lines_left_x2 sta :total_left_x2
bne :loop
jne :loop
rts rts
; DoEvenRange
;
; Does all the core operations for an even range (16-bit accumulator and registers)
;
; X = number of lines * 2, 0 to 32
; Y = starting line * $1000
; A = code field location * $1000
DoEvenRange mac
asl ; mult the offset by 2 and clear the carry at the same time
adc #dispTbl
stal patch+1
patch jmp $0000
dispTbl jmp bottom
db 1
jmp x01
db 1
jmp x02
db 1
jmp x03
db 1
jmp x04
db 1
jmp x05
db 1
jmp x06
db 1
jmp x07
db 1
jmp x08
db 1
jmp x09
db 1
jmp x10
db 1
jmp x11
db 1
jmp x12
db 1
jmp x13
db 1
jmp x14
db 1
jmp x15
db 1
x16 tya
adc :exit_offset+$1E
tax
lda: $F000,x
sta: OPCODE_SAVE+$F000,y
lda :exit_bra+$1E
sta: $F000,x
lda :entry_offset+$1E ; Pre-merged with the appropriate opcode + offset
sta: CODE_ENTRY_OPCODE+$F000,y
x15 tya
adc :exit_offset+$1E
tax
lda: $E000,x
sta: OPCODE_SAVE+$E000,y
lda :exit_bra+$1C
sta: $E000,x
lda :entry_offset+$1C
sta: CODE_ENTRY_OPCODE+$E000,y
x14 lda $D002,x
sta OPCODE_HIGH_SAVE+$D000,y
x13 lda $C002,x
sta OPCODE_HIGH_SAVE+$C000,y
x12 lda $B002,x
sta OPCODE_HIGH_SAVE+$B000,y
x11 lda $A002,x
sta OPCODE_HIGH_SAVE+$A000,y
x10 lda $9002,x
sta OPCODE_HIGH_SAVE+$9000,y
x09 lda $8002,x
sta OPCODE_HIGH_SAVE+$8000,y
x08 lda $7002,x
sta OPCODE_HIGH_SAVE+$7000,y
x07 lda $6002,x
sta OPCODE_HIGH_SAVE+$6000,y
x06 lda $5002,x
sta OPCODE_HIGH_SAVE+$5000,y
x05 lda $4002,x
sta OPCODE_HIGH_SAVE+$4000,y
x04 lda $3002,x
sta OPCODE_HIGH_SAVE+$3000,y
x03 lda $2002,x
sta OPCODE_HIGH_SAVE+$2000,y
x02 lda $1002,x
sta OPCODE_HIGH_SAVE+$1000,y
x01 lda: $0002,x
sta: OPCODE_HIGH_SAVE+$0000,y
bottom <<<
; SaveHighOperand ; SaveHighOperand
; ;
; Save the high byte of the 3-byte code field instruction into the odd handler at the end ; Save the high byte of the 3-byte code field instruction into the odd handler at the end

View File

@ -108,6 +108,10 @@ TileStoreLookup ENT
Col2CodeOffset ENT Col2CodeOffset ENT
lup 82 lup 82
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE} dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
]step equ ]step+1
--^
lup 82 ; Make is a double-length table so we can add the ScreenWidth without testing for wrap-around
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
]step equ ]step+1 ]step equ ]step+1
--^ --^
dw CODE_TOP+{81*PER_TILE_SIZE} dw CODE_TOP+{81*PER_TILE_SIZE}
@ -386,6 +390,10 @@ BG1YOffsetTable ENT
; Per-scanline offsets for BG0 ; Per-scanline offsets for BG0
StartXMod164Tbl ENT StartXMod164Tbl ENT
dw 0,0
LastOffsetTbl ENT
ds 416
; Other Toolset variables ; Other Toolset variables
OneSecondCounter ENT OneSecondCounter ENT
@ -566,7 +574,7 @@ Scale15 dw $003C,$003C,$003C,$003E,$003E,$003E,$003E,$0040,$0040,$0040,$0040,$
blt_return blt_return
stk_save stk_save
StartXMod164Arr ENT ;StartXMod164Arr ENT
ds 416*2 ; ds 416*2
LastPatchOffsetArr ENT ;LastPatchOffsetArr ENT
ds 416*2 ; ds 416*2