More parts of the render pipeline in place

This commit is contained in:
Lucas Scharenbroich 2021-07-09 14:18:49 -05:00
parent 7ee1ddb604
commit 5d713caf5c
9 changed files with 934 additions and 314 deletions

View File

@ -48,6 +48,57 @@ _R1W1 mac ; Read Bank 0 / Write Bank 1
stal STATE_REG
<<<
_PushReg mac ; Used to save/restore registers when calling subroutines.
pha
phx
phy
<<<
_PullReg mac
ply
plx
pla
<<<
_PushReg2 mac ; Variation to also save the P-register to preserve m/x
pha
phx
phy
php
<<<
_PullReg2 mac
plp
ply
plx
pla
<<<
jne mac
beq *+5
jmp ]1
<<<
jeq mac
bne *+5
jmp ]1
<<<
jcc mac
bcs *+5
jmp ]1
<<<
jcs mac
bcc *+5
jmp ]1
<<<
min mac
cmp ]1
bcc mout
lda ]1
mout <<<
****************************************
* Basic Error Macro *
****************************************
@ -70,3 +121,11 @@ NoErr eom

View File

@ -33,6 +33,7 @@ KBD_REG equ $E0C000
KBD_STROBE_REG equ $E0C010
VBL_STATE_REG equ $E0C019
SHADOW_SCREEN equ $012000
SHR_SCREEN equ $E12000
SHR_SCB equ $E19D00
@ -292,7 +293,13 @@ DoFrame
; Set the Y-Position within the virtual buffer
lda #0 ; Set the virtual Y-position
jsr SetYPos
jsr SetBG0YPos
lda #0 ; Set the virtual X-position
jsr SetBG0XPos
jsr Render ; Render the play field
rts
; Just load the screen width here. This is not semantically right; we actually are taking the nummber
; of tiles in the width of the playfield, multiplying by two to get the number of words and then
@ -333,11 +340,8 @@ DoFrame
jsr SetConst
rep #$30
ldy #$7000 ; Set the return after line 200 (Bank 13, line 8)
jsr SetReturn
; jsr BltDispatch ; Execute the blit
; ldy #$7000 ; Set the return after line 200 (Bank 13, line 8)
; jsr SetReturn
plb ; set the bank back to the code field
ldx ScreenWidth ; This is the word to exit from
@ -640,7 +644,9 @@ qtRec adrl $0000
put App.Init.s
put App.Msg.s
put font.s
put Render.s
put blitter/Blitter.s
put blitter/Horz.s
put blitter/PEISlammer.s
put blitter/Tables.s
put blitter/Template.s
@ -677,6 +683,14 @@ qtRec adrl $0000

View File

@ -46,12 +46,14 @@
; edges of the rendered play field.
; The render function is the point of committment -- most of the APIs that set sprintes and
; update coordinates are lazy; they simply save the value and set a dirty flag in the
; DirtyBits word.
;
; This function examines the dirty bits and actually performs the work to update the code field
; and internal data structure to properly render the play field. Then the update pipeline is
; executed.
Render
jsr ShadowOff
jsr ShadowOn
rts

View File

@ -9,6 +9,7 @@
; 19 will draw the first 20 lines on the play field, regardless of where the playfield is physically
; on the SHR screen or the current value of StartY
exit_ptr equ tmp0
jmp_low_save equ tmp2
BltRange
clc`
@ -35,27 +36,24 @@ BltRange
; The way we patch the exit code is subtle, but very fast. The CODE_EXIT offset points to
; an JMP/JML instruction that transitions to the next line after all of the code has been
; executed. Since every code field line is bank-aligned, we know that the low-byte of the
; operand is always $00.
; executed.
;
; The trick we use is to patch the low byte to force the code to jump to a special return
; function (jml blt_return) in the *next* code field line. When it's time to restore the
; code, we can unconditionally store a $00 value to set things back to normal.
;
; This is the ideal situation -- patch/restore in a single 8-bit lda #imm / sta instruction
; pair with no need to preserve the data
; function (jml blt_return) in the *next* code field line.
ldy #CODE_EXIT+1 ; this is a JMP or JML instruction that points to the next line.
lda [exit_ptr],y
sta jmp_low_save
lda #FULL_RETURN ; this is the offset of the return code
sta [exit_ptr],y ; patch out the low byte of the JMP/JML
rep #$20
; Now we need to set up the Bank, Stack Pointer and Direct Page registers for calling into
; the code field
pei BG1DataBank-1 ; Set the data bank for BG1 data
plb
lda BG1DataBank ; Set the data bank for BG1 data
pha
plb
rep #$20
phd ; Save the application direct page
lda BlitterDP ; Set the direct page to the blitter data
@ -66,7 +64,7 @@ BltRange
tsc ; save the stack pointer
stal stk_save+1
blt_entry jml $000000 ; Jump into the blitter code $XX/YYZZ
blt_entry jml $000000 ; Jump into the blitter code $XX/YY00
blt_return _R0W0
stk_save lda #0000 ; load the stack
@ -76,49 +74,10 @@ stk_save lda #0000 ; load the stack
sep #$20
ldy #CODE_EXIT+1
lda #00
lda jmp_low_save
sta [exit_ptr],y
rep #$20
rts
; This subroutine is used to set up the BltDispatch code based on the current state of
; the machine and/or the state of the engine. The tasks it performs are
;
; 1. Set the blt_entry low byte based on the graphics engine configuration
BltSetup
sep #$20 ; Only need 8-bits for this
lda EngineMode
bit #$01 ; Are both background layers enabled?
beq :oneLyr
lda #entry_2-base
bra :twoLyr
:oneLyr lda #entry_3-base
:twoLyr sta blt_entry+1 ; set the low byte of the JML
rep #$20
rts

View File

@ -8,15 +8,23 @@ ScreenX1 equ 10
ScreenTileHeight equ 12 ; Height of the playfield in 8x8 blocks
ScreenTileWidth equ 14 ; Width of the playfield in 8x8 blocks
StartY equ 16 ; Which code buffer line displays first on screen. Range = 0 to 207
EngineMode equ 18 ; Defined the mode/capabilities that are enabled
StartX equ 16 ; Which code buffer byte is the left edge of the screen. Range = 0 to 167
StartY equ 18 ; Which code buffer line is the top of the screen. Range = 0 to 207
EngineMode equ 20 ; Defined the mode/capabilities that are enabled
; bit 0: 0 = Single Background, 1 = Parallax
DirtyBits equ 20 ; Identify values that have changed between frames
DirtyBits equ 22 ; Identify values that have changed between frames
BG1DataBank equ 22 ; Data bank that holds BG1 layer data
BlitterDP equ 23 ; Direct page address the holder blitter data
BG1DataBank equ 24 ; Data bank that holds BG1 layer data
BlitterDP equ 25 ; Direct page address the holder blitter data
bstk equ 224 ; 16-byte stack to push bank addresses
OldStartX equ 26
OldStartY equ 28
bstk equ 208 ; 16-byte stack to push bank addresses
tmp8 equ 224
tmp9 equ 226
tmp10 equ 228
tmp0 equ 240 ; 16 bytes of temporary space to be used as scratch
tmp1 equ 242
@ -35,3 +43,8 @@ DIRTY_BIT_BG0_Y equ $0002

339
src/blitter/Horz.s Normal file
View File

@ -0,0 +1,339 @@
; Subroutines that deal with the horizontal scrolling. The primary function of
; these routines are to adjust tables and patch in new values into the code field
; when the virtual X-position of the play field changes.
; SetBG0XPos
;
; Set the virtual horizontal position of the primary background layer. In addition to
; updating the direct page state locations, this routine needs to preserve the original
; value as well. This is a bit subtle, because if this routine is called multiple times
; with different values, we need to make sure the *original* value is preserved and not
; continuously overwrite it.
;
; We assume that there is a clean code field in this routine
SetBG0XPos
cmp StartX
beq :out ; Easy, if nothing changed, then nothing changes
ldx StartX ; Load the old value (but don't save it yet)
sta StartX ; Save the new position
lda #DIRTY_BIT_BG0_X
tsb DirtyBits ; Check if the value is already dirty, if so exit
bne :out ; without overwriting the original value
stx OldStartX ; First change, so preserve the value
:out rts
; Based on the current value of StartX in the direct page, patch up the code fields
; to render the correct data. Note that we do *not* do the OpcodeRestore in this
; routine. The reason is that the restore *must* be applied using the (StartX, StartY)
; values from the previous frame, which requires logic that is not relevant to setting
; up the code field.
_ApplyBG0XPos
:virt_line equ tmp1
:lines_left equ tmp2
:draw_count equ tmp3
:exit_offset equ tmp4
:entry_offset equ tmp5
:exit_bra equ tmp6
:exit_address equ tmp7
:base_address equ tmp8
:draw_count_x2 equ tmp9
; This code is fairly succinct. See the corresponding code in Vert.s for more detailed comments.
lda StartY ; This is the base line of the virtual screen
sta :virt_line ; Keep track of it
lda ScreenHeight
sta :lines_left
; Calculate the exit and entry offsets into the code fields. This is a bit tricky, because odd-aligned
; rendering causes the left and right edges to move in a staggered fashion.
;
; ... +----+----+----+----+----+- ... -+----+----+----+----+----+
; | 04 | 06 | 08 | 0A | 0C | | 44 | 46 | 48 | 4A |
; ... +----+----+----+----+----+- ... -+----+----+----+----+----+
; | |
; +---- screen width --------------+
; entry | | exit
;
; Here is an example of a screen 64 bytes wide. When everything is aligned to an even offset
; then the entry point is column $08 and the exit point is column $48
;
; If we move the screen forward one byte (which means the pointers move backwards) then the low-byte
; of column $06 will be on the right edge of the screen and the high-byte of column $46 will left-edge
; of the screen. Since the one-byte edges are handled specially, the exit point shifts one column, but
; the entry point does not.
;
; ... +----+----+----+----+----+- ... -+----+----+----+----+----+
; | 04 | 06 | 08 | 0A | 0C | | 44 | 46 | 48 | 4A |
; ... +----+----+----+----+----+- ... -+----+----+----+----+----+
; | | | |
; +--|------ screen width -------|--+
; entry | | exit
;
; When the screen is moved one more byte forward, then the entry point will move to the
; next column.
;
; ... +----+----+----+----+----+- ... -+----+----+----+----+----+
; | 04 | 06 | 08 | 0A | 0C | | 44 | 46 | 48 | 4A |
; ... +----+----+----+----+----+- ... -+----+----+----+----+----+
; | |
; +------ screen width ------------+
; entry | | exit
;
; So, in short, the entry tile position is rounded up from the x-position and the exit
; tile position is rounded down.
lda StartX ; This is the starting byte offset (0 - 163)
inc ; round up to calculate the entry column
and #$FFFE
tax
lda Col2CodeOffset,X ; This is an offset from the base page boundary
sta :entry_offset
lda StartX ; Repeat with adding the screen width
clc ; to calculate the exit column
adc ScreenWidth
bit #$0001 ; Check if odd or even
bne :isOdd
and #$FFFE
tax
lda CodeFieldEvenBRA,x
sta :exit_bra
bra :wasEven
:isOdd
and #$FFFE
tax
lda CodeFieldOddBRA,x
sta :exit_bra
:wasEven
lda Col2CodeOffset,X
sta :exit_offset
; Main loop that
;
; 1. Saves the opcodes in the code field
; 2. Writes the BRA instruction to exit the code field
; 3. Writes the JMP entry point to enter the code field
:loop
lda :virt_line
asl ; This will clear the carry bit
tax
ldal BTableLow,x ; Get the address of the first code field line
tay ; Save it to use as the base address
adc :exit_offset ; Add some offsets to get the base address in the code field line
sta :exit_address
sty :base_address
sep #$20
ldal BTableHigh,x
pha
plb ; This is the bank that will receive the updates
rep #$20
lda :virt_line
and #$000F
eor #$FFFF
inc
clc
adc #16
min :lines_left
sta :draw_count ; Do this many lines
asl
sta :draw_count_x2
; First step is to set the BRA instruction to exit the code field at the proper location. There
; are two sub-steps to do here; we need to save the 16-bit value that exists at the location and
; then overwrite it with the branch instruction.
;
; Special note, the SaveOpcode function stores the opcode *within* the code field as it is
; used in odd-aligned cases to determine how to draw the 8-bit value on the left edge of the
; screen
; y is already set to :base_address
tax ; :draw_count_x2
lda :exit_address ; Save from this location
jsr SaveOpcode
ldx :draw_count_x2 ; Do this many lines
lda :exit_bra ; Copy this value into all of the lines
ldy :exit_address ; starting at this address
jsr SetConst
; 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
ldx :draw_count_x2
lda :entry_offset
ldy :base_address
jsr SetCodeEntry
rep #$20
; Do the end of the loop -- update the virtual line counter and reduce the number
; of lines left to render
lda :virt_line ; advance to the virtual line after the segment we just
clc ; filled in
adc :draw_count
sta :virt_line
lda :lines_left ; subtract the number of lines we just completed
sec
sbc :draw_count
sta :lines_left
jne :loop
phk
plb
rts
; SaveOpcode
;
; Save the values to the restore location. This should only be used to patch the
; code field since the save location is fixed.
;
; X = number of lines * 2, 0 to 32
; Y = starting line * $1000
; A = code field location * $1000
SaveOpcode
jmp (:tbl,x)
:tbl da :bottom
da :do01,:do02,:do03,:do04
da :do05,:do06,:do07,:do08
da :do09,:do10,:do11,:do12
da :do13,:do14,:do15,:do16
:do15 tax
bra :x15
:do14 tax
bra :x14
:do13 tax
bra :x13
:do12 tax
bra :x12
:do11 tax
bra :x11
:do10 tax
bra :x10
:do09 tax
bra :x09
:do08 tax
bra :x08
:do07 tax
bra :x07
:do06 tax
bra :x06
:do05 tax
bra :x05
:do04 tax
bra :x04
:do03 tax
bra :x03
:do02 tax
bra :x02
:do01 tax
bra :x01
:do16 tax
:x16 lda $F000,x
sta OPCODE_SAVE+$F000,y
:x15 lda $E000,x
sta OPCODE_SAVE+$E000,y
:x14 lda $D000,x
sta OPCODE_SAVE+$D000,y
:x13 lda $C000,x
sta OPCODE_SAVE+$C000,y
:x12 lda $B000,x
sta OPCODE_SAVE+$B000,y
:x11 lda $A000,x
sta OPCODE_SAVE+$A000,y
:x10 lda $9000,x
sta OPCODE_SAVE+$9000,y
:x09 lda $8000,x
sta OPCODE_SAVE+$8000,y
:x08 lda $7000,x
sta OPCODE_SAVE+$7000,y
:x07 lda $6000,x
sta OPCODE_SAVE+$6000,y
:x06 lda $5000,x
sta OPCODE_SAVE+$5000,y
:x05 lda $4000,x
sta OPCODE_SAVE+$4000,y
:x04 lda $3000,x
sta OPCODE_SAVE+$3000,y
:x03 lda $2000,x
sta OPCODE_SAVE+$2000,y
:x02 lda $1000,x
sta OPCODE_SAVE+$1000,y
:x01 lda: $0000,x
sta: OPCODE_SAVE+$0000,y
:bottom rts
; SetCodeEntry
;
; Patch in the low byte at the CODE_ENTRY. Must be called with 8-bit accumulator
;
; X = number of lines * 2, 0 to 32
; Y = starting line * $1000
; A = address low byte
SetCodeEntry
jmp (:tbl,x)
:tbl da :bottom-00,:bottom-03,:bottom-06,:bottom-09
da :bottom-12,:bottom-15,:bottom-18,:bottom-21
da :bottom-24,:bottom-27,:bottom-30,:bottom-33
da :bottom-36,:bottom-39,:bottom-42,:bottom-45
da :bottom-48
:top sta CODE_ENTRY+$F000,y
sta CODE_ENTRY+$E000,y
sta CODE_ENTRY+$D000,y
sta CODE_ENTRY+$C000,y
sta CODE_ENTRY+$B000,y
sta CODE_ENTRY+$A000,y
sta CODE_ENTRY+$9000,y
sta CODE_ENTRY+$8000,y
sta CODE_ENTRY+$7000,y
sta CODE_ENTRY+$6000,y
sta CODE_ENTRY+$5000,y
sta CODE_ENTRY+$4000,y
sta CODE_ENTRY+$3000,y
sta CODE_ENTRY+$2000,y
sta CODE_ENTRY+$1000,y
sta: CODE_ENTRY+$0000,y
:bottom rts

View File

@ -14,7 +14,7 @@
; ldx Col2CodeOffset,y
; sta $0001,x
;
; This table is necessary, because due to the data being draw via stack instructions, the
; This table is necessary, because due to the data being drawn via stack instructions, the
; tile order is reversed.
PER_TILE_SIZE equ 3
@ -216,8 +216,3 @@ BlitBuff ds 4*13
BTableHigh ds 208*2*2
BTableLow ds 208*2*2

View File

@ -6,6 +6,10 @@ DP_ADDR equ entry_1-base+1 ; offset to patch in the
BG1_ADDR equ entry_2-base+1 ; offset to patch in the Y-reg for BG1 (dp),y addressing
STK_ADDR equ entry_3-base+1 ; offset to patch in the stack (SHR) right edge address
DP_ENTRY equ entry_1-base
TWO_LYR_ENTRY equ entry_2-base
ONE_LYR_ENTRY equ entry_3-base
CODE_ENTRY equ entry_jmp-base+1 ; low byte of the page-aligned jump address
CODE_TOP equ loop-base
CODE_LEN equ top-base
@ -113,7 +117,7 @@ FillScreen lda #0
jsr ClearToColor
ldy ScreenY0
]yloop
:yloop
tya
asl a
tax
@ -127,16 +131,16 @@ FillScreen lda #0
lsr
tay
lda #$FFFF
]xloop stal $E10000,x
:xloop stal SHR_SCREEN,x
inx
inx
dey
bne ]xloop
bne :xloop
ply
iny
cpy ScreenY1
bcc ]yloop
bcc :yloop
rts
; Set the starting line of the virtual buffer that will be displayed on the first physical line
@ -194,22 +198,10 @@ FillScreen lda #0
; Input: A = line number [0, 207]
; Output: A = low word, X = high word
GetBlitLineAddress
pha ; save the value
and #$FFF0 ; Divide by 16 to get the bank number of this line and
lsr ; then multiply by 4 to get the offset. So just divide by 4.
lsr
tax
lda BlitBuff+2,x ; This is the high word of the bank address
tax
pla ; Pop the value and multiply the lower 4 bits by 4096 to get
and #$000F ; the line offset within the bank
xba
asl
asl
asl
asl ; This is the page of the line
tay
lda BTableLow,y
ldx BTableHigh,y
rts
@ -389,7 +381,7 @@ SetNextLine lda #$F000+{entry_3-base}
jmp SetAbsAddrs
; Copy a series of bank bytes onto the direct page, which we will later point the stack
; at, and are use to iterate among the different code banks.
; at and use to iterate among the different code banks.
;
; Y = starting index * 4
; X = number of bank
@ -446,7 +438,7 @@ PushBanks sep #$20
; A = value
;
; Set M to 0 or 1
SetConst ; Need a blnk line here, otherwise the :tbl local variable resolveds backwards
SetConst ; Need a blank line here, otherwise the :tbl local variable resolveds backwards
jmp (:tbl,x)
:tbl da :bottom-00,:bottom-03,:bottom-06,:bottom-09
da :bottom-12,:bottom-15,:bottom-18,:bottom-21
@ -479,49 +471,77 @@ SetConst ; Need a blnk line here,
; X = number of lines * 2, 0 to 32
; Y = starting line * $1000
; A = store location * $1000
SaveOpcode pha ; save the accumulator
ldal :tbl,x
dec
plx ; put the accumulator into X
pha ; push the address into the stack
rts ; and jump
SaveOpcode0
jmp (:tbl,x)
:tbl da :bottom-00,:bottom-06,:bottom-12,:bottom-18
da :bottom-24,:bottom-30,:bottom-36,:bottom-42
da :bottom-48,:bottom-54,:bottom-60,:bottom-66
da :bottom-72,:bottom-78,:bottom-84,:bottom-90
da :bottom-96
:top lda $F000,y
:tbl da :bottom
da :do01,:do02,:do03,:do04
da :do05,:do06,:do07,:do08
da :do09,:do10,:do11,:do12
da :do13,:do14,:do15,:do16
:do15 tax
bra :x15
:do14 tax
bra :x14
:do13 tax
bra :x13
:do12 tax
bra :x12
:do11 tax
bra :x11
:do10 tax
bra :x10
:do09 tax
bra :x09
:do08 tax
bra :x08
:do07 tax
bra :x07
:do06 tax
bra :x06
:do05 tax
bra :x05
:do04 tax
bra :x04
:do03 tax
bra :x03
:do02 tax
bra :x02
:do01 tax
bra :x01
:do16 tax
:x16 lda $F000,y
sta $F000,x
lda $E000,y
:x15 lda $E000,y
sta $E000,x
lda $D000,y
:x14 lda $D000,y
sta $D000,x
lda $C000,y
:x13 lda $C000,y
sta $C000,x
lda $B000,y
:x12 lda $B000,y
sta $B000,x
lda $A000,y
:x11 lda $A000,y
sta $A000,x
lda $9000,y
:x10 lda $9000,y
sta $9000,x
lda $8000,y
:x09 lda $8000,y
sta $8000,x
lda $7000,y
:x08 lda $7000,y
sta $7000,x
lda $6000,y
:x07 lda $6000,y
sta $6000,x
lda $5000,y
:x06 lda $5000,y
sta $5000,x
lda $4000,y
:x05 lda $4000,y
sta $4000,x
lda $3000,y
:x04 lda $3000,y
sta $3000,x
lda $2000,y
:x03 lda $2000,y
sta $2000,x
lda $1000,y
:x02 lda $1000,y
sta $1000,x
lda: $0000,y
:x01 lda: $0000,y
sta: $0000,x
:bottom rts
@ -533,50 +553,77 @@ SaveOpcode pha ; save the accumulator
; X = number of lines * 2, 0 to 32
; Y = starting line * $1000
; A = store location * $1000
RestoreOpcode pha ; save the accumulator
ldal :tbl,x
dec
plx ; put the accumulator into X
pha ; push the address into the stack
rts ; and jump
RestoreOpcode
jmp (:tbl,x)
:tbl da :bottom-00,:bottom-06,:bottom-12,:bottom-18
da :bottom-24,:bottom-30,:bottom-36,:bottom-42
da :bottom-48,:bottom-54,:bottom-60,:bottom-66
da :bottom-72,:bottom-78,:bottom-84,:bottom-90
da :bottom-96
:tbl da :bottom
da :do01,:do02,:do03,:do04
da :do05,:do06,:do07,:do08
da :do09,:do10,:do11,:do12
da :do13,:do14,:do15,:do16
:top lda $F000,x
:do15 tax
bra :x15
:do14 tax
bra :x14
:do13 tax
bra :x13
:do12 tax
bra :x12
:do11 tax
bra :x11
:do10 tax
bra :x10
:do09 tax
bra :x09
:do08 tax
bra :x08
:do07 tax
bra :x07
:do06 tax
bra :x06
:do05 tax
bra :x05
:do04 tax
bra :x04
:do03 tax
bra :x03
:do02 tax
bra :x02
:do01 tax
bra :x01
:do16 tax
:x16 lda $F000,x
sta $F000,y
lda $E000,x
:x15 lda $E000,x
sta $E000,y
lda $D000,x
:x14 lda $D000,x
sta $D000,y
lda $C000,x
:x13 lda $C000,x
sta $C000,y
lda $B000,x
:x12 lda $B000,x
sta $B000,y
lda $A000,x
:x11 lda $A000,x
sta $A000,y
lda $9000,x
:x10 lda $9000,x
sta $9000,y
lda $8000,x
:x09 lda $8000,x
sta $8000,y
lda $7000,x
:x08 lda $7000,x
sta $7000,y
lda $6000,x
:x07 lda $6000,x
sta $6000,y
lda $5000,x
:x06 lda $5000,x
sta $5000,y
lda $4000,x
:x05 lda $4000,x
sta $4000,y
lda $3000,x
:x04 lda $3000,x
sta $3000,y
lda $2000,x
:x03 lda $2000,x
sta $2000,y
lda $1000,x
:x02 lda $1000,x
sta $1000,y
lda: $0000,x
:x01 lda: $0000,x
sta: $0000,y
:bottom rts
@ -729,8 +776,8 @@ SetAbsAddrs sec
sta: $0000,y
:bottom rts
; Full up a full bank with blitter templates. Currently we can fit 16 lines per bank, so need
; a total of 13 banks to hold the 208 lines to full-screen support
; Fill up a full bank with blitter templates. Currently we can fit 16 lines per bank, so need
; a total of 13 banks to hold the 208 lines for full-screen support
;
; A = high word of bank table
; Y = index * 4 of the bank to initialize
@ -769,13 +816,13 @@ BuildBank
plb
plb
lda #$F000+{entry_3-base} ; Set the address from each line to the next
lda #$F000+{ONE_LYR_ENTRY} ; Set the address from each line to the next
ldy #CODE_EXIT+1
ldx #15*2
jsr SetAbsAddrs
ldy #$F000+CODE_EXIT ; Patch the last line with a JML to go to the next bank
lda #{$005C+{entry_3-base}*256}
lda #{$005C+{ONE_LYR_ENTRY}*256}
sta [target],y
ldy #$F000+CODE_EXIT+2
lda nextBank
@ -893,7 +940,7 @@ long_3 stal *+5-base
; Return to caller -- the even_exit JMP from the previous line will jump here when a render is complete
full_return jml blt_return ; Full exit
; Re-enable interrupts and contniue -- the even_exit JMP fro the previous line will jump here every
; Re-enable interrupts and continue -- the even_exit JMP from the previous line will jump here every
; 8 or 16 lines in order to give the system some extra time to handle interrupts.
enable_int ldal stk_save ; restore the stack
tcs
@ -1029,4 +1076,23 @@ top

View File

@ -9,17 +9,190 @@
; updating the direct page state locations, this routine needs to
SetBG0YPos
cmp StartY
beq :nochange
sta StartY ; Save the position
lda #DIRTY_BIT_BG0_Y ; Mark that it has changed
tsb DirtyBits
:nochange
rts
beq :out ; Easy, if nothing changed, then nothing changes
ldx StartY ; Load the old value (but don't save it yet)
sta StartY ; Save the new position
lda #DIRTY_BIT_BG0_Y
tsb DirtyBits ; Check if the value is already dirty, if so exit
bne :out ; without overwriting the original value
stx OldStartY ; First change, so preserve the value
:out rts
; Based on the current value of StartY in the direct page. Set up the dispatch
; information so that the BltDispatch driver will render the correct code field
; lines in the the correct order
; information so that the BltRange driver will render the correct code field
; lines in the correct order
_ApplyBG0YPos
:rtbl_idx equ tmp0
:virt_line equ tmp1
:lines_left equ tmp2
:draw_count equ tmp3
; First task is to fill in the STK_ADDR values by copying them from the RTable array. We
; copy from RTable[i] into BlitField[StartY+i]. As with all of this code, the difficult part
; is decomposing the update across banks
stz :rtbl_idx ; Start copying from the first entry in the table
lda StartY ; This is the base line of the virtual screen
sta :virt_line ; Keep track of it
; copy a range of address from the table into the destination bank. If we restrict ourselves to
; rectangular playfields, this can be optimized to just subtracting a constant value. See the
; Templates::SetScreenAddrs subroutine.
lda ScreenHeight
sta :lines_left
; This is the verbose part -- figure out how many lines to draw. We don't want to artificially limit
; the height of the visible screen (for example, doing an animated wipe while scrolling), so the screen
; height could be anything from 1 to 200.
;
; For larger values, we want to break things up on 16-line boundaries based on the virt_line value. So,
;
; draw_count = min(lines_left, (16 - (virt_line % 16))
;
; Note that almost everything in this loop can be done with 8-bit operations sincc the values are
; all under 200. The one exception is the virt_line value which could exceed 256. This will be
; a later optimization and might save around 10 cycles per iteration, or up to ~120 cycles per frame
; and ~2,500 per secord. This is ~1% of our total CPU budget and is *just* enough cycles to be
; interesting.... Another 8 cycles could be removed by doing all calculatinos pre-multiplied by 2
; to avoid several 'asl' instructions
:loop
lda :virt_line
asl
tax
ldal BTableLow,x ; Get the address of the first code field line
tay
sep #$20
ldal BTableHigh,x
pha
plb ; This is the bank that will receive the updates
rep #$20
lda :virt_line
and #$000F
eor #$FFFF
inc
clc
adc #16
min :lines_left
sta :draw_count ; Do this many lines
asl
tax
lda :rtbl_idx ; Read from this location in the RTable
asl
jsr CopyRTableToStkAddr
lda :virt_line ; advance to the virtual line after the segment we just
clc ; filled in
adc :draw_count
sta :virt_line
lda :rtbl_idx ; advance the index into the RTable
adc :draw_count
sta :rtbl_idx
lda :lines_left ; subtract the number of lines we just completed
sec
sbc :draw_count
sta :lines_left
jne :loop
phk
plb
rts
; Unrolled copy routine to move RTable intries into STK_ADDR position.
;
; A = intect into the RTable array (x2)
; Y = starting line * $1000
; X = number of lines (x2)
CopyRTableToStkAddr
jmp (:tbl,x)
:tbl da :none
da :do01,:do02,:do03,:do04
da :do05,:do06,:do07,:do08
da :do09,:do10,:do11,:do12
da :do13,:do14,:do15,:do16
:do15 tax
bra :x15
:do14 tax
bra :x14
:do13 tax
bra :x13
:do12 tax
bra :x12
:do11 tax
bra :x11
:do10 tax
bra :x10
:do09 tax
bra :x09
:do08 tax
bra :x08
:do07 tax
bra :x07
:do06 tax
bra :x06
:do05 tax
bra :x05
:do04 tax
bra :x04
:do03 tax
bra :x03
:do02 tax
bra :x02
:do01 tax
bra :x01
:do16 tax
ldal RTable+30,x
sta STK_ADDR+$F000,y
:x15 ldal RTable+28,x
sta STK_ADDR+$E000,y
:x14 ldal RTable+26,x
sta STK_ADDR+$D000,y
:x13 ldal RTable+24,x
sta: STK_ADDR+$C000,y
:x12 ldal RTable+22,x
sta STK_ADDR+$B000,y
:x11 ldal RTable+20,x
sta STK_ADDR+$A000,y
:x10 ldal RTable+18,x
sta STK_ADDR+$9000,y
:x09 ldal RTable+16,x
sta: STK_ADDR+$8000,y
:x08 ldal RTable+14,x
sta STK_ADDR+$7000,y
:x07 ldal RTable+12,x
sta STK_ADDR+$6000,y
:x06 ldal RTable+10,x
sta STK_ADDR+$5000,y
:x05 ldal RTable+08,x
sta: STK_ADDR+$4000,y
:x04 ldal RTable+06,x
sta STK_ADDR+$3000,y
:x03 ldal RTable+04,x
sta STK_ADDR+$2000,y
:x02 ldal RTable+02,x
sta STK_ADDR+$1000,y
:x01 ldal RTable+00,x
sta: STK_ADDR+$0000,y
:none rts