its-a-feature Posted May 29, 2020 Share Posted May 29, 2020 Hi, so I'm just getting into 6502 assembly programming, and I'm having a hard time figuring out how to edit PF1 mid scanline so that I can make an asymmetrical playfield. I was wondering if anybody could explain it to me, with code examples if possible. Also I'm on PAL, so I have 242 screenlines instead of 192. Quote Link to comment Share on other sites More sharing options...
+Karl G Posted May 29, 2020 Share Posted May 29, 2020 In a nutshell, you need to count cycles for your scanlines, and write to the registers at the right time. For the left half of the playfield, you write to the playfield registers before they are displayed on the screen. For the right half of the screen, you write to each of these registers again after the left portion of that playfield register has finished displaying, and before the right half has begun displaying. This timing chart is invaluable for determining when to perform these playfield register writes. For example, for PF0, for the left half of the playfield, you will want to complete the first write to this register by cycle 22. For the second write, you will want to complete the write between cycle 28 (when the left half of PF0 has been drawn) and cycle 49 (when the right half of PF0 starts to display). 1 Quote Link to comment Share on other sites More sharing options...
its-a-feature Posted May 29, 2020 Author Share Posted May 29, 2020 30 minutes ago, Karl G said: In a nutshell, you need to count cycles for your scanlines, and write to the registers at the right time. For the left half of the playfield, you write to the playfield registers before they are displayed on the screen. For the right half of the screen, you write to each of these registers again after the left portion of that playfield register has finished displaying, and before the right half has begun displaying. This timing chart is invaluable for determining when to perform these playfield register writes. For example, for PF0, for the left half of the playfield, you will want to complete the first write to this register by cycle 22. For the second write, you will want to complete the write between cycle 28 (when the left half of PF0 has been drawn) and cycle 49 (when the right half of PF0 starts to display). Okay I tried to take that and implement it, but it's still not working... Is there something I'm missing? Here's my code... Kernel ldx #242 lda #$55 sta COLUPF LOOP cpx #49 bcs SKIP lda #%00100000 sta PF0 SKIP sta WSYNC dex bne LOOP rts Quote Link to comment Share on other sites More sharing options...
NoLand Posted May 29, 2020 Share Posted May 29, 2020 (edited) Mind that you'll have to (a) write the first value/pattern of PF0 on the start of each scanline for the left side, then wait for PF0 having been actually displayed and then set the new value – and this for each line. Start counting your cycles at WSYNC. E.g., sta WSYNC ;strobe WSYNC to be woke up at start of next scanline lda #%00010000 ;[3 cycles] sta PF0 ;[3 cycles, now at 6] lda #%01110000 ;[3 cycles, now at 9] sta PF1 ;[3 cycles, now at 12] lda #%11111100 ;[3 cycles, now at 15] sta PF2 ;[3 cycles, now at 18] lda #00010000 ;[3 cycles, now at 21] load right-side PF0 ;now wait until PF0 has been displayed ;scanline display starts at the end of cycle 23 ;+ 4 fat pixels = 4 * 4 / 3 (pixels per CPU cycle) = 5.333 ;so we'll have to wait at least until cycle #28 has passed. ;on the other hand, we should be done before cycle #49, ;when PF0 is used by the TIA again for the right side. nop ;[2 cycles, now at 23] nop ;[2 cycles, now at 25] nop ;[2 cycles, now at 27] ;mind that the value will be actually set only at the end of ;the last cycle of the STA instruction, so we're good to go sta PF0 ;[3 cycles, now at 30] ; now wait for PF1 (compare the chart) ; and for PF2 ... Edited May 29, 2020 by NoLand 1 Quote Link to comment Share on other sites More sharing options...
its-a-feature Posted May 29, 2020 Author Share Posted May 29, 2020 10 minutes ago, NoLand said: Mind that you'll have to (a) write the first value/pattern of PF0 on the start of each scanline for the left side, then wait for PF0 having been actually displayed and then set the new value – and this for each line. Start counting your cycles at WSYNC. E.g., sta WSYNC ;strobe WSYNC to be woke up at start of next scanline lda #%00010000 ;[3 cycles] sta PF0 ;[3 cycles, now at 6] lda #%01110000 ;[3 cycles, now at 9] sta PF1 ;[3 cycles, now at 12] lda #%11111100 ;[3 cycles, now at 15] sta PF2 ;[3 cycles, now at 18] lda #00010000 ;[3 cycles, now at 21] load right-side PF0 ;now wait until PF0 has been displayed ;scanline display starts at the end of cycle 23 ;+ 4 fat pixels = 4 * 4 / 3 (pixels per CPU cycle) = 5.333 ;so we'll have to wait at least until cycle #28 has passed. ;on the other hand, we should be done before cycle #49, ;when PF0 is used by the TIA again for the right side. nop ;[2 cycles, now at 23] nop ;[2 cycles, now at 25] nop ;[2 cycles, now at 27] ;mind that the value will be actually set only at the end of ;the last cycle of the STA instruction, so we're good to go sta PF0 ;[3 cycles, now at 30] ; now wait for PF1 (compare the chart) ; and for PF2 ... That makes sense, and it works now... thank you! Quote Link to comment Share on other sites More sharing options...
NoLand Posted May 29, 2020 Share Posted May 29, 2020 (edited) Mind that using a mirrored playfield setup (as opposed to a repeated one) will give you some extra time for the last two PF-registers. (Repeated: 4 + 8 + 8 + 4 + 8 + 8 vs. mirrored: 4 + 8 + 8 + 8 + 8 + 4. Meaning, there are 5 extra cycles for setting the last two PF values, in this case PF1 and PF0.) Edited May 29, 2020 by NoLand 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted May 29, 2020 Share Posted May 29, 2020 3 hours ago, its-a-feature said: I'm having a hard time figuring out how to edit PF1 mid scanline so that I can make an asymmetrical playfield. While you now have this working, Step 3 - Score & Timer display of my Collect Tutorial may add more insight. The tutorial covers the creation of a 2K game from start to end. The comments of each Step often go into more detail on how things work, such as Step 4's comments with additional information on how the player (sprite) drawing works. 1 Quote Link to comment Share on other sites More sharing options...
orange808 Posted May 29, 2020 Share Posted May 29, 2020 Just starting out? Here's a snippet from my cheatsheet with essential stuff from the internets. Probably want to copy and paste it somewhere. If you stick with the VCS long enough, you'll eventually need all of it. I don't remember where the playfield chart came from. (Sorry.) It must be from the old mailing list. Credit to Omegamatrix for the division routines and Brad Mott for the motion information. 0 inclusive (0-75) table Asymmetrical Playfield, Repeated Graphics (PF0-PF1-PF2-PF0-PF1-PF2): ============================================== | Playfield Register | Earliest | Latest | ============================================== | Left copy of PF0 | Cycle 52 * | Cycle 20 | | Left copy of PF1 | Cycle 63 * | Cycle 26 | | Left copy of PF2 | Cycle 74 * | Cycle 36 | | Right copy of PF0 | Cycle 26 | Cycle 47 | | Right copy of PF1 | Cycle 36 | Cycle 52 | | Right copy of PF2 | Cycle 47 | Cycle 63 | ============================================== Asymmetrical Playfield, Reflected Graphics (PF0-PF1-PF2-PF2-PF1-PF0): ============================================== | Playfield Register | Earliest | Latest | ============================================== | Left copy of PF0 | Cycle 74 * | Cycle 20 | | Left copy of PF1 | Cycle 68 * | Cycle 26 | | Left copy of PF2 | Cycle 58 * | Cycle 36 | | Right copy of PF2 | Cycle 47 | Cycle 47 | | Right copy of PF1 | Cycle 36 | Cycle 58 | | Right copy of PF0 | Cycle 26 | Cycle 68 | ============================================== ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; HMPx values 0 1 2 3 4 5 6 7 8 9 a b c d e f Cyc 10 0 -1 -2 -2 -2 -2 -2 -2 8 7 6 5 4 3 2 1 ** HBLANK 11 0 -1 -1 -1 -1 -1 -1 -1 8 7 6 5 4 3 2 1 HBLANK 12 0 0 0 0 0 0 0 0 8 7 6 5 4 3 2 1 HBLANK 13 1 1 1 1 1 1 1 1 8 7 6 5 4 3 2 1 HBLANK 14 1 1 1 1 1 1 1 1 8 7 6 5 4 3 2 1 ** HBLANK 15 2 2 2 2 2 2 2 2 8 7 6 5 4 3 2 2 HBLANK 16 3 3 3 3 3 3 3 3 8 7 6 5 4 3 3 3 HBLANK 17 4 4 4 4 4 4 4 4 8 7 6 5 4 4 4 4 HBLANK 18 4 4 4 4 4 4 4 4 8 7 6 5 4 4 4 4 ** HBLANK 19 5 5 5 5 5 5 5 5 8 7 6 5 5 5 5 5 HBLANK 20 6 6 6 6 6 6 6 6 8 7 6 6 6 6 6 6 HBLANK 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . . 53 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 56 0 0 0 0 0 0 -1 -2 0 0 0 0 0 0 0 0 57 0 0 0 0 0 -1 -2 -3 0 0 0 0 0 0 0 0 58 0 0 0 0 0 -1 -2 -3 0 0 0 0 0 0 0 0 ** 59 0 0 0 0 -1 -2 -3 -4 0 0 0 0 0 0 0 0 60 0 0 0 -1 -2 -3 -4 -5 0 0 0 0 0 0 0 0 61 0 0 -1 -2 -3 -4 -5 -6 0 0 0 0 0 0 0 0 62 0 0 -1 -2 -3 -4 -5 -6 0 0 0 0 0 0 0 0 ** 63 0 -1 -2 -3 -4 -5 -6 -7 0 0 0 0 0 0 0 0 64 -1 -2 -3 -4 -5 -6 -7 -8 0 0 0 0 0 0 0 0 65 -2 -3 -4 -5 -6 -7 -8 -9 0 0 0 0 0 0 0 -1 66 -2 -3 -4 -5 -6 -7 -8 -9 0 0 0 0 0 0 0 -1 ** 67 -3 -4 -5 -6 -7 -8 -9 -10 0 0 0 0 0 0 -1 -2 68 -4 -5 -6 -7 -8 -9 -10 -11 0 0 0 0 0 -1 -2 -3 69 -5 -6 -7 -8 -9 -10 -11 -12 0 0 0 0 -1 -2 -3 -4 70 -5 -6 -7 -8 -9 -10 -11 -12 0 0 0 0 -1 -2 -3 -4 ** 71 -6 -7 -8 -9 -10 -11 -12 -13 0 0 0 -1 -2 -3 -4 -5 72 -7 -8 -9 -10 -11 -12 -13 -14 0 0 -1 -2 -3 -4 -5 -6 73 -8 -9 -10 -11 -12 -13 -14 -15 0 -1 -2 -3 -4 -5 -6 -7 74 -8 -9 -10 -11 -12 -13 -14 -15 0 -1 -2 -3 -4 -5 -6 -7 ** 75 0 -1 -2 -3 -4 -5 -6 -7 8 7 6 5 4 3 2 1 HBLANK 76 0 -1 -2 -3 -4 -5 -6 -7 8 7 6 5 4 3 2 1 HBLANK 77 0 -1 -2 -3 -4 -5 -6 -7 8 7 6 5 4 3 2 1 HBLANK 78 0 -1 -2 -3 -4 -5 -6 -7 8 7 6 5 4 3 2 1 HBLANK 79 0 -1 -2 -3 -4 -5 -6 -7 8 7 6 5 4 3 2 1 HBLANK 80 0 -1 -2 -3 -4 -5 -6 -6 8 7 6 5 4 3 2 1 HBLANK 81 0 -1 -2 -3 -4 -5 -5 -5 8 7 6 5 4 3 2 1 HBLANK 82 0 -1 -2 -3 -4 -5 -5 -5 8 7 6 5 4 3 2 1 ** HBLANK 83 0 -1 -2 -3 -4 -4 -4 -4 8 7 6 5 4 3 2 1 HBLANK 84 0 -1 -2 -3 -3 -3 -3 -3 8 7 6 5 4 3 2 1 HBLANK 85 0 -1 -2 -2 -2 -2 -2 -2 8 7 6 5 4 3 2 1 HBLANK 86 0 -1 -2 -2 -2 -2 -2 -2 8 7 6 5 4 3 2 1 ** HBLANK 87 0 -1 -1 -1 -1 -1 -1 -1 8 7 6 5 4 3 2 1 HBLANK 88 0 0 0 0 0 0 0 0 8 7 6 5 4 3 2 1 HBLANK 89 1 1 1 1 1 1 1 1 8 7 6 5 4 3 2 1 HBLANK 90 1 1 1 1 1 1 1 1 8 7 6 5 4 3 2 1 ** HBLANK 91 2 2 2 2 2 2 2 2 8 7 6 5 4 3 2 2 HBLANK 92 3 3 3 3 3 3 3 3 8 7 6 5 4 3 3 3 HBLANK 93 4 4 4 4 4 4 4 4 8 7 6 5 4 4 4 4 HBLANK Notice that 10 + 76 = 86 and the table is repeating... 10 0 -1 -2 -2 -2 -2 -2 -2 8 7 6 5 4 3 2 1 ** HBLANK 11 0 -1 -1 -1 -1 -1 -1 -1 8 7 6 5 4 3 2 1 HBLANK 12 0 0 0 0 0 0 0 0 8 7 6 5 4 3 2 1 HBLANK 13 1 1 1 1 1 1 1 1 8 7 6 5 4 3 2 1 HBLANK 14 1 1 1 1 1 1 1 1 8 7 6 5 4 3 2 1 ** HBLANK 15 2 2 2 2 2 2 2 2 8 7 6 5 4 3 2 2 HBLANK 16 3 3 3 3 3 3 3 3 8 7 6 5 4 3 3 3 HBLANK 17 4 4 4 4 4 4 4 4 8 7 6 5 4 4 4 4 HBLANK ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Unsigned Integer Division Routines ; by Omegamatrix ;Divide by 2 ;1 byte, 2 cycles lsr ;Divide by 3 ;18 bytes, 30 cycles sta temp lsr adc #21 lsr adc temp ror lsr adc temp ror lsr adc temp ror lsr ;Divide by 4 ;2 bytes, 4 cycles lsr lsr ;Divide by 5 ;18 bytes, 30 cycles sta temp lsr adc #13 adc temp ror lsr lsr adc temp ror adc temp ror lsr lsr ;Divide by 6 ;17 bytes, 30 cycles lsr sta temp lsr lsr adc temp ror lsr adc temp ror lsr adc temp ror lsr ;Divide by 7 (From December '84 Apple Assembly Line) ;15 bytes, 27 cycles sta temp lsr lsr lsr adc temp ror lsr lsr adc temp ror lsr lsr ;Divide by 8 ;3 bytes, 6 cycles lsr lsr lsr ;Divide by 9 ;17 bytes, 30 cycles sta temp lsr lsr lsr adc temp ror adc temp ror adc temp ror lsr lsr lsr ;Divide by 10 ;17 bytes, 30 cycles lsr sta temp lsr adc temp ror lsr lsr adc temp ror adc temp ror lsr lsr ;Divide by 11 ;20 bytes, 35 cycles sta temp lsr lsr adc temp ror adc temp ror adc temp ror lsr adc temp ror lsr lsr lsr ;Divide by 12 ;17 bytes, 30 cycles lsr lsr sta temp lsr adc temp ror lsr adc temp ror lsr adc temp ror lsr ; Divide by 13 ; 21 bytes, 37 cycles sta temp lsr adc temp ror adc temp ror adc temp ror lsr lsr clc adc temp ror lsr lsr lsr ;Divide by 14 ;1/14 = 1/7 * 1/2 ;16 bytes, 29 cycles sta temp lsr lsr lsr adc temp ror lsr lsr adc temp ror lsr lsr lsr ;Divide by 15 ;14 bytes, 24 cycles sta temp lsr adc #4 lsr lsr lsr adc temp ror lsr lsr lsr ;Divide by 16 ;4 bytes, 8 cycles lsr lsr lsr lsr ;Divide by 17 ;18 bytes, 30 cycles sta temp lsr adc temp ror adc temp ror adc temp ror adc #0 lsr lsr lsr lsr ;Divide by 18 = 1/9 * 1/2 ;18 bytes, 32 cycles sta temp lsr lsr lsr adc temp ror adc temp ror adc temp ror lsr lsr lsr lsr ;Divide by 19 ;17 bytes, 30 cycles sta temp lsr adc temp ror lsr adc temp ror adc temp ror lsr lsr lsr lsr ;Divide by 20 ;18 bytes, 32 cycles lsr lsr sta temp lsr adc temp ror lsr lsr adc temp ror adc temp ror lsr lsr ;Divide by 21 ;20 bytes, 36 cycles sta temp lsr adc temp ror lsr lsr lsr lsr adc temp ror adc temp ror lsr lsr lsr lsr ;Divide by 22 ;21 bytes, 34 cycles lsr cmp #33 adc #0 sta temp lsr adc temp ror adc temp ror lsr adc temp ror lsr lsr lsr ;Divide by 23 ;19 bytes, 34 cycles sta temp lsr lsr lsr adc temp ror adc temp ror lsr adc temp ror lsr lsr lsr lsr ;Divide by 24 ;15 bytes, 27 cycles lsr lsr lsr sta temp lsr lsr adc temp ror lsr adc temp ror lsr ;Divide by 25 ;16 bytes, 29 cycles sta temp lsr lsr lsr adc temp ror lsr adc temp ror lsr lsr lsr lsr ;Divide by 26 ;21 bytes, 37 cycles lsr sta temp lsr adc temp ror adc temp ror adc temp ror lsr lsr adc temp ror lsr lsr lsr ;Divide by 27 ;15 bytes, 27 cycles sta temp lsr adc temp ror lsr lsr adc temp ror lsr lsr lsr lsr ;Divide by 28 ;14 bytes, 24 cycles lsr lsr sta temp lsr adc #2 lsr lsr adc temp ror lsr lsr ;Divide by 29 ;20 bytes, 36 cycles sta temp lsr lsr adc temp ror adc temp ror lsr lsr lsr adc temp ror lsr lsr lsr lsr ;Divide by 30 ;14 bytes, 26 cycles sta temp lsr lsr lsr lsr sec adc temp ror lsr lsr lsr lsr ;Divide by 31 ;14 bytes, 26 cycles sta temp lsr lsr lsr lsr lsr adc temp ror lsr lsr lsr lsr ;Divide by 32 lsr lsr lsr lsr lsr Quote Link to comment Share on other sites More sharing options...
alex_79 Posted May 30, 2020 Share Posted May 30, 2020 10 hours ago, orange808 said: I don't remember where the playfield chart came from. It's by @SeaGtGruff: https://atariage.com/forums/topic/149228-a-simple-display-timing-diagram/?do=findComment&comment=1820187 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted May 30, 2020 Share Posted May 30, 2020 18 hours ago, orange808 said: Asymmetrical Playfield, Reflected Graphics (PF0-PF1-PF2-PF2-PF1-PF0): ============================================== | Playfield Register | Earliest | Latest | ============================================== | Left copy of PF0 | Cycle 74 * | Cycle 20 | | Left copy of PF1 | Cycle 68 * | Cycle 26 | | Left copy of PF2 | Cycle 58 * | Cycle 36 | | Right copy of PF2 | Cycle 47 | Cycle 47 | | Right copy of PF1 | Cycle 36 | Cycle 58 | | Right copy of PF0 | Cycle 26 | Cycle 68 | ============================================== In Stay Frosty 2 I used an asymmetrical Playfield with Reflected Graphics. The right copy of PF2 had to be updated at cycle 48. .platformLoop lda (FrostyImagePtr+.SEC*2),y ; 5 64 and (FrostyMaskPtr+.SEC*2),y ; 5 69 sta WSYNC ; 3 72 sta GRP0 ; 3 lda (FrostyColorPtr+.SEC*2),y ; 5 8 sta COLUP0 ; 3 11 ldx Platforms+.SEC*4-4 ; 3 14 stx PF1 ; 3 17 ldx Platforms+.SEC*4-4+1 ; 3 20 stx PF2 ; 3 23 ldx Platforms+.SEC*4-4+2 ; 3 26 jsr SLEEP12 SLEEP 5 ;17 43 dey ; 2 45 stx PF2 ; 3 48 <- must be at 48 ldx Platforms+.SEC*4-4+3 ; 3 51 stx PF1 ; 3 54 cpy #2 ; 2 56 bcs .platformLoop ; 3 59 Just confirmed it via Stella: Quote Link to comment Share on other sites More sharing options...
orange808 Posted May 30, 2020 Share Posted May 30, 2020 Pretty sure there's a note that it's 0-75 (zero inclusive) table. :) Tomato, tomato. It's the same cycle. Quote Link to comment Share on other sites More sharing options...
orange808 Posted May 30, 2020 Share Posted May 30, 2020 :) Quote Link to comment Share on other sites More sharing options...
+splendidnut Posted May 30, 2020 Share Posted May 30, 2020 Huh, when counting from 0, I end up at cycle 48 for doing the update to PF2 (reflected playfield). How are you counting your cycles to end up at 47? Actually... nevermind... it's the whole inclusive bit. You must be a mathematician. 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.