tschak909 Posted October 8, 2016 Share Posted October 8, 2016 Hey guys, Am currently going through and counting cycles in the Dodgeball kernel, and I seem to be running out of cycles now that I've changed both player and playfield output to indirect Y addressing. Source code attached, KERNEL.mainloop is the culprit routine. What could I be doing wrong ? -Thom dodgeball.asm Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted October 8, 2016 Share Posted October 8, 2016 First thing I see is your cycle counts are wrong - lda (indirect),y take a minimum of 5 cycles, not 4. LDA (LoaD Accumulator) Affects Flags: S Z MODE SYNTAX HEX LEN TIM Immediate LDA #$44 $A9 2 2 Zero Page LDA $44 $A5 2 3 Zero Page,X LDA $44,X $B5 2 4 Absolute LDA $4400 $AD 3 4 Absolute,X LDA $4400,X $BD 3 4+ Absolute,Y LDA $4400,Y $B9 3 4+ Indirect,X LDA ($44,X) $A1 2 6 Indirect,Y LDA ($44),Y $B1 2 5+ + add 1 cycle if page boundary crossed The other thing I see in the listing is this: 1667 f7f8 PF1_2 1668 f7f8 ff .byte.b #%11111111 1669 f7f9 00 .byte.b #%00000000 1670 f7fa 00 .byte.b #%00000000 1671 f7fb 00 .byte.b #%00000000 1672 f7fc 00 .byte.b #%00000000 1673 f7fd e0 .byte.b #%11100000 1674 f7fe 00 .byte.b #%00000000 1675 f7ff 00 .byte.b #%00000000 1676 f800 00 .byte.b #%00000000 1677 f801 40 .byte.b #%01000000 1678 f802 40 .byte.b #%01000000 1679 f803 40 .byte.b #%01000000 1680 f804 40 .byte.b #%01000000 1681 f805 40 .byte.b #%01000000 1682 f806 00 .byte.b #%00000000 1683 f807 00 .byte.b #%00000000 1684 f808 00 .byte.b #%00000000 1685 f809 e0 .byte.b #%11100000 1686 f80a 00 .byte.b #%00000000 1687 f80b 00 .byte.b #%00000000 1688 f80c 00 .byte.b #%00000000 1689 f80d 00 .byte.b #%00000000 1690 f80e ff .byte.b #%11111111 which is an example of where that + comes into play. PF1_2 starts at address $F7F8. When you add the value in Y to that, if the high byte of the resulting address is different then you crossed a page boundary. So if Y > 8 the resulting address is $F8xx. $F7 != $F8, so you crossed the page making the lda (indirect),y take 6 cycles instead of 5. It looks like your Y value maxes out at 28, so to prevent the page wrap make sure your data does not occupy the last 28 bytes of a page. Do that by adding align 256 statements in strategic locations such as: align 256 PF0_2 .byte #%11110000 .byte #%00010000 .byte #%00010000 .byte #%00010000 .byte #%00010000 .byte #%11110000 ... Quote Link to comment Share on other sites More sharing options...
tschak909 Posted October 8, 2016 Author Share Posted October 8, 2016 Yeah, I know, I didn't update the cycle counts for using the indirect Y... I do also need to put my aligns back in now that i've gone to a 4K cart, but that's not what's causing the issue... I'll continue to work on it. -Thom Quote Link to comment Share on other sites More sharing options...
Just Jeff Posted October 8, 2016 Share Posted October 8, 2016 These STA PFs don't seem to be where you think they are. They happen in the middle of the scan line: LDY TEMP ; 3 -- STA GRP0 ; 3 3 TXA ; 2 5 EOR BALLY2 ; 3 8 AND #$FC ; 2 10 PHP ; 3 13 LDA (PF0PTR),Y ; 4 17 STA PF0 ; 3 20 LDA (PF1PTR),Y ; 4 24 STA PF1 ; 3 27 LDA (PF2PTR),Y ; 4 31 STA PF2 ; 3 34 INX ; 2 39 LDA PLAYERY1 ; 3 42 SBC SCANLINE ; 3 45 AND #$FE ; 2 47 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted October 8, 2016 Share Posted October 8, 2016 These STA PFs don't seem to be where you think they are. They happen in the middle of the scan line: That's normal - playfield doesn't move so you can update the registers mid-scanline provided you don't do so while they're being shown. In my code I normally put when those updates need to occur so when I'm revising the kernel I can tell right away if there will be problems or not. From Frantic: KernelLoop: ; at this point the registers hold the following: ; A - graphics for player 1 ; Y - enable for missile 1 & PF0 for right side of screen ; PF0 and PF1 have already been updated for left side of room ; GRP0 (on VDEL) has been preloaded with player 0 graphics ; BL (on VDEL) has been preenabled with missile data ; at cycle 73 sta GRP1 ; 3 76/0 - before 22 - also updates GRP0 & BL via VDEL lda #<DS_COLUP0 ; 2 2 sta COLUP0 ; 3 5 - before 22 lda #<DS_COLUP1 ; 2 7 sta COLUP1 ; 3 10 - before 22 sty ENAM1 ; 3 13 - before 22 lda #<DS_EVENT_M0 ; 2 15 - bit 7 triggers kernel event sta ENAM0 ; 3 18 - before 22 sbmi KernelEvent ; 2 20 - 3 21 if taken SLEEP 3 ; 3 23 UPDATE_SPEECH ; 5 28 sty PF0 ; 3 31 - PF0R, 28-49 lda #<DS_PF2L ; 2 33 sta PF2 ; 3 36 - PF2L, before 38 ldy DS_PF0R_M1 ; 4 40 - any after sty PF0, loads for next line lda #<DS_PF1R ; 2 42 sta PF1 ; 3 45 - PF1R, 39-54 lda #<DS_GRP0 ; 2 47 sta GRP0 ; 3 50 - any, on VDEL lda #<DS_PF2R ; 2 52 sta PF2 ; 3 55 - PF2R, 50-65 lda #<DS_PF0L_BL ; 2 57 sta PF0 ; 3 60 - PF0L, after 55 sta ENABL ; 3 63 - any, on VDEL lda #<DS_PF1L ; 2 65 sta PF1 ; 3 68 - PF1L, 66 - 28 lda #<DS_GRP1 ; 2 70 jmp KernelLoop ; 3 73 GRP1 - before cycle 22 COLUP0 - before cycle 22 COLUP1 - before cycle 22 ENAM0 - before cycle 22 ENAM1 - before cycle 22 PF0 left side - after 55 on prior scanline. also before 22 on current, not specified because 0-22 is already super busy PF1 left side - between 66 (prior scanline) and 28 PF2 left side - between 0 and 38 PF0 right side - between 28 and 49 PF1 right side - between 39 and 54 PF2 right side - between 50 and 65 GRP0 - any cycle, it's on VDEL so update is delayed until GRP1 is written ENABL - any cycle, it's on VDEL so update is delayed until GRP1 is written 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted October 8, 2016 Share Posted October 8, 2016 So using Stella's debugger this is when the updates are occurring vs when they should occur for a symmetrical reflected playfield: LDA (PF0PTR),Y ; 4 17 STA PF0 ; 3 20 happens at 36, should be @0-22 LDA (PF1PTR),Y ; 4 24 STA PF1 ; 3 27 happens at 44, should be @70-28 LDA (PF2PTR),Y ; 4 31 STA PF2 ; 3 34 happens at 52, should be @60-38 I might be off a cycle or two on the 70 and 60 updates - those mean PF1 and PF2 can be updated on the prior scanline after TIA drew the second copy. 1 Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted October 8, 2016 Share Posted October 8, 2016 Also, be aware that you should use the BIT.w opcode (or some other inconsequential opcode for a 3-byte instruction) in place of the secondary branches when using (indirect),Y addressing in skipdraw code. Fixed loop: .mainLoop: ; X 33 LDX #ENABL ; 2 35 TXS ; 2 37 LDA SCANLINE ; 3 40 TAX ; 2 42 LSR ; 2 44 LSR ; 2 46 LSR ; 2 48 STA TEMP ; 3 51 LDA PLAYERY0 ; 3 54 SBC SCANLINE ; 3 57 AND #$FE ; 2 59 TAY ; 2 61 AND #$F0 ; 2 63 BEQ .doP0 ; 2 65 LDA #$00 ; 2 67 .byte $2C ; 4BIT.w71 .doP0: ; X 66 LDA (PLAYERP0),Y ; 5 71 LDY TEMP ; 3 74 STA GRP0 ; 3 1 TXA ; 2 3 EOR BALLY2 ; 3 6 AND #$FC ; 2 8 PHP ; 3 11 LDA (PF0PTR),Y ; 5 16 STA PF0 ; 3 19 LDA (PF1PTR),Y ; 5 24 STA PF1 ; 3 27 LDA (PF2PTR),Y ; 5 32 STA PF2 ; 3 35 INX ; 2 37 LDA PLAYERY1 ; 3 40 SBC SCANLINE ; 3 43 AND #$FE ; 2 45 TAY ; 2 47 AND #$F0 ; 2 49 BEQ .doP1 ; 2 51 LDA #$00 ; 2 53 .byte $2C ; 4BIT.w57 .doP1: ; X 52 LDA (PLAYERP1),Y ; 5 57 STA WSYNC ; 3 -- STA GRP1 ; 3 3 TXA ; 2 5 EOR BALLY1 ; 3 8 AND #$FC ; 2 10 PHP ; 3 13 TXA ; 2 15 EOR BALLY0 ; 3 18 AND #$FC ; 2 20 PHP ; 3 23 INX ; 2 25 STX SCANLINE ; 3 28 CPX #232 ; 2 30 BCC .mainLoop ; 2 Quote Link to comment Share on other sites More sharing options...
Just Jeff Posted October 9, 2016 Share Posted October 9, 2016 That's normal - playfield doesn't move so you can update the registers mid-scanline provided you don't do so while they're being shown. In my code I normally put when those updates need to occur so when I'm revising the kernel I can tell right away if there will be problems or not. Thanks! I might not have been clear enough. I meant that he's storing too late, too close to the middle. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted October 9, 2016 Share Posted October 9, 2016 Thanks! I might not have been clear enough. I meant that he's storing too late, too close to the middle. Aha! and that's exactly what was happening Quote Link to comment Share on other sites More sharing options...
tschak909 Posted October 11, 2016 Author Share Posted October 11, 2016 I am sucking at this horrifically... sigh. -Thom Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted October 11, 2016 Share Posted October 11, 2016 1) know when you can safely update things to prevent shearing, document those cycle times in your sourceFor moveable objects (players, missiles, ball) you need to update them on or before cycle 22*. A comment as simple as 0-22 will doFor the playfield it depends on whether you're going for a symmetrical or asymmetrical playfield, and if you're using the reflected or repeated layout.The TIA Timing diagram from Step 3 is arranged for a repeated playfield. I added some blue lines for a reflected playfield: Do note that there is a minor delay for the update to occur - looking at the diagram it appears that an asymmetrical reflected playfield would be impossible as you'd have to update PF2 for the right side on cycle 49.3333. However, as seen in Stay Frosty, it works if PF2 is updated on cycle 48.If you're going for symmetrical (like you are) then you have to update the registers before they get displayed for the left side, and after they've been displayed on the right. If you update them in the middle you get shearing. 2) always always always keep your kernel's cycle counts up to date so you can make sure #1 happens at the right timeIf the cycle counts in your source had been up to date it would have been immediately obvious what was wrong. Instead, I had to build your project then step through the code via Stella to see that the counts were way off. * for advanced 1 line kernels like the one in Draconian, you can turn on VDELP0 and VDELBL for the entire display which allows you to update GRP0 and ENABL at any time during the scanline. 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted October 11, 2016 Share Posted October 11, 2016 Use Stella's debugger to help: The oval shows the cycle times for each instruction. If your timing appears to be wrong, use these values to double check the counts you put in your source. If the values are right, then look for page boundary penalty. Those occur for many instructions, even branches. The arrows point to the current scanline cycle count and the instruction that's going to run next (check the PC, also note the green box around the instruction). This means the prior instruction of STA PF0 ended on cycle 36, well after the cycle 22 it needed to be done by. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted October 11, 2016 Author Share Posted October 11, 2016 Use Stella's debugger to help: Screen Shot 2016-10-11 at 10.55.15 AM.png The oval shows the cycle times for each instruction. If your timing appears to be wrong, use these values to double check the counts you put in your source. If the values are right, then look for page boundary penalty. Those occur for many instructions, even branches. The arrows point to the current scanline cycle count and the instruction that's going to run next (check the PC, also note the green box around the instruction). This means the prior instruction of STA PF0 ended on cycle 36, well after the cycle 22 it needed to be done by. Yup, I have been using the debugger to help with this, in precisely this capacity. It just takes me forever and a day to slowly work through trying to move instructions around to fit in timing... of all of this project, the kernel has proven to be the hardest part of any piece of software I've ever written, due to the timing sensitivity (then again, I never did, for example, disk drive controller firmware, which I imagine is far worse in some respects...) -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted October 12, 2016 Author Share Posted October 12, 2016 I am starting to think that shuffling the code to use an (ind),Y index was a _really_ bad idea... I'm having trouble getting the write to occur when it needs to... -Thom 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.