khryssun Posted May 10, 2004 Share Posted May 10, 2004 Here is a mysterious bug in the VBLANK routine in the program below. The VBLANK routine burns 36 scanlines instead of 37 ! See the comments I put into the code for more explanations, if you have an answer to this riddle, it's welcome... This bug drives me crazy processor 6502 include "vcs.h" include "macro.h" SEG ORG $F000 Reset ; Clear all and Set Stack Pointer to #$FF SEI CLD LDX #$FF TXS LDA #0 Clear_Mem STA 0,X DEX BNE Clear_Mem LDA #$80 ; Blue STA COLUBK ; Set Background ; Start to Build Frame Start_Frame ; Start of Vertical Blank LDA #2 STA VSYNC STA WSYNC STA WSYNC STA WSYNC ; 3 Scanlines of VSYNC LDA #0 STA VSYNC ; Start of Vertival Blank ; Count 37 Scanlines------------ Start LDA #43 STA TIM64T Wait_VBLANK_End LDA INTIM BNE Wait_VBLANK_End STA WSYNC ; Count 37 Scanlines------------ End ; In fact the code above (between ---Start & ---End) ; burns only 36 Scanlines !!! ; In theory it should burns 37 Scanlines : ; 43*64 cycles = 2752 cycles ; 2752 cycles / 76 cycles per Scanline = 36.21 ; Waiting the end of the current scanline drawn ; with STA WSYNC should lead to 37 Scanlines. Right ? ; ; In practice it's WRONG : it burns only 36 !?! ; Use DOS version of Z26 and press ALT 9 to display ; the number of scanlines drawn : ; you'll see 261 instead of 262... ; ; Replace this part of code with basic following code : ; ; LDX 37 ; Vertical_Blank ; STA WSYNC ; DEX ; BNE Vertical_Blank ; ; And it will work (total = 262 scanlines) ; Where is the bug in the first code ??? LDA #0 STA VBLANK ; Enable TIA Output ; Display 192 Scanlines LDY #192 ; 192 Scanlines Picture STA WSYNC DEY ; End of Picture ? BNE Picture ; No = Continue ; Frame Ends Here LDA #%00000010 STA VBLANK ; Disable TIA Output ; 30 Scanlines of Overscan LDX #30 Overscan STA WSYNC DEX BNE Overscan JMP Start_Frame ; Build Next Frame ORG $FFFA Interrupt_Vectors .word Reset ; NMI .word Reset ; RESET .word Reset ; IRQ END Quote Link to comment Share on other sites More sharing options...
khryssun Posted May 10, 2004 Author Share Posted May 10, 2004 I received this answer from Erik Mooney (on the stella list) that solve the problem. I post it, it may be helpful to other programmers. Many thanks Erik > - Storing 43 into TIM64T burns 43*64 = 2752 cycles Not exactly. Based on a quick test in PCAEWin's debugger, when you store 43 into TIM64T, it *immediately* decrements to 42, then waits 64 cycles before decrementing to 41, 40, and so on. Storing 43 to TIM64T actually makes INTTIM reach 0 at 1+42*64 = 2689 cycles later, or only 35.38 scanlines later. Either store 44 instead of 43 to TIM64T (which is how the sample code from Nick Bensema's original "How To Draw A Playfield" does it, although the comments are misleading), or use BPL instead of BNE (which will make it wait an extra 64 cycles until the 0 in INTTIM decrements to $FF.) (At least I believe this is the answer, although I could be wrong. ) Quote Link to comment Share on other sites More sharing options...
khryssun Posted May 12, 2004 Author Share Posted May 12, 2004 And here's the explanation of this by Chris Wilkson : (BTW, Erik you were right on how it works. Here's why.) The timer is in fact decremented immediately. But that's not what causes the confusion. Your code checks to see if the timer is zero and branches as soon as this happens. But remember that the RIOT's timer ends at the *end* of the zero count, not the beginning. Thanks all Quote Link to comment Share on other sites More sharing options...
Blinky Posted July 10, 2004 Share Posted July 10, 2004 You could say the timer will read zero during the last 'interval' cycles Note that in case the timer is read after it timed out it will never become zero again and code will loop infinite. An alternative method for reading the timer is by testing the timer interrupt bit which is set when the timer times out. The A register is left untouched and It is supported by z26 too! WSLP bit INTIM+1 ;test timer interrupt flag bpl WSLP ;branch timer still counting sta WSYNC ;complete last scanline Personally I use INTIRQ instead of INTIM+1. But INTIRQ is not yet defined in vcs Quote Link to comment Share on other sites More sharing options...
Bruce Tomlin Posted July 11, 2004 Share Posted July 11, 2004 INTIRQ (or any of the IRQ versions of the timer start registers) is completely useless on the 2600 or 7800, because the IRQ output from the 6532 is not connected to anything. (FWIW, only the 7800 even has the 6502 IRQ line connected, and that only comes from the cartridge slot.) Quote Link to comment Share on other sites More sharing options...
Bruce Tomlin Posted July 11, 2004 Share Posted July 11, 2004 Argh. Now I see what you were doing. I just haven't found enough good docs on the 6532 yet. (Although I do have some 6530 docs, it's not quite close enough.) Quote Link to comment Share on other sites More sharing options...
Tom Posted July 11, 2004 Share Posted July 11, 2004 bruce: 6502.org has some 65xx data sheets: http://www.6502.org/documents/datasheets/m...s_6532_riot.pdf Quote Link to comment Share on other sites More sharing options...
Tom Posted July 11, 2004 Share Posted July 11, 2004 Note that in case the timer is read after it timed out it will never become zero again and code will loop infinite. no, it will indeed become zero again: after the timer expired, it continues counting at the system clock's frequency (regardless of which TIMxT register was written to). this allows you (to some extent) to calculate how much time exceeded since the timer expired. doesn't really matter here though, since you don't want to miss the moment the timer expired in your waitvblank loop... Personally I use INTIRQ instead of INTIM+1. But INTIRQ is not yet defined in vcs the register is defined in vcs.h, but it's called TIMINT Quote Link to comment Share on other sites More sharing options...
Blinky Posted July 11, 2004 Share Posted July 11, 2004 no, it will indeed become zero again: after the timer expired, it continues counting at the system clock's frequency The datasheet say it will continue to count to a maximum of -255T which would be 1 and not zero. This situation should never happen. But when writting new code and you're code locks-up for a unknown reason. This might something to look for. It's just something to keep in mind when programming. the register is defined in vcs.h, but it's called TIMINT Thanks. I was using the wrong vcs.h which didn't include it. Quote Link to comment Share on other sites More sharing options...
Tom Posted July 11, 2004 Share Posted July 11, 2004 The datasheet say it will continue to count to a maximum of -255T which would be 1 and not zero. ah, you're right! i should have read it more closely. this explains a certain bug in robotfindskitten 7800 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.