DMC DMA during sprite DMA on Visual2A03

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

DMC DMA during sprite DMA on Visual2A03

Post by cpow »

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: Select all

.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: Select all

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
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Re: DMC DMA during sprite DMA on Visual2A03

Post by cpow »

cpow wrote:...
Forever Alone? :(
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

You need to annotate the long tables of numbers, say what's significant and why.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

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?]
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

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.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

Post by jwdonal »

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?
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

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.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

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.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

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.
Last edited by cpow on Sat Jan 26, 2013 12:31 pm, edited 1 time in total.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

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: Select all

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: Select all

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: Select all

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.
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

Doesn't it break blargg's dmc dma test roms, regarding the extra cycle?
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

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.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

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)
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: DMC DMA during sprite DMA on Visual2A03

Post by thefox »

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
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
Post Reply