DMC DMA during sprite DMA on Visual2A03

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
DMC DMA during sprite DMA on Visual2A03
by on (#95464)
Using the Visual2A03 and about three hours on my computer to process >1000 CPU cycles, I was able to create a program that started a DMC sample which required fetching a new byte coincident with an in-progress sprite DMA.

The Visual2A03 'program'

Equivalent code:
Code:
.org 0
CLI
LDA #$C0
STA $4017
LDA #$01
STA $4013
LDA #$8F
STA $4010
LDA #$10
STA $4015
LDA #$01
STA $4014
STA $4014
forever: BPL forever

As I was going through this I first thought I'd only need to wait for one sprite DMA completion since the DMC is set for a period of 54 cycles per bit or 432 cycles between DMAs. That turned out not to be the case because I forgot that I would have to wait both the currently-in-progress 'silence' byte and my newly DMA'd first byte to pass through the DMC output stage before the DMC would fetch another byte using DMA. I decided to just do two back-to-back sprite DMAs, rather than play with other code to delay a single sprite DMA.

Here is the log output from the Visual2A03 'program'...cut down significantly. The interesting cycle is cycle 822. This log shows that the DMC DMA happens *right in the middle of* the sprite DMA without one impacting the other in any way [sprite data and DMC data are not 'clobbered']. Cycle 823 is the CPU driving the address bus for one cycle, presumably because the sprite DMA logic needs two cycles per transfer, and since it was held off, it has nothing to put on the bus until cycle 824.

Another interesting thing...I'd read that the DMC DMA always takes 4 cycles. But starting at cycle 38 c_rdy (the internal RDY to the 6502) is pulled low and the CPU is held off for what appears to be 3 cycles with the DMC fetch from $C000 being the last of the three. [Not 4?]

Code:
cycle   ab   db   rw   Fetch   pc   a   x   y   s   p   c_rdy
31   0012   8d   1   STA Abs   0012   10   c0   00   bd   nv-Bdizc   1
31   0012   8d   1   STA Abs   0012   10   c0   00   bd   nv-Bdizc   1
32   0013   15   1      0013   10   c0   00   bd   nv-Bdizc   1
32   0013   15   1      0013   10   c0   00   bd   nv-Bdizc   1
33   0014   40   1      0014   10   c0   00   bd   nv-Bdizc   1
33   0014   40   1      0014   10   c0   00   bd   nv-Bdizc   1
34   4015   40   0      0015   10   c0   00   bd   nv-Bdizc   1
34   4015   10   0      0015   10   c0   00   bd   nv-Bdizc   1
35   0015   a9   1   LDA #   0015   10   c0   00   bd   nv-Bdizc   1
35   0015   a9   1   LDA #   0015   10   c0   00   bd   nv-Bdizc   1
36   0016   01   1      0016   10   c0   00   bd   nv-Bdizc   1
36   0016   01   1      0016   10   c0   00   bd   nv-Bdizc   1
37   0017   8d   1   STA Abs   0017   01   c0   00   bd   nv-Bdizc   1
37   0017   8d   1   STA Abs   0017   01   c0   00   bd   nv-Bdizc   1
38   0018   14   1      0018   01   c0   00   bd   nv-Bdizc   1
38   0018   14   1      0018   01   c0   00   bd   nv-Bdizc   0
39   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   0
39   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   0
40   c000   00   1      0019   01   c0   00   bd   nv-Bdizc   0
40   c000   00   1      0019   01   c0   00   bd   nv-Bdizc   0
41   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   1
41   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   1
42   0019   40   1      0019   01   c0   00   bd   nv-Bdizc   1
42   0019   40   1      0019   01   c0   00   bd   nv-Bdizc   1
43   4014   40   0      001a   01   c0   00   bd   nv-Bdizc   1
43   4014   01   0      001a   01   c0   00   bd   nv-Bdizc   0
44   001a   8d   1   STA Abs   001a   01   c0   00   bd   nv-Bdizc   0
44   001a   8d   1   STA Abs   001a   01   c0   00   bd   nv-Bdizc   0
45   001a   8d   1   STA Abs   001b   01   c0   00   bd   nv-Bdizc   0
45   001a   8d   1   STA Abs   001b   01   c0   00   bd   nv-Bdizc   0
46   0100   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
46   0100   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
47   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
47   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
48   0101   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
48   0101   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
49   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
49   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
50   0102   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
50   0102   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
51   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
51   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
...
554   01fe   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
554   01fe   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
555   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
555   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
556   01ff   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
556   01ff   00   1   BRK   001b   01   c0   00   bd   nv-Bdizc   0
557   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
557   2004   00   0   BRK   001b   01   c0   00   bd   nv-Bdizc   0
558   001a   8d   1   STA Abs   001b   01   c0   00   bd   nv-Bdizc   1
558   001a   8d   1   STA Abs   001b   01   c0   00   bd   nv-Bdizc   1
559   001b   14   1      001b   01   c0   00   bd   nv-Bdizc   1
559   001b   14   1      001b   01   c0   00   bd   nv-Bdizc   1
560   001c   40   1      001c   01   c0   00   bd   nv-Bdizc   1
560   001c   40   1      001c   01   c0   00   bd   nv-Bdizc   1
561   4014   40   0      001d   01   c0   00   bd   nv-Bdizc   1
561   4014   01   0      001d   01   c0   00   bd   nv-Bdizc   0
562   001d   10   1   BPL    001d   01   c0   00   bd   nv-Bdizc   0
562   001d   10   1   BPL    001d   01   c0   00   bd   nv-Bdizc   0
563   001d   10   1   BPL    001e   01   c0   00   bd   nv-Bdizc   0
563   001d   10   1   BPL    001e   01   c0   00   bd   nv-Bdizc   0
564   0100   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
564   0100   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
565   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
565   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
566   0101   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
566   0101   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
567   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
567   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
...
818   017f   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
818   017f   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
819   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
819   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
820   0180   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
820   0180   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
821   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
821   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
822   c001   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
822   c001   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
823   001d   10   1   BPL    001e   01   c0   00   bd   nv-Bdizc   0
823   001d   10   1   BPL    001e   01   c0   00   bd   nv-Bdizc   0
824   0181   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
824   0181   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
825   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
825   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
826   0182   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
826   0182   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
827   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
827   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
...
1074   01fe   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1074   01fe   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1075   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1075   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1076   01ff   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1076   01ff   00   1   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1077   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1077   2004   00   0   BRK   001e   01   c0   00   bd   nv-Bdizc   0
1078   001d   10   1   BPL    001e   01   c0   00   bd   nv-Bdizc   1
1078   001d   10   1   BPL    001e   01   c0   00   bd   nv-Bdizc   1
1079   001e   fe   1      001e   01   c0   00   bd   nv-Bdizc   1
1079   001e   fe   1      001e   01   c0   00   bd   nv-Bdizc   1
1080   001f   00   1      001f   01   c0   00   bd   nv-Bdizc   1
1080   001f   00   1      001f   01   c0   00   bd   nv-Bdizc   1
1081   001d   10   1   BPL    001d   01   c0   00   bd   nv-Bdizc   1
1081   001d   10   1   BPL    001d   01   c0   00   bd   nv-Bdizc   1
1082   001e   fe   1      001e   01   c0   00   bd   nv-Bdizc   1
1082   001e   fe   1      001e   01   c0   00   bd   nv-Bdizc   1
1083   001f   00   1      001f   01   c0   00   bd   nv-Bdizc   1
1083   001f   00   1      001f   01   c0   00   bd   nv-Bdizc   1
Re: DMC DMA during sprite DMA on Visual2A03
by on (#95643)
cpow wrote:
...

Forever Alone? :(

by on (#95649)
You need to annotate the long tables of numbers, say what's significant and why.

by on (#95650)
Dwedit wrote:
You need to annotate the long tables of numbers, say what's significant and why.

My annotation was above the long table. :D

cpow wrote:
The interesting cycle is cycle 822. This log shows that the DMC DMA happens *right in the middle of* the sprite DMA without one impacting the other in any way [sprite data and DMC data are not 'clobbered']. Cycle 823 is the CPU driving the address bus for one cycle, presumably because the sprite DMA logic needs two cycles per transfer, and since it was held off, it has nothing to put on the bus until cycle 824.

Another interesting thing...I'd read that the DMC DMA always takes 4 cycles. But starting at cycle 38 c_rdy (the internal RDY to the 6502) is pulled low and the CPU is held off for what appears to be 3 cycles with the DMC fetch from $C000 being the last of the three. [Not 4?]

by on (#95651)
I heard from that other thread that DMC DMA takes 4 cycles normally, 3 if it happens on a CPU write cycle, and 2 if it happens during sprite DMA. Seems consistent with Blargg's tests. Then a couple of other rare cases where it happens on the last or second-last cycle of Sprite DMA.

But games generally don't care if you don't emulate DMC cycle theft. Even games that are picky about the DMC channel working correctly (Fire Hawk, Mig 29 Soviet Fighter) run with no glitches if the DMC channel isn't stealing any cycles.

Konami games on the other hand need DMC cycle theft to be accurate. Konami games use a random number generator that repeatedly runs until Vlbank happens. So any cycle that's wrong will give a different RNG result.

Now we just need to find the initial state of the DMC counters. I suspect it is random. I base that on the demo of Blades of Steel. It plays differently every time you power on the NES. Since DMC cycle theft works differently depending on whether or not it hits a CPU write cycle, that can throw off the RNG easily. An inconsistent PPU starting state will also throw off the demo, so it's hard to tell why the game is so unpredictable.

by on (#95686)
cpow wrote:
This log shows that the DMC DMA happens *right in the middle of* the sprite DMA without one impacting the other in any way [sprite data and DMC data are not 'clobbered'].

I must be misunderstanding what you're saying. The CPU cannot possibly read two different addresses at the same time. The CPU only has one address bus. So obviously one of them has to get clobbered. I agree that neither of the operations is "stalled" if that's what you meant (which was discovered in this thread), but only _one_ of the addresses (either sprite address or DMC address) can be driven on the CPU's address bus. You can't have both. :) So either the DMC read gets sprite data or the sprite read gets DMC data. Those are your only choices.

Can you clarify what you meant?

by on (#95687)
No clobbering anywhere, sprite DMA just gets interrupted to do the DMC DMA.

But let's see here...
Sprite DMA begins reading bytes at cycle 564 and finishes before cycle 1078.
514 cycles total. So that's 256 reads due to sprite DMA, 256 writes due to sprite DMA, one read due to DMC, and one dummy read at address 1D (program counter) for some reason.
So Visual2A03 says it gets interrupted in the middle of the sprite DMA transfer. Nothing gets corrupted. All reads and writes happen properly. Just one extra read at the program counter.

by on (#95698)
Interesting. Can you get two DMC DMAs to happen during one sprite DMA using playback speed $F? I'd love to be able to close this out by leaving it at "Each DMC DMA extends sprite DMA by two cycles", but I need this one final validation before I can commit to that wording.

by on (#95703)
Dwedit wrote:
No clobbering anywhere, sprite DMA just gets interrupted to do the DMC DMA.

Exactly. That's why I got excited. :D I'd only ever seen it assumed that one or the other gets clobbered. Not true!
Dwedit wrote:
But let's see here...
and one dummy read at address 1D (program counter) for some reason.

Probably because, like I said in the other thread, the sprite DMA read/write/read/write beat is maintained since it is still going on, but the DMC DMA only needs to read, so when it's done with its read in the cycle where the sprite DMA would have done a read, there's nothing for either of the two 'controllers' to do in the next bus cycle, so the bus is yielded back to the CPU which puts out its last address as a read. Most likely due to these transistors (centered in the image) which control which of the internal AB's go to the AB pins on the 2A03. [If you click on some of the lines around there you'll find ab_use_spr_w, ab_use_spr_r, ab_use_pcm, ab_use_cpu].
Dwedit wrote:
So Visual2A03 says it gets interrupted in the middle of the sprite DMA transfer. Nothing gets corrupted. All reads and writes happen properly. Just one extra read at the program counter.

Correct.
tepples wrote:
Interesting. Can you get two DMC DMAs to happen during one sprite DMA using playback speed $F? I'd love to be able to close this out by leaving it at "Each DMC DMA extends sprite DMA by two cycles", but I need this one final validation before I can commit to that wording.

I'll work on that. Should be fairly easy.

by on (#95706)
The following Visual2A03 program was used to capture sprite DMA being interrupted by two consecutive DMC DMA fetches at DMC period $F. Here's the relevant portions of the logged output:
Code:
cycle   ab   db   rw   Fetch   pc   a   x   y   s   p   c_rdy
820   0200   a0   1   LDY #   009e   02   c0   00   bd   nv-Bdizc
820   0200   a0   1   LDY #   009e   02   c0   00   bd   nv-Bdizc
821   2004   a0   0   LDY #   009e   02   c0   00   bd   nv-Bdizc
821   2004   a0   0   LDY #   009e   02   c0   00   bd   nv-Bdizc
822   c001   e1   1   SBC (zp,X)   009e   02   c0   00   bd   nv-Bdizc
822   c001   e1   1   SBC (zp,X)   009e   02   c0   00   bd   nv-Bdizc
823   009d   10   1   BPL    009e   02   c0   00   bd   nv-Bdizc
823   009d   10   1   BPL    009e   02   c0   00   bd   nv-Bdizc
824   0201   a1   1   LDA (zp,X)   009e   02   c0   00   bd   nv-Bdizc
824   0201   a1   1   LDA (zp,X)   009e   02   c0   00   bd   nv-Bdizc
825   2004   a1   0   LDA (zp,X)   009e   02   c0   00   bd   nv-Bdizc
825   2004   a1   0   LDA (zp,X)   009e   02   c0   00   bd   nv-Bdizc

The sprite DMA starts at cycle 820. The first DMC DMA is at cycles 822-823. The sprite RAM being fetched and the DMC RAM being fetched have been filled with different breadcrumbs so we can see that the fetches occur correctly. [Sprite DMA gets $a0 then $a1 while DMC DMA gets $e1 in between].
Code:
cycle   ab   db   rw   Fetch   pc   a   x   y   s   p   c_rdy
1252   02d7   a7   1   unknown   009e   02   c0   00   bd   nv-Bdizc
1252   02d7   a7   1   unknown   009e   02   c0   00   bd   nv-Bdizc
1253   2004   a7   0   unknown   009e   02   c0   00   bd   nv-Bdizc
1253   2004   a7   0   unknown   009e   02   c0   00   bd   nv-Bdizc
1254   c002   e2   1   unknown   009e   02   c0   00   bd   nv-Bdizc
1254   c002   e2   1   unknown   009e   02   c0   00   bd   nv-Bdizc
1255   009d   10   1   BPL    009e   02   c0   00   bd   nv-Bdizc
1255   009d   10   1   BPL    009e   02   c0   00   bd   nv-Bdizc
1256   02d8   a8   1   TAY   009e   02   c0   00   bd   nv-Bdizc
1256   02d8   a8   1   TAY   009e   02   c0   00   bd   nv-Bdizc
1257   2004   a8   0   TAY   009e   02   c0   00   bd   nv-Bdizc
1257   2004   a8   0   TAY   009e   02   c0   00   bd   nv-Bdizc

The sprite DMA is still going on, and there's a second DMC DMA interruption of it at cycles 1254-1255. Here again the breadcrumbs show the memory properly being fetched for each operation. [Sprite DMA gets $a7 then $a8 while DMC DMA gets $e2 in between].
Code:
cycle   ab   db   rw   Fetch   pc   a   x   y   s   p   c_rdy
1334   02ff   af   1   unknown   009e   02   c0   00   bd   nv-Bdizc
1334   02ff   af   1   unknown   009e   02   c0   00   bd   nv-Bdizc
1335   2004   af   0   unknown   009e   02   c0   00   bd   nv-Bdizc
1335   2004   af   0   unknown   009e   02   c0   00   bd   nv-Bdizc
1336   009d   10   1   BPL    009e   02   c0   00   bd   nv-Bdizc
1336   009d   10   1   BPL    009e   02   c0   00   bd   nv-Bdizc
1337   009e   fe   1      009e   02   c0   00   bd   nv-Bdizc
1337   009e   fe   1      009e   02   c0   00   bd   nv-Bdizc
1338   009f   00   1      009f   02   c0   00   bd   nv-Bdizc
1338   009f   00   1      009f   02   c0   00   bd   nv-Bdizc

The sprite DMA completes and the CPU resumes at cycle 1336, so the sprite DMA has taken 516 cycles total, with two DMC DMA interruptions.

by on (#95709)
Doesn't it break blargg's dmc dma test roms, regarding the extra cycle?

by on (#95712)
Zepper wrote:
Doesn't it break blargg's dmc dma test roms, regarding the extra cycle?

The test ROMs I think you're referring to use DMC period $0 which would not generate more than one potential DMC DMA fetch during a sprite DMA.

by on (#95728)
tepples wrote:
Interesting. Can you get two DMC DMAs to happen during one sprite DMA using playback speed $F? I'd love to be able to close this out by leaving it at "Each DMC DMA extends sprite DMA by two cycles", but I need this one final validation before I can commit to that wording.


Closed. Explanation is three posts above. 8)
Re: DMC DMA during sprite DMA on Visual2A03
by on (#158278)
I was trying to rerun the test from the first post, but something seems to be wrong in Visual2A03. The test writes $01 to $4014 but the DMA fetches are happening from $00, $01, ... (not from $100, $101, ... like they should). Has OAM DMA been broken in Visual2A03 at some point?

NOTE: Looks like expert.html has been removed, so have to replace expert.html => index.html in the URL: http://www.qmtpro.com/~nes/chipimages/v ... more=c_rdy