; Subroutines that deal with the vertical scrolling and rendering. The primary function ; of these routines are to adjust tables and patch in new values into the code field ; when the virtual Y-position of the play field changes. ; Based on the current value of StartY in the direct page. Set up the dispatch ; 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 jsr Mod208 sta StartYMod208 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