Okay, I've run this through my head a few times now, and I can't find any problems with it. Someone check my logic.

1) According to Disch's recent tests, DMC DMA always attempts to engage on an odd cycle.2) It is already well known that the first cycle after an OAM DMA is always an even cycle.

By performing an OAM DMA, then cycle-timing to ensure that all reads from $4016/$4107 occur on even cycles, shouldn't it be possible to ensure that the controller reads are never hijacked? The DMC generates at most one DMA every ~400 cycles, so the alignment after a DMC DMA is irrelevant - the entire routine should be able to complete before a second one can occur.

I don't have the hardware to test it myself (PAL region), but if nobody can find an obvious reason why it won't work I can write a test ROM for others to try.

... I'm pretty certain you wouldn't lose significant vblank time...? Unless I'm misunderstanding what Rahsennor is saying, it sounds like it should be possible to just put careful odd-number-of-cycle delays in your reading routine to make it such that the reads from $4016/4017 wouldn't be on the relevant even/odd phase to cause the glitch, and so it should only take one read through?

Only if the total amount of vblank code actually takes more than ~20 scanlines (which is usually not the case, to maintain NTSC compatibility). BTW there might be other "windows" in which the OAM DMA can be done (instead of just the first 20 scanlines). All that has been tested is that if the DMA was done slightly after 20 scanlines, the update got corrupted. (This also seemed to cause the strange results in blargg's OAM tests on PAL NES -- after I forced all reads to happen right after start of vblank, the tests passed.)

Then again, the DPCM glitch also doesn't seem to affect PAL NES in the first place.

lidnariq wrote:

... I'm pretty certain you wouldn't lose significant vblank time...? Unless I'm misunderstanding what Rahsennor is saying, it sounds like it should be possible to just put careful odd-number-of-cycle delays in your reading routine to make it such that the reads from $4016/4017 wouldn't be on the relevant even/odd phase to cause the glitch, and so it should only take one read through?

Yeah, assuming one would just be reading the values and storing them for later processing, let's say 8 CPU cycles per read, that's only ~64 cycles wasted (~100 at most).

That'll break on PAL, as sprite DMA needs to happen within the first 20 scanlines

Even if your engine is designed to take advantage of PAL's longer vblank when available, as RHDE is, I imagine that "If PAL NES then do OAM first else do OAM last" would handle all cases. Incidentally, so would reading the controller in a DMC IRQ handler, if you're using it as a crude raster timer.

Yeah, PAL vblank is so long that reading the controllers during that time shouldn't make any difference... Just take care of the sprite DMA and controller reading right away, while on NTSC you'd do both these things last, with the controller part possibly spilling into the visible frame.

Yes, the idea was to do the DMA last and let the controller reading spill over into the visible frame. Gives you something to do while you wait for sprite 0.

I wasn't aware that there was any special constraint on OAM DMA on PAL systems. I just did it first out of habit. It only takes 11 cycles to decide whether to do the DMA first or last, assuming you have a flag in the top two bits of a zero page variable. Or if you can make sure your NMI handler always takes an even number of cycles (tricky, but not as bad as making it constant-time) you can just do the DMA first and the controller reading last and it should work fine in either case.

There's also the possibility of using this trick to perform VRAM reads, which you'd want to do inside vblank anyway. In fact, that might be a better way to test it, since you have full control over the contents of the nametables/pattern tables.

Slapped together the simplest test I could come up with, and to my surprise, it works perfectly in Nestopia... but on odd cycles instead of even. None of the other emulators I tested emulate DMC conflicts at all. Can anyone here try it out and tell me what it does on real hardware?

I made two versions of the test, one that always reads on even cycles, and one that always reads on odd cycles. The test is as simple as it gets: it plays a DMC loop at the highest rate and runs the polling code in a tight loop, with rendering off. If right is pressed on either controller, the screen goes white. Otherwise the screen should stay black. This assumes a standard controller that pads with all 1s, so that glitched reads always result in right being pressed.

Tested on PAL hardware with nes-004 controller for a couple of minutes on each test. Both work 100% of the times tested, assuming that the only thing to test for is the screen to go white. If i raise the tv volume quite a bit, i hear a bright tone that's interrupted for as long as i hold right pressed.

Who is online

Users browsing this forum: No registered users and 6 guests

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum