Rybags Posted August 9, 2009 Share Posted August 9, 2009 Refer my earlier post... from what I've found in testing, the "danger cycle" is one earlier when dealing with single-line modes. Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 9, 2009 Share Posted August 9, 2009 If I have time I'm going to whip up a program to show where the interrupts fall on a scan line for a given divisor. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 9, 2009 Share Posted August 9, 2009 I had an idea I tried earlier... use Serial Output, as you can control the Interrupt more easily. Sadly... the only useful Serial Output modes generate a high pitched noise you can't mask, and you also get a bit of noise from the data transmission. Quote Link to comment Share on other sites More sharing options...
phaeron Posted August 9, 2009 Share Posted August 9, 2009 I've just confirmed the behaviour using similar technique (enable SEROC IRQ at known times). Burn 5 cycles after WSYNC then Store 8 to IRQEN. It blocks any DLI, except those types that are on single scanline modes. To block single-scanline DLIs, strangely enough, you just need to burn 4 cycles after the DLI. Might be just the way Antic does DLIs... if it's a single scanline mode line then it must start the NMI one cycle earlier. I also tried the same technique but executing a 7-cycle 6502 Instruction... no problematic effects caused there at all. Also tried varying the delay after WSYNC - no effect. It would seem that you need to store to IRQEN exactly on cycle 112 (or cycle 111 if dealing with single-line modes). But it could be that POKEY has some delay before triggering the IRQ once we've enabled it. What mode/width are you using? WSYNC can be delayed by up to two cycles if playfield or refresh DMA extends to the end of a scanline. I've also suspected that you may encounter yet another cycle delay if the cycle immediately after STA WSYNC is contended, but unfortunately, I can't find my test app to confirm this. Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 9, 2009 Share Posted August 9, 2009 I used to generate software interrupts by flipping one of the PIA control pins from input to output with the interrupt enabled. Quote Link to comment Share on other sites More sharing options...
atariksi Posted August 9, 2009 Share Posted August 9, 2009 I had an idea I tried earlier... use Serial Output, as you can control the Interrupt more easily. Sadly... the only useful Serial Output modes generate a high pitched noise you can't mask, and you also get a bit of noise from the data transmission. There's another major bug in the 400/800 OS. To try it, just hit the RESET key on the exact cycle that VBI occurs and only one NMI gets serviced although both are in the status register 54287. In that code I posted, if you press the RESET key, you will see the PINK bar change to BLUE meaning you can still read the RESET key like a console key although NMIs are disabled. So you can use RESET like a console key if you write cycle-exact code. Press RESET to Start the game like going to START menu to do SHUT-DOWN under Windows. Quote Link to comment Share on other sites More sharing options...
phaeron Posted August 9, 2009 Share Posted August 9, 2009 If I have time I'm going to whip up a program to show where the interrupts fall on a scan line for a given divisor. I'd be interested in knowing your results, as I'm currently implementing POKEY initialization in my emulator. The tricky part is that there is an offset from when SKCTL bits 0+1 go up and when the audio clocks turn over, because they're implemented as polynomial counters where the clear value is mid-way through the cycle. In the case of the 64KHz clock, it appears to start 7 cycles prior to the comparator firing, but there is an additional two cycles of delay from the clock to the counters. I haven't quite figured out the 15KHz clock yet since the comparator seems to work slightly differently in that portion of the schematic. Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 9, 2009 Share Posted August 9, 2009 (edited) If we ever get good enough schematics for the chips, we could build them in a logic simulator and watch the cycle by cycle operation. As it is, we figure out a little more each day. Edited August 9, 2009 by Bryan Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 9, 2009 Share Posted August 9, 2009 (edited) This quick BASIC program shows the distribution of IRQ's and how many lines the entire sequence takes. You can see why a divisor of 14 is much safer than 15. 10 GRAPHICS 7:COLOR 3:TRAP 10 20 PLOT 23,30:DRAWTO 136,30 30 PLOT 23,40:DRAWTO 136,40 40 ? "64KHZ IRQ PLOTTER - AUDF VALUE";:INPUT D 50 IF D<0 OR D>255 THEN 10 55 COLOR 0:PLOT 23,35:DRAWTO 136,35 60 COLOR 1:PLOT 23,35:X=0:L=1:F=D:? "LINE 1" 70 X=X+28:IF X>113 THEN X=X-114:L=L+1:? "LINE ";L 80 IF F=0 THEN 100 90 F=F-1:GOTO 70 100 IF X=0 THEN 120 110 PLOT 23+X,35:F=D:GOTO 70 120 GOTO 40 64PLOT.zip Edited August 9, 2009 by Bryan Quote Link to comment Share on other sites More sharing options...
Sheddy Posted August 9, 2009 Author Share Posted August 9, 2009 (edited) Here is a solution that works without any extra mucking about in the interrupt code. AUDF is changed from 15 to 14, which creates a repeating interrupt pattern that can avoid the NMI (but the pitch is a little higher). The timer is aligned with WSYNC and the sample plays without issues. There are only changes to the init routine (marked with asterisks). EDIT: I revised the attachment. The first one had the wrong source file. great work Bryan Still trying to make sure I understand why this works though actually I have to say everyone here has done great in pinning this sucker down and creating workarounds so quickly Edited August 9, 2009 by Sheddy Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 10, 2009 Share Posted August 10, 2009 (edited) You're welcome. A brief explanation of why it works: The goal is to find what cycles on a scan line will have an IRQ at some point. The number of cycles between IRQ's is (AUDF+1)*28. A scan line is 114 cycles, so you can string a bunch of scan lines end-to-end and start plotting where the IRQ's will fall. Eventually you land on the same cycle number you started with and the pattern will repeat. Fortunately, using the SKCTL trick, we can pick where the starting cycle is so we can align the pattern to always miss the DLI and VBI. BTW, try a divisor of 18 in the program above! Edited August 10, 2009 by Bryan Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 10, 2009 Share Posted August 10, 2009 (edited) The test I was doing used Blank lines where all the DLIs were occurring. Trust me - the required cycle for an IRQ to mask out a DLI is one earlier when the next line contains a single-line mode. The problem with using SKCTL is that it shuts down the Poly-Counters... so I guess we have to do this at a "quiet time" and then ensure that we retain that voice in 64 KHz mode. Changing AUDF on a voice only comes into effect after the current value has counted down. Changing the base clock of a voice is immediate. ed - has anyone tested all this with HScrol-enabled hires modes? I suspect the timings might vary even more. Or, on the other hand, there might be some cases where the DMA does us a favour and prevents IRQs occurring in critical cycles. Edited August 10, 2009 by Rybags Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 10, 2009 Share Posted August 10, 2009 (edited) The test I was doing used Blank lines where all the DLIs were occurring. Trust me - the required cycle for an IRQ to mask out a DLI is one earlier when the next line contains a single-line mode. The IRQ positions are spaced 6 cycles apart with a divisor of 14 (there are only 19 places on the line where an IRQ can occur). It should be possible to set the 64KHz timer to make sure both single and double line DLI's are covered. The problem with using SKCTL is that it shuts down the Poly-Counters... so I guess we have to do this at a "quiet time" and then ensure that we retain that voice in 64 KHz mode. I think we should only have to set the 64KHz timer once at the beginning of the program. After that it should maintain its alignment with the screen. Unless we discover that the DLI can move around even more, that should be fine. Changing AUDF on a voice only comes into effect after the current value has counted down. Changing the base clock of a voice is immediate. ed - has anyone tested all this with HScrol-enabled hires modes? I suspect the timings might vary even more. Or, on the other hand, there might be some cases where the DMA does us a favour and prevents IRQs occurring in critical cycles. I only tested it for Sheddy's demo program, but we could modify it to try a more complex display list. Edited August 10, 2009 by Bryan Quote Link to comment Share on other sites More sharing options...
atariksi Posted August 10, 2009 Share Posted August 10, 2009 The test I was doing used Blank lines where all the DLIs were occurring. Trust me - the required cycle for an IRQ to mask out a DLI is one earlier when the next line contains a single-line mode. The problem with using SKCTL is that it shuts down the Poly-Counters... so I guess we have to do this at a "quiet time" and then ensure that we retain that voice in 64 KHz mode. Changing AUDF on a voice only comes into effect after the current value has counted down. Changing the base clock of a voice is immediate. ed - has anyone tested all this with HScrol-enabled hires modes? I suspect the timings might vary even more. Or, on the other hand, there might be some cases where the DMA does us a favour and prevents IRQs occurring in critical cycles. Just a thought-- it may be that timing of POKEY is a little ahead of ANTIC (subcycle) so when NMI occurs before ANTIC/6502 can suppress IRQs, POKEY already beat them to it. Perhaps, people with schematics can figure it out for sure. And SKCTL stops/resets the 64Khz/15Khz clocks but not the 1.79Mhz clock. Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 10, 2009 Share Posted August 10, 2009 I'm getting ready for bed and it occurred to me that my second point above is rubbish. I already know from plotting different divisors that the 64KHz cycles can fall all over a scan line, so what we're really aligning is the beginning of our division cycle. So, the hard part is knowing how to re-align the Pokey channel without SKCTL if it has been used for something else. I'm sure there's a way... Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 10, 2009 Share Posted August 10, 2009 Just a thought-- it may be that timing of POKEY is a little ahead of ANTIC (subcycle) so when NMI occurs before ANTIC/6502 can suppress IRQs, POKEY already beat them to it. Perhaps, people with schematics can figure it out for sure. And SKCTL stops/resets the 64Khz/15Khz clocks but not the 1.79Mhz clock. I can tell you what my fix would be- Gate out the IRQ line as long as /NMI is asserted. Once the NMI's are cleared, and IRQ can happen. This would require consistent use of NMIRES, though. A more complex fix would be to use a falling /NMI to set an /IRQ supressing flip-flop that would be cleared on the next clock. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 10, 2009 Share Posted August 10, 2009 I don't think those fixes would work either. I suspect this entire thing might be due to the way 6502 works. My theory - during certain cycle/s of early IRQ processing (ie, 6502 pushing stuff to the stack, loading PC from $FFFE/F), the 6502 misses the falling edge on NMI. Since NMIs are always edge-triggered, not seeing the transition means the NMI is missed. Masking IRQs by an XOR type method with NMI won't work because our problem is most likely occurring when an IRQ has already started but the NMI trails it slightly. Surely though, if this is the case, it must have been encountered by other 6502 users out there and be documented. Quote Link to comment Share on other sites More sharing options...
emkay Posted August 10, 2009 Share Posted August 10, 2009 Surely though, if this is the case, it must have been encountered by other 6502 users out there and be documented. Depends on how deep coders have gone into coding techniques. How many people do you know who have used fullscreen 3D animations plus DLIs plus digi speech at the same time But it is interesting. Did I understand it right? NMI does not happen, if a POKEY timer is getting activated some cycles before? Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 10, 2009 Share Posted August 10, 2009 That's the conclusion so far... I've encountered 2 cycles that can mess them up, there could be more due to all the different cirumstances due to DMA (PMG, scrolling etc). You'd reckon the C64 guys might have encountered it if it's a 6502 thing... I'd say it's reasonably common to play Digi sound with their NMIs while also having Raster IRQs. Quote Link to comment Share on other sites More sharing options...
andym00 Posted August 10, 2009 Share Posted August 10, 2009 That's the conclusion so far... I've encountered 2 cycles that can mess them up, there could be more due to all the different cirumstances due to DMA (PMG, scrolling etc). You'd reckon the C64 guys might have encountered it if it's a 6502 thing... I'd say it's reasonably common to play Digi sound with their NMIs while also having Raster IRQs. With the 64 the only condition I'm aware of that can cause dropped interrupts is if you read the interrupt control register (I think 2 cycles) before an IRQ is triggered which can cause it not to raise a CIA interrupt, be that NMI or IRQ depending upon which CIA you're polling, but this is CIA bug not '6502' bug.. So basically if you ACK the interrupt 2 cycles before it happens, it won't happen from the point of view of triggering an interrupt.. Wish I had something useful to contribute to this thread, but it's been fascinating to watch you guys doing your Sherlock Holmes impressions this weekend I'm dying to know what is is that causes this now, and good luck Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 10, 2009 Share Posted August 10, 2009 (edited) <dbl> Edited August 10, 2009 by Rybags Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 10, 2009 Share Posted August 10, 2009 The other difference is that it's "RDY vs HALT"... the '64 uses RDY when VIC wants to halt the CPU, in theory the CPU just idles for those cycles. DMA/HALT is different, supposedly if the 6502 is held on a particular cycle phase, then maybe it's effectively stalled rather than idling. Another thing is that the CIA will hold NMI low indefinately until you clear it - it's a common trick on the C64 to use a CIA NMI to disable the Restore key. It seems Antic only holds NMI low for a short period. Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 10, 2009 Share Posted August 10, 2009 (edited) My theory - during certain cycle/s of early IRQ processing (ie, 6502 pushing stuff to the stack, loading PC from $FFFE/F), the 6502 misses the falling edge on NMI. Yeah, it's got to have something to do with the timing used by either /IRQ (Pokey), /NMI (Antic) or the /HALT line (Antic). It's possible that a small sub-cycle adjustment would have prevented it. I think Atari coders have run into this many times before (probably during disk loads) and didn't know what it was. I thought of a possible way to align a playback routine with the 64KHz clock prior to play- On a non-DMA line (Vblank), write 0 to AUDF1, change the IRQ vector to point to the alignment routine, and wait until you are past the memory refresh cycles. Then enable the TIMER1 interrupt and start loading A with immediates: lda #, lda #, lda #, lda #... fourteen times so you've covered an entire 28-cycle (64KHz) interval. When the alignment IRQ runs, it will know which cycle the IRQ is currently on (A) and can load AUDF1 with a value to resync the playback. Then change the vector back and reload AUDF1 with the playback divisor. It's complicated, but it might work. Edited August 10, 2009 by Bryan Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 10, 2009 Share Posted August 10, 2009 Something like that sounds feasible. I just wonder, though, if we could align the divisor on an odd cycle (or whatever may be needed) in the first place, maybe we could reduce the conflicts to only be those that coincide with single-line DLIs. I've not done a lot of incorporating DLIs into disk loaders... the main problem I found was that the DLI activity would cause the occasional glitch in SIO, so I stayed away from doing it. Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 10, 2009 Share Posted August 10, 2009 (edited) Something like that sounds feasible. I just wonder, though, if we could align the divisor on an odd cycle (or whatever may be needed) in the first place, maybe we could reduce the conflicts to only be those that coincide with single-line DLIs. I've not done a lot of incorporating DLIs into disk loaders... the main problem I found was that the DLI activity would cause the occasional glitch in SIO, so I stayed away from doing it. Hmm... once the 64KHz timer is started, it can potentially hit every even or odd cycle depending on alignment. It should be possible to pick one or the other with SKCTL. If I monitor a 64KHz oscillation on Pokey I can see if I can shift it one cycle relative to sync. This can help us determine if one state is better than the other. Another experiment would be to tie /NMI to both /IRQ and /NMI on the 6502 and set up two handling routines. The NMI should run, followed by the IRQ (assuming /NMI is held for some time) and we can see if that's the case or if only IRQ runs. Edited August 10, 2009 by Bryan 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.