APU DMC: Difference between revisions
(added pitch table stolen from www.2ao3.org) |
(turned headings into real headings) |
||
Line 51: | Line 51: | ||
The '''sample buffer''' either holds a single 8-bit sample byte or is empty. It is filled by the reader and can only be emptied by the output unit; once loaded with a sample byte it will be played back. | The '''sample buffer''' either holds a single 8-bit sample byte or is empty. It is filled by the reader and can only be emptied by the output unit; once loaded with a sample byte it will be played back. | ||
=== Pitch table === | |||
For NTSC: | |||
+-------+--------+-----------------------+--------------------+ | +-------+--------+-----------------------+--------------------+ | ||
| Speed | Period | Approx. Sampling Rate | Approx. Note | | | Speed | Period | Approx. Sampling Rate | Approx. Note | | ||
Line 89: | Line 89: | ||
| $F | $036 | 33,143.935190 Hz | C11 -17.8829 cents | | | $F | $036 | 33,143.935190 Hz | C11 -17.8829 cents | | ||
+-------+--------+-----------------------+--------------------+ | +-------+--------+-----------------------+--------------------+ | ||
=== Memory reader === | |||
When the sample buffer is emptied, the memory reader fills the sample buffer with the next byte from the currently playing sample. It has an address counter and a bytes remaining counter. | When the sample buffer is emptied, the memory reader fills the sample buffer with the next byte from the currently playing sample. It has an address counter and a bytes remaining counter. | ||
Line 103: | Line 104: | ||
At any time, if the interrupt flag is set, the [[CPU|CPU's IRQ line]] is ''continuously'' asserted until the interrupt flag is cleared. | At any time, if the interrupt flag is set, the [[CPU|CPU's IRQ line]] is ''continuously'' asserted until the interrupt flag is cleared. | ||
=== Output unit === | |||
The output unit continuously outputs a 7-bit value to the [[APU Mixer|mixer]]. It contains an 8-bit right shift register, a bits-remaining counter, a 7-bit delta-counter, and a silence flag. | The output unit continuously outputs a 7-bit value to the [[APU Mixer|mixer]]. It contains an 8-bit right shift register, a bits-remaining counter, a 7-bit delta-counter, and a silence flag. |
Revision as of 16:27, 29 April 2010
The NES APU's delta modulation channel (DMC) can output 1-bit delta-encoded samples or can have its 7-bit counter directly loaded, allowing flexible manual sample playback.
The DMC channel contains the following: memory reader, interrupt flag, sample buffer, timer, output unit, 7-bit counter.
Timer | v Reader ---> Buffer ---> Output ---> Counter ---> (to mixer)
$4010 | IL--.FFFF | Flags and frequency (write) |
bit 7 | I--- ---- | IRQ enabled flag. If clear, the interrupt flag is cleared. |
bit 6 | -L-- ---- | Loop flag |
bits 3-0 | ---- RRRR | Rate indexRate $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $A $B $C $D $E $F ------------------------------------------------------------------------------ NTSC 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54 PAL 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50 |
$4011 | -DDD.DDDD | Direct load (write) |
bits 6-0 | -DDD DDDD | The counter is loaded with D. If a sample is currently playing, the counter is occasionally not changed properly. |
$4012 | AAAA.AAAA | Sample address (write) |
bits 7-0 | AAAA AAAA | Sample address = %11AAAAAA.AA000000 |
$4013 | LLLL.LLLL | Sample length (write) |
bits 7-0 | LLLL LLLL | Sample length = %LLLL.LLLL0001 |
The counter's value is sent to the mixer. It is loaded with 0 on power-up.
Automatic 1-bit delta-encoded sample playback is carried out by a combination of three units. The memory reader fills the 8-bit sample buffer whenever it is emptied by the sample output unit. The status register is used to start and stop automatic sample playback.
The sample buffer either holds a single 8-bit sample byte or is empty. It is filled by the reader and can only be emptied by the output unit; once loaded with a sample byte it will be played back.
Pitch table
For NTSC:
+-------+--------+-----------------------+--------------------+ | Speed | Period | Approx. Sampling Rate | Approx. Note | *=======*========*=======================*====================* +-------+--------+-----------------------+--------------------+ | $0 | $1AC | 4181.711449 Hz | C8 -1.7783 cents | +-------+--------+-----------------------+--------------------+ | $1 | $17C | 4709.927632 Hz | D8 +4.1558 cents | +-------+--------+-----------------------+--------------------+ | $2 | $154 | 5264.036765 Hz | E8 -3.2870 cents | +-------+--------+-----------------------+--------------------+ | $3 | $140 | 5593.039063 Hz | F8 +1.6684 cents | +-------+--------+-----------------------+--------------------+ | $4 | $11E | 6257.945804 Hz | G8 -3.8636 cents | +-------+--------+-----------------------+--------------------+ | $5 | $0FE | 7046.348425 Hz | A8 +1.5605 cents | +-------+--------+-----------------------+--------------------+ | $6 | $0E2 | 7919.347345 Hz | B8 +3.7673 cents | +-------+--------+-----------------------+--------------------+ | $7 | $0D6 | 8363.422897 Hz | C9 -1.7783 cents | +-------+--------+-----------------------+--------------------+ | $8 | $0BE | 9419.855263 Hz | D9 +4.1554 cents | +-------+--------+-----------------------+--------------------+ | $9 | $0A0 | 11,186.078130 Hz | F9 +1.6684 cents | +-------+--------+-----------------------+--------------------+ | $A | $08E | 12,604.031690 Hz | G9 +8.2855 cents | +-------+--------+-----------------------+--------------------+ | $B | $080 | 13,982.597660 Hz | A9 -12.0179 cents | +-------+--------+-----------------------+--------------------+ | $C | $06A | 16,884.646230 Hz | C10 +14.4775 cents | +-------+--------+-----------------------+--------------------+ | $D | $054 | 21,306.815480 Hz | E10 +17.2012 cents | +-------+--------+-----------------------+--------------------+ | $E | $048 | 24,857.951390 Hz | G10 -15.9279 cents | +-------+--------+-----------------------+--------------------+ | $F | $036 | 33,143.935190 Hz | C11 -17.8829 cents | +-------+--------+-----------------------+--------------------+
Memory reader
When the sample buffer is emptied, the memory reader fills the sample buffer with the next byte from the currently playing sample. It has an address counter and a bytes remaining counter.
When a sample is (re)started, the current address is set to the sample address, and bytes remaining is set to the sample length.
Any time the sample buffer is in an empty state and bytes remaining is not zero, the following occur:
- The sample buffer is filled with the next sample byte read from the current address, subject to whatever mapping hardware is present. The CPU is suspend for four clock cycles.
- The address is incremented; if it exceeds $FFFF, it is wrapped around to $8000.
- The bytes remaining counter is decremented; if it becomes zero and the loop flag is set, the sample is restarted (see above), otherwise if the bytes remaining counter becomes zero and the IRQ enabled flag is set, the interrupt flag is set.
At any time, if the interrupt flag is set, the CPU's IRQ line is continuously asserted until the interrupt flag is cleared.
Output unit
The output unit continuously outputs a 7-bit value to the mixer. It contains an 8-bit right shift register, a bits-remaining counter, a 7-bit delta-counter, and a silence flag.
When an output cycle ends, a new cycle is started as follows:
- The bits-remaining counter is loaded with 8
- If the sample buffer is empty, the silence flag is set, otherwise the silence flag is cleared and the sample buffer is emptied into the shift register.
When the timer outputs a clock, the following actions occur in order:
- If the silence flag is clear, bit 0 of the shift register is applied to the counter as follows: If bit 0 is clear and the delta-counter is greater than 1, the counter is decremented by 2, otherwise if bit 0 is set and the delta-counter is less than 126, the counter is incremented by 2.
- The right shift register is clocked.
- The bits-remaining counter is decremented. If it becomes zero, a new cycle is started.
Nothing can interrupt a cycle; every cycle runs to completion before a new cycle is started.
Likely internal implementation of the read
The following is speculation, and thus not necessarily 100% accurate. It does accurately predict observed behavior.
The 6502 cannot be pulled off of the bus normally. The 2A03 DMC gets around this by pulling RDY low internally. This causes the CPU to pause during the next read cycle, until RDY goes high again. The DMC unit holds RDY low for 4 cycles. The first three cycles it idles, as the CPU could have just started an interrupt cycle, and thus be writing for 3 consecutive cycles (and thus ignoring RDY). On the fourth cycle, the DMC unit drives the next sample address onto the address lines, and reads that byte from memory. It then drives RDY high again, and the CPU picks up where it left off.
This matters, because it can interfere with the expected operation of the controller registers, reads of the PPU status register, and CPU VRAM or SPR reads if they happen to occur in the same cycle that the DMC unit pulls RDY low.
For the controller registers, this can cause an extra rising clock edge to occur, and thus shift an extra bit out. For the others, the PPU will see multiple reads, which will cause extra increments of the address latches, or clear the vblank flag.