APU DMC ($4011 Direct Load vs. Delta-counter) Question

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
APU DMC ($4011 Direct Load vs. Delta-counter) Question
by on (#57760)
Does writing to $4011 write to the delta-counter register?

Here's a scenario:

1) System is reset.
2) The user writes $0F (arbitrary value) to $4011 one time
3) A DMC sample playback is started by setting up the sample address and length and then enabling the DMC channel via $4015.4.
4) The least significant bit of the first sample byte read is '1'.

Which of the following occurs?:

A) The delta-counter adds 2 to $0F making the new delta-counter value = $11.

B) The delta-counter adds 2 to $00 making the new delta-counter value = $02. Note that the original delta-counter value is $00 because the system was just reset. (This option basically means that $4011 does not write to the delta-counter itself but directly to the final DMC output register instead.)

I think I know what the answer is but I want to be sure.

THANKS!! :)

by on (#57763)
It's scenario A)
hmmm
by on (#57766)
Hmmm...I was actually hoping for option B. LOL.

Option 'A' seems weird to me because the delta-counter is reading each bit shifted out from the sample bytes (and performing the +/- 2 operation) at the timer's clocking rate (which is based on the frequency index specified in $4010.[3:0]). But the CPU is running at ~1.79MHz all the time with write operations to $4011 occurring based on that clock rate.

So the delta-counter is operating at one rate and the CPU is writing to $4011 at another rate. So in hardware how am I supposed to write to the same register at 2 different clock rates? Flip-flops only have one clock input and one clock-enable input. You can't assign to the same reigster at two different clock rates. It just doesn't make sense. I could "emulate" the effect of option A but it isn't going to be pretty.

I could totally be mis-understanding how the DMC unit is supposed to operate but every single test ROM and commercial game that I've tried sounds absolutely perfect (when compared to Nestopia's output and a real NES). I was just about to post some audio/video clips of it in operation because I thought it was pretty much done. But I guess not....??

Actually, I don't think I have any test ROMs that first write to $4011 and then playback samples so maybe something like that actually would not sound right with my implementation.... :(

Any help?

Thanks! :)

by on (#57776)
In fact I don't think the CPU writes to $4011 when DMC is playing. It just increment/decrement the counter by 2 at regular intervals, and when there is a need for it pause the CPU to read one byte from the data bus. Writing to $4011 just happens to force the counter to take a new value.
I could be wrong tough.

by on (#57778)
Both STA $4011 and each bit of a compressed waveform change the current DAC value. But most games do not overlap cycle-timed STA $4011 and playback of compressed waveforms. Either the CPU does STA $4011 once at the start of the program and then just lets samples occasionally saturate against the $00 and $7E rails, or the CPU does STA $4011 only once at the start of each waveform.

The only program I know of that overlaps STA $4011 and compressed waveform playback is blargg's saw demo.
OK
by on (#57793)
OK, this is really interesting. I would love to see how they really implemented this in the original NES. I have a feeling this may be an "old technology meets new technology issue". I'll see what I can do - I think I might have an idea of how Nintendo got this to work...

Tepples, thanks _very_ much for the link to Blargg's ROM with overlapping writes. It will be invaluable during my testing to get this working!

Pz!

Jonathon

by on (#57796)
I imagine they just let the hardware do whatever it felt like doing when DMC playback and CPU were both modifying the delta counter at the same time. So if I were implementing these in hardware, I'd first just ignore the issue and see what it did. It has to do something, and that something may be correct. I'm not sure I've even determined what happens in this case on the NES.

by on (#57810)
Or it's just a synchronous up/down counter with an asynch load.

I'd guess it's something like this:
Code:
module dmc_counter(clk, ena, dir, load, d, q);
  input clk, ena, dir, load;
  input [7:0] d;
  output reg [7:0] q;

  always @(posedge clk)
     if (load)
       q <= d;
     else if (ena)
       else if (dir)
         q <= q + 1'b1;
       else
         q <= q - 1'b1;
endmodule

with clk = 1.789MHz, ena is count_en, load is ((addr == 16'h4011) && ~rw)), dir is the appropriate bit of the cur_sample reg, d is dout from the CPU, q is the dac value


[If you're going to indent things, put it in a [code] element. -- MOD]

by on (#57896)
Rumor has it the prototype famicom was a bunch of cards in a card cage, 3 or 4 each for cpu and ppu. They would have had a real mos 6502(with decimal mode) on one of the cpu cards, and also had the entire sound generation system done up in discrete logic. I'm guessing a 74xx 8 bit delta counter with synchronous count, async reload was really used there, and later merged into the n2a03 final chip design (though it lost a bit somewhere).

Challenge: build a 6502 based pcb which exactly emulates the nes n2a03, including serial stuff and all 5 sound channels (with the exception that decimal mode works, since selectively disabling that is nearly impossible). bonus points for posting schematics. More bonus points if you figure out how to emulate the serial bug when reading joysticks while dmc is running (if you manage to do it in a relatively simple way, chances are the real hardware had that same flawed design, which was fixed in the pal n2a07 (and maybe in the n2a03 rev H? can someone test that?); occam's razor strikes again.)

LN

by on (#57898)
Wow that'd be neat to see... I have some 6502s spared altough it still sounds like a giant headeche to re-do all of it (it would be impossible to recreate the PPU with only discrete logic chips I think).

by on (#57915)
The serial bug is actually trivial to do with a real 6502. The DMC dma just pulls RDY down for 4 cycles, and does it's write on the 4th. The CPU ignores RDY for writes, for reads, it holds the address lines stable, and pauses internal operations (this'd be for adding wait states, for instance)

If DMC hits before the second half of the read from $4016 or $4017, that address stays on the bus for 3 cycles, so the APU hardware sees 3 reads.

The messiest part of the PPU would probably be the sprite ram I think. The rest is mostly some latchable counters and misc logic. It'd be a ton of chips, but theoretically doable, though the speed might not be perfect.

Technically, you could do a bit of a number at disabling decimal mode with some sneaky logic. The Real Thing usually has a SYNC signal, which is asserted when the CPU is fetching an opcode. Feed a flag from comparator that looks for a SED instruction into an AND gate with SYNC, and have that control a 2:1 mux that provides either the value from memory or CLD. It wouldn't be perfect, as it won't catch sneaky tricks with PLP or RTI, but it'd go a fair ways.

by on (#57938)
Image
update
by on (#57945)
So I tested with Blargg's apps that tepples pointed me to. Only one of them worked. And that was the one that didn't do overlapping $4011 writes and sample reads. Haha. So after fixing my DMC to work like scenario (A) all of Blargg's test apps work now! I'm *VERY* excited! :-D

Thanks everyone for your help! I will be posting some audio/video to my site very soon. It might be a couple more days though - I haven't been getting much sleep lately and need some rest. *yawwwn*

Pz!

Jonathon

by on (#57967)
kyuusaku wrote:
Image

Cool!