Rybags Posted August 10, 2009 Share Posted August 10, 2009 From the CPU perspective, kind of. HALT can cause an Interrupt to be seen a cycle or more later. I don't think that's a problem though. Where we're having trouble is around the end of the scanline, so far as our Cycle numbering is concerned. We can have next to no DMA in that area but still have problems. I think that if we can align the Timer IRQ to an odd cycle, then it might eliminate any cases of DLIs being missed in "big mode" cases, or "single scanline mode" cases. Remembering here that since the divisor is 28, it will always remain aligned to either an odd or even cycle. Quote Link to comment Share on other sites More sharing options...
atariksi 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. On the NMI System Reset, it's always cycle 9 after WSYNC on all NTSC 400/800 machines I tried. I haven't tried with various graphics mode to see if they move this cycle back and forth. Quote Link to comment Share on other sites More sharing options...
Bryan Posted August 10, 2009 Share Posted August 10, 2009 Now that I think of it, if I needed to play samples from time to time without touching SKCTL, I'd probably use the earlier method of checking for a missed DLI early in the IRQ code: irq pha ; save a tya pha ; save y lda NMIST ; check for a pending DLI nop ; replace NOP with something useful, but the delay is necessary for some reason adc NMIST ; If DLI was present both times, this will result in a carry bcc continue --perform DLI duties or jump down to continue This method works just as well as any other, but requires a little extra code. It seems the DLI flag is present in NMIST before the NMI happens because the double check with an instruction in between is necessary to make it stable. Quote Link to comment Share on other sites More sharing options...
atariksi Posted August 11, 2009 Share Posted August 11, 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. Which serial output IRQ were you using? There's two serial output IRQs-- serial output done (bit 3) and serial output data needed (bit 4). Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 11, 2009 Share Posted August 11, 2009 With that test I was using "Data Needed"... "Output Done" generates an IRQ automatically if you don't have SIO happening. I tried some of the "not useful" serial modes... they don't generate unwanted noise, but it seems they don't generate IRQs either (if in fact they even do SIO at all). Quote Link to comment Share on other sites More sharing options...
atariksi Posted August 12, 2009 Share Posted August 12, 2009 With that test I was using "Data Needed"... "Output Done" generates an IRQ automatically if you don't have SIO happening. I tried some of the "not useful" serial modes... they don't generate unwanted noise, but it seems they don't generate IRQs either (if in fact they even do SIO at all). So how many cycles after SIO completion does the IRQ occur. For Output Done, it's the very next cycle. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 12, 2009 Share Posted August 12, 2009 That wasn't my concern. The idea I had was to use a SIO IRQ instead of Timers. In theory, you should be able to get near cycle-exact accuracy without having to worry about initialising Pokey. Quote Link to comment Share on other sites More sharing options...
phaeron Posted August 12, 2009 Share Posted August 12, 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. 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. I'm still getting a nagging feeling that there's something specific to the timer IRQs that we're missing here. Why don't we see glitching due to SIO interrupts or the keyboard? Both are unpredictable with regard to scan line timing, and you'd think that someone would have noticed it if it happened at all. There are definitely cases where people use DLIs during SIO transfers -- the demo Joyride uses them. At 1,920 IRQs a second you're bound to hit a specific cycle at some point. That goes double if it is also able to mask the VBI. Incidentally, I found out during some cassette emulation work that the kernel does re-init POKEY at times other than just startup. In particular, it also does so when reading a cassette record, immediately after determining baud rate. If you're writing a program that is sensitive to the slow timer phase, you definitely need to re-init it yourself to ensure consistency. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 12, 2009 Share Posted August 12, 2009 You can get glitching from SIO ... it was mentioned earlier. Keyboard would be a really rare case though. It's fairly common for the VBlank to occur during the key IRQ, which means Stage 2 gets skipped. For the case of the keyboard interfering with a DLI, the odds are just too low. I suppose if you had a screen absolutely full of DLIs, you'd have a good chance of having a conflict. Timers probably show up better since they're an exact event, where keys are very random. Quote Link to comment Share on other sites More sharing options...
phaeron Posted August 12, 2009 Share Posted August 12, 2009 You can get glitching from SIO ... it was mentioned earlier. Keyboard would be a really rare case though. It's fairly common for the VBlank to occur during the key IRQ, which means Stage 2 gets skipped. For the case of the keyboard interfering with a DLI, the odds are just too low. I suppose if you had a screen absolutely full of DLIs, you'd have a good chance of having a conflict. Timers probably show up better since they're an exact event, where keys are very random. Oh, it may not be that rare.... Try the attached program. On my 800XL, the keyboard glitches the screen very reliably. See, it turns out there's a gotcha... the keyboard scanning circuit is based off of the 15KHz clock, which runs at scan line rate. Normally, this clock is offset from the screen such that keyboard IRQs can never fall onto the bad cycle. However, if by chance SKCTL is used to reset POKEY at exactly the right cycle -- which is what this program does -- then every keyboard IRQ will land on that cycle! I wonder how I should document this in the emulator change list... "added emulation for Atari's IRQ/NMI #$&*(up" missdli3.zip Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 12, 2009 Share Posted August 12, 2009 Didn't think about that... but, I've got a nice reasonably compact subroutine written up that will put Pokey into INIT and release it on the exact cycle you specify. I've even taken the trouble to adjust for Refresh cycles. I'll put it up shortly. Quote Link to comment Share on other sites More sharing options...
Heaven/TQA Posted August 12, 2009 Share Posted August 12, 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. 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. I'm still getting a nagging feeling that there's something specific to the timer IRQs that we're missing here. Why don't we see glitching due to SIO interrupts or the keyboard? Both are unpredictable with regard to scan line timing, and you'd think that someone would have noticed it if it happened at all. There are definitely cases where people use DLIs during SIO transfers -- the demo Joyride uses them. At 1,920 IRQs a second you're bound to hit a specific cycle at some point. That goes double if it is also able to mask the VBI. Incidentally, I found out during some cassette emulation work that the kernel does re-init POKEY at times other than just startup. In particular, it also does so when reading a cassette record, immediately after determining baud rate. If you're writing a program that is sensitive to the slow timer phase, you definitely need to re-init it yourself to ensure consistency. My memories concerning Joyride could be bad but where are DLIs while loading? Joyride does have the starfield while loading but I don't see any DLIs, same to Overmind or Total Daze? I only can remember 7 Cities of Gold and Alternate Reality but there you can see glitches while streaming data from discs... Quote Link to comment Share on other sites More sharing options...
ANTIQ Posted August 12, 2009 Share Posted August 12, 2009 Is my vague memory of the OS keyclick routine writing to WSYNC of any use? Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 12, 2009 Share Posted August 12, 2009 That happened in OS A/B from the pre-XL days. It just delayed DLIs on occasion. I don't think it ever suppressed them. On the XL they changed the code to a loop that waited for VCount to change, eliminating the problem. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 12, 2009 Share Posted August 12, 2009 (edited) Here's the subroutine I've developed to release Pokey from INIT status on the cycle of your choosing. It also adjusts for Refresh, so you don't need to work it out yourself. e.g. if you specify Cycle 25, it will adjust it to Cycle 24 since 25 is a Refresh cycle. It uses a delay loop if necessary, and adjusts 2 JMP instructions for the remainder of the required delay. Single-cycle resolution is provided by changing the STA SKCTL instruction to STA SKCTL,X as needed (that takes 5 instead of 4 cycles). Best to put the routine on/near a Page Boundary, it only calculates the low byte of the JMP instructions. Calling procedure: Put the cycle # in X Register. Store 00 in SKCTL. JSR to the routine. skctl = $d20f wsync = $d40a storea_abs = $8D; Machine instruction STA $nnnn storea_absx = $9D; Machine instruction STA $nnnn,X ; ; Routine to release INIT on Pokey at horizontal cycle passed in X ; *= $4000 ; lda #25; Cycle # for first Refresh sta temp1 lda #storea_abs sta set_skctl; Set STA instuction to absolute lda #0 sta adjust ldy #9 adj1 cpx temp1 bcc set_adjust inc adjust lda temp1 clc adc #4 sta temp1 dey bne adj1; Adjust delay for Refresh cycles set_adjust txa sec sbc adjust tax; Put adjusted value back into X ; txa; A=cycle # to Init Pokey lsr a lsr a lsr a; /8 sta del_loop_count txa and #7 lsr a sta temp1 bcc init2 lda #storea_absx sta set_skctl; Set STA instruction to absolute,X init2 lda #<set_skctl sec sbc temp1 sta jump_instruction1 sta jump_instruction2 lda #3; SKCTL Normal operating mode ldx #0 lda #2; VCOUNT wait line # waitvc cmp $d40b bne waitvc lda #3; SKCTL Normal operating mode ldy del_loop_count beq init3 sta wsync cpy 0; 3 cycle NOP - extra cycle needed because last instruction of loop is only 7 cycles on final iteration nop delay_loop cpy 0; 3 dey; 5 bne delay_loop; 8 (7) jump_instruction1=*+1 jmp set_skctl nop nop nop nop set_skctl sta skctl; Put Pokey back in normal operating state rts init3 sta wsync nop; 2 nop; 2 jump_instruction2=*+1 jmp set_skctl; 7 ; ; ; temp1 .byte 0 del_loop_count .byte 0 adjust .byte 0 Edited August 12, 2009 by Rybags Quote Link to comment Share on other sites More sharing options...
NRV Posted August 12, 2009 Share Posted August 12, 2009 great! going to use it.. Have you tested it on any emulator? I wonder how I should document this in the emulator change list... "added emulation for Atari's IRQ/NMI #$&*(up" haha Can we hope "perfect IRQ emulation" from Altirra? ( pleeeeeeeease ) Regards Quote Link to comment Share on other sites More sharing options...
atariksi Posted August 12, 2009 Share Posted August 12, 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. 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. I'm still getting a nagging feeling that there's something specific to the timer IRQs that we're missing here. Why don't we see glitching due to SIO interrupts or the keyboard? Both are unpredictable with regard to scan line timing, and you'd think that someone would have noticed it if it happened at all. There are definitely cases where people use DLIs during SIO transfers -- the demo Joyride uses them. At 1,920 IRQs a second you're bound to hit a specific cycle at some point. That goes double if it is also able to mask the VBI. Incidentally, I found out during some cassette emulation work that the kernel does re-init POKEY at times other than just startup. In particular, it also does so when reading a cassette record, immediately after determining baud rate. If you're writing a program that is sensitive to the slow timer phase, you definitely need to re-init it yourself to ensure consistency. My memories concerning Joyride could be bad but where are DLIs while loading? Joyride does have the starfield while loading but I don't see any DLIs, same to Overmind or Total Daze? I only can remember 7 Cities of Gold and Alternate Reality but there you can see glitches while streaming data from discs... One thing to realize is that low-frequency IRQs have almost zero probability of hitting same cycle as NMI and affecting them assuming routines aren't playing with 54286 directly. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 12, 2009 Share Posted August 12, 2009 I tested the routine by 1> Trace in Atari AsmEd (for some values 0 - 18). 2> Change the routine slightly, put a store #$FE in $D01A instead of STA SKTCL, followed by LDA #0, STA $D01A. Alter the VCOUNT wait so it's just onscreen (VCOUNT=7 or so). Wrote a routine which lets you alter the X parameter with joystick. I haven't tested it under real Timer IRQ conditions, that'll be a bit more exhaustive. Once a sweet spot is found, the routine could probably just be swapped out with a short hard-coded wait + loop + set SKCTL. Quote Link to comment Share on other sites More sharing options...
phaeron Posted August 13, 2009 Share Posted August 13, 2009 great! going to use it.. Have you tested it on any emulator? I wonder how I should document this in the emulator change list... "added emulation for Atari's IRQ/NMI #$&*(up" haha Can we hope "perfect IRQ emulation" from Altirra? ( pleeeeeeeease ) Working on it, but I keep hitting annoying side issues while trying to debug this. Like, for instance, I had no idea that the 6502 executes one instruction after CLI even if the IRQ line has already been long active. I do have POKEY INIT skewing the clocks working, although the timing probably needs adjustment. I also have a sneaky suspicion that there's information about this out there somewhere and I'd know about it if I could read Polish.... The newest update in our continuing interrupt WTF is that enabling missile DMA decreases the magic number of required delay cycles by one and enabling player+missile DMA decreases it by five. This means that the critical event happens after P/M DMA, which occurs on cycles 0 and 2-5. It's looking like the critical event is the point at which the IRQ interrupt sequence ends relative to when NMI is pulled (either cycle 0/1, relative to cycle . 9 cycles after WSYNC puts this sequence at cycles 0-6, and with P/M DMA active you would have to start the sequence earlier to finish it at the same time. It also explains Rybags' single scan line case, because in that case there is one cycle of display list DMA at cycle 0. Finally, it turns out that BRK also works to trigger this problem -- which completely rules out POKEY. Perhaps it's actually WDC that we should blame. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 13, 2009 Share Posted August 13, 2009 Might still be an Antic problem, but I did try with 7-cycle instructions and it didn't worry it. Knowing how long Antic holds NMI low for would help... and also if there's any official specs that describe it, although the common word seems to be that NMI sources should hold it low until the "peripheral" is serviced/cleared. Quote Link to comment Share on other sites More sharing options...
atariksi Posted August 13, 2009 Share Posted August 13, 2009 From the CPU perspective, kind of. HALT can cause an Interrupt to be seen a cycle or more later. I don't think that's a problem though. Where we're having trouble is around the end of the scanline, so far as our Cycle numbering is concerned. We can have next to no DMA in that area but still have problems. I think that if we can align the Timer IRQ to an odd cycle, then it might eliminate any cases of DLIs being missed in "big mode" cases, or "single scanline mode" cases. Remembering here that since the divisor is 28, it will always remain aligned to either an odd or even cycle. Overall with or without the NMI suppressing cycle, it's more problematic in having a high frequency IRQ running and a whole bunch of DLIs since IRQ latency will be greatly impacted by the DLIs. They have to be interleaved to begin with anyway. Better off using an IRQ that simulates the DLI and for audio playback. Quote Link to comment Share on other sites More sharing options...
phaeron Posted August 14, 2009 Share Posted August 14, 2009 Alright, at the risk of beating a dead horse, I'm going to announce what I believe to be the real condition, based on a lot of testing with various delays, mode lines, and interrupting methods: >> The last cycle of the seven-cycle IRQ/BRK sequence must land on exactly cycle 10 to block an NMI. << The following sequence should accomplish this once, regardless of any DMA (assuming no intervening interrupts and no display list or P/M DMA on the scan line): STA WSYNC ;clear existing DMA cycles STA WSYNC ;sync to cycle 105 PHA ;*, 105, 106 PLA ;107, 108, 109, 110 PHA ;111, 112, 113 PLA ;0, 1, 2, 3 BRK ;4, 5, 6, 7, 8, 9, 10 Additional factors: You must ensure that the starting cycle for your delay is known exactly. STA WSYNC in uncontrolled conditions is not enough as you still have three cycles of uncertainty: a possible DMA cycle immediately after STA WSYNC, a possible playfield DMA cycle at 105, and a possible refresh DMA cycle at 106. For each cycle of DMA in cycles 0-8 (missile, display list, players, display list LMS) you must initiate the delay or interrupt sequence one cycle earlier for it to hit at the right time. Playfield DMA cycles starting at cycle 12 don't matter. The instruction pattern at the beginning of the IRQ routine doesn't matter. If you are initiating an immediate IRQ by CLI with the IRQ line active, the 6502 will execute one more instruction before initiating the IRQ sequence. If you are initiating an immediate IRQ by writing IRQEN with a POKEY interrupt active, the 6502 will execute two more instructions before initiating the IRQ sequence, at least if the next instruction is short (two cycles). If you are strobing STIMER to sync a 16-bit, 1.79MHz timer (atariksi's example), the write needs to happen 7 cycles in advance of the desired interrupt sequence start. This implies that all timers roll over immediately after STIMER instead of waiting one period. What all of this also implies is that you cannot reliably avoid this problem with a 64KHz clock. The reason is that, while you can align the clock itself to fire the IRQ on an odd cycle, you're still screwed if instruction completion delays the 6502's interrupt response so that it lands on an even boundary. Therefore, either the 15KHz or the 1.79MHz clocks are the way to go for interference-free POKEY timers. (Which, embarrassingly, is the way the OP was doing it before I sent him off on this particular tangent by suggesting the 64KHz clock. Oops.) There is one pertinent case that I haven't tested, which is if playfield DMA is occurring on cycle 10. This can only occur on a mode 2-7 line with wide playfield fetch that has been shortened to one scan line. It's difficult to test this case, though. Quote Link to comment Share on other sites More sharing options...
Irgendwer Posted August 14, 2009 Share Posted August 14, 2009 From the CPU perspective, kind of. HALT can cause an Interrupt to be seen a cycle or more later. I don't think that's a problem though. If the CPU is stopped by HALT, when does ANTIC uses the bus/ how does ANTIC know the CPU has finished it's instruction? Does ANTIC wait seven static cycles? Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 14, 2009 Share Posted August 14, 2009 One possible solution if we want to use 64 KHz mode is to test if we're interrupting a DLI, within our Timer routine. VCount only having 2-line resolution doesn't help us out much there, though. When V-Scrolling is thrown into the mix, it confuses things even more. The other solution might be similar to "Stable rasters" on the C-64... have a DLI setup a bit earlier. Have it idle for a specific time, even performing the duties of the Timer IRQ for that period. That guarantees the next DLI can fire off. In the event that the first DLI is suppressed, we should rest assured that the second one isn't suppressed. A bit kludge-o-matic, but workable. The exact solution needed would be different for the specific game/demo we're working on. Quote Link to comment Share on other sites More sharing options...
Rybags Posted August 14, 2009 Share Posted August 14, 2009 From the CPU perspective, kind of. HALT can cause an Interrupt to be seen a cycle or more later. I don't think that's a problem though. If the CPU is stopped by HALT, when does ANTIC uses the bus/ how does ANTIC know the CPU has finished it's instruction? Does ANTIC wait seven static cycles? HALT is immediate, it doesn't matter what the CPU is doing. RDY takes one cycle, that's why we usually get the "free" cycle 104, in fact the first cycle of a subsequent instruction occurs straight after a STA WSYNC. 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.