+Karl G Posted February 11, 2021 Share Posted February 11, 2021 It seems like this situation must come up all the time, but somehow I've not dealt with it. How does one deal with the situation where e.g. the playfield changes every 8 scanlines, but one is using a 2-line kernel? I have enough time to use the scanline number as an index and read from a table, but not enough time to divide it by 4 before using it as an index. The only real solution I can think of is increasing my playfield data tables by 4, but I'm wondering if there's a more elegant solution. Here's my current kernel code for reference: lda #arena_height-1 sta Scanline lda #0 ldx #0 VisibleScreen sta WSYNC ; 3 (0) sta PF0 ; 3 (3) tay ; 2 (5) sta ENAM0 ; 3 (8) lsr ; 2 (10) sta ENAM1 ; 3 (13) lsr ; 2 (15) sta ENABL ; 3 (18) inx ; 2 (20) lda DataPF1,x ; 4 (24*) sta PF1 ; 3 (27) lda DataPF2,x ; 4 (31) sta PF2 ; 3 (34) ldy P0Draw ; 3 (37) lda P0Height ; 3 (40) dcp P0Draw ; 5 (45) bcs ____draw_p0 ; 2 (47) ldx #0 ; 2 (49) jmp ____done_p0 ; 3 (52) ____draw_p0 lax (P0Ptr),y ; 5 (53) ____done_p0 ldy P1Draw ; 3 (56) lda P1Height ; 3 (59) dcp P1Draw ; 5 (64) bcs ____draw_p1 ; 2 (66) lda #0 ; 2 (68) jmp ____done_p1 ; 3 (71) ____draw_p1 lda (P1Ptr),y ; 5 (72) ____done_p1 ; Cycles actually between 70-72 depending on which branches taken, but evened out by the WSYNC Line2 sta WSYNC ; 3 (0) stx GRP0 ; 3 (3) sta GRP1 ; 3 (6) lda M0Height ; 3 (9) dcp M0Draw ; 5 (14) bcs ____draw_m0 ; 2 (16) ldy #0 ; 2 (18) jmp ____done_m0 ; 3 (21) ____draw_m0 ldy #2 ; 2 (19) sleep 2 ; 2 (21) ____done_m0 lda M1Height ; 3 (24*) dcp M1Draw ; 5 (29) bcs ____draw_m1 ; 2 (31) sleep 4 ; 4 (35) jmp ____done_m1 ; 3 (38) ____draw_m1 tya ; 2 (34) ora #4 ; 2 (36) tay ; 2 (38) ____done_m1 lda BallHeight ; 3 (41) dcp BallDraw ; 5 (46) bcs ____draw_ball ; 2 (48) tya ; 2 (50) jmp ____done_ball ; 3 (53) ____draw_ball tya ; 2 (51) ora #8 ; 2 (53) ____done_ball ; Scanline should be divided by 4, but there's not enough time ldx Scanline ; 3 (56) lda DataPF0,x ; 4 (60) dec Scanline ; 5 (65) bpl VisibleScreen ; 3 (68) Quote Link to comment Share on other sites More sharing options...
+splendidnut Posted February 11, 2021 Share Posted February 11, 2021 Instead of your current Scanline counter, have two counters: one for counting the playfield rows, and the other for counting scanlines within the playfield rows. Then change the end of your loop code (starting with LDX Scanline...) to something like: dec lineCnt ;5 [58] bpl VisibleScreen ;3 [60/61] lda #3 ;2 [62] sta lineCnt ;3 [65] dec pfLineCnt ;5 [70] bpl VisibleScreenAfterWSYNC ;3 [73] The only thing I didn't add was the "lda DataPF0,x".... if you can find some way to squeeze that in (get rid of the unnecessary? TAY and the need for INX near the beginning of the loop), that might work 1 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted February 11, 2021 Share Posted February 11, 2021 38 minutes ago, splendidnut said: have two counters Yep, that's what I show in the Collect Tutorial. I used Y for the scanline and X for the playfield when I added the playfield routines in step 7. ArenaLoop: ; 27 - (currently 7 from bpl ArenaLoop) tya ; 2 29 - 2LK loop counter in A for testing and #%11 ; 2 31 - test for every 4th time through the loop, bne SkipX ; 2 33 (3 34) branch if not 4th time inx ; 2 35 - if 4th time, increase X so new playfield data is used SkipX: ; 35 - use 35 as it's the longest path here ... ; start of line 1 of the 2LK sta GRP1 ; 3 3 - @0-22, update player1 graphics lda ArenaPF0,x ; 4 7 - get current scanline's playfield pattern sta PF0 ; 3 10 - @0-22 and update it lda ArenaPF1,x ; 4 14 - get current scanline's playfield pattern sta PF1 ; 3 17 - @71-28 and update it lda ArenaPF2,x ; 4 21 - get current scanline's playfield pattern sta PF2 ; 3 24 - @60-39 When I added the ball in step 11 I needed to use X for it, so added a RAM variable ArenaIndex that gets loaded into X when its time to update the PFxx registers. ArenaLoop: ; 37 - (currently 11 from bpl ArenaLoop) tya ; 2 39 - 2LK loop counter in A for testing and #%11 ; 2 41 - test for every 4th time through the loop, bne SkipX ; 2 43 - (3 44) branch if not 4th time inc ArenaIndex ; 5 48 - if 4th time, increase index so new playfield data is used SkipX: ; 48 - use 48 as it's the longest path here ... ldx ArenaIndex ; 3 6 lda ArenaPF0,x ; 4 10 - get current scanline's playfield pattern sta PF0 ; 3 13 - @0-22 and update it lda ArenaPF1,x ; 4 17 - get current scanline's playfield pattern sta PF1 ; 3 20 - @71-28 and update it lda ArenaPF2,x ; 4 24 - get current scanline's playfield pattern sta PF2 ; 3 27 - @60-39 1 1 Quote Link to comment Share on other sites More sharing options...
+Karl G Posted February 11, 2021 Author Share Posted February 11, 2021 Thanks! I am closer now using a second counter and doing a little cleanup. I just need to do a little work to figure out why my cycle counts are still off. Quote Link to comment Share on other sites More sharing options...
+Karl G Posted February 12, 2021 Author Share Posted February 12, 2021 In case it's useful to anyone, I got it to work with the suggested two counters after some rearranging and enabling VDELP1. I was also able to "upgrade" to pointers for the 3 playfield registers. VisibleScreen sta ENAM0 ; 3 (3) lsr ; 2 (5) sta ENAM1 ; 3 (8) lsr ; 2 (10) sta ENABL ; 3 (13) VSEntry ldy P0Draw ; 3 (16) lda P0Height ; 3 (19) dcp P0Draw ; 5 (24*) bcs ____draw_p0 ; 2 (26) ldx #0 ; 2 (28) .byte $2C ; 4 (32) ____draw_p0 lax (P0Ptr),y ; 5 (32) ____done_p0 ldy P1Draw ; 3 (35) lda P1Height ; 3 (38) dcp P1Draw ; 5 (43) bcs ____draw_p1 ; 2 (45) lda #0 ; 2 (47) .byte $2C ; 4 (51) ____draw_p1 lda (P1Ptr),y ; 5 (51) ____done_p1 sta GRP1 ; 3 (54) ; VDEL ldy PFline ; 3 (57) lda (PF2Ptr),y ; 5 (62) sta PF2 ; 3 (65) lda (PF1Ptr),y ; 5 (70) sta PF1 ; 3 (73) Line2 lda (PF0Ptr),y ; 5 (2) sta PF0 ; 3 (5) stx GRP0 ; 3 (8) lda Scanline ; 3 (11) and #3 ; 2 (13) beq ____do_4th ; 2 (15) sleep 3 ; 3 (18) jmp ____skip_4th ; 3 (21) ____do_4th dec PFline ; 5 (21) ____skip_4th PM0 lda M0Height ; 3 (24*) dcp M0Draw ; 5 (29) bcs ____draw_m0 ; 2 (31) ldy #0 ; 2 (33) jmp ____done_m0 ; 3 (36) ____draw_m0 ldy #2 ; 2 (34) sleep 2 ; 2 (36) ____done_m0 PM1 lda M1Height ; 3 (39) dcp M1Draw ; 5 (44) bcs ____draw_m1 ; 2 (46) sleep 4 ; 4 (50) jmp ____done_m1 ; 3 (53) ____draw_m1 tya ; 2 (49) ora #4 ; 2 (51) tay ; 2 (53) ____done_m1 PBL lda BallHeight ; 3 (56) dcp BallDraw ; 5 (61) bcs ____draw_ball ; 2 (63) tya ; 2 (65) jmp ____done_ball ; 3 (68) ____draw_ball tya ; 2 (66) ora #8 ; 2 (68) ____done_ball dec Scanline ; 5 (73) bpl VisibleScreen ; 3 (0) Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted February 13, 2021 Share Posted February 13, 2021 20 hours ago, Karl G said: enabling VDELP1 With that you can update GRP1 at any time in the scanline, but need to update GPR0 and ENABL during the time critical horizontal blank. If you turn that around, and enable VDELP0 and VDELBL instead, you'll make timing in your Kernel a little more flexible: GRP1 is now in horizontal blank, but can update both GRP0 and ENABL at any time. 1 Quote Link to comment Share on other sites More sharing options...
+Karl G Posted February 13, 2021 Author Share Posted February 13, 2021 7 minutes ago, SpiceWare said: With that you can update GRP1 at any time in the scanline, but need to update GPR0 and ENABL during the time critical horizontal blank. If you turn that around, and enable VDELP0 and VDELBL instead, you'll make timing in your Kernel a little more flexible: GRP1 is now in horizontal blank, but can update both GRP0 and ENABL at any time. Ahh, thanks. I got the timings to work for this kernel already, but that's good to know for future kernels. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.