APU Sweep

From NESdev Wiki
Revision as of 16:46, 14 May 2011 by Quietust (talk | contribs) (the problem isn't in pulse 2, but in pulse 1 - pulse 2 adds the two's complement during subtraction (as it should), but pulse 1 adds the ONE'S complement due to its carry input being hardwired)
Jump to navigationJump to search

A NES APU sweep unit can be made to periodically adjust a pulse channel's period up or down.

Each sweep unit contains the following: divider, reload flag.

$4001 EPPP.NSSS Pulse channel 1 sweep setup (write)
$4005 EPPP.NSSS Pulse channel 2 sweep setup (write)
bit 7 E--- ---- Enabled flag
bits 6-4 -PPP ---- The divider's period is set to P + 1
bit 3 ---- N--- Negate flag
bits 2-0 ---- -SSS Shift count (number of bits)
Side effects Sets the reload flag

NOTE: The term "shifter result" used in the following description is equivalent to [shift-result + current period]. That is, it does not mean the result of the right-shift alone.

When clocked by the frame counter, the divider is first clocked and then if the reload flag is set, it is cleared and the divider is reloaded.

An internal shifter continuously calculates a result based on the channel's 11-bit raw timer period, but it doesn't change anything. The raw period is shifted right by the shift count, then either added to or subtracted from* the channel's raw period, yielding the final shifter result (used below). For reasons unknown, pulse channel 1 hardwires its carry input rather than using the state of the negate flag, resulting in the subtraction operation adding the one's complement instead of the expected two's complement (as pulse channel 2 does).

When the channel's raw period is less than 8, or the shifter result is greater than $7FF and the negate flag is clear, the channel is silenced (0 is sent to the mixer) but the channel's raw period is not changed. Otherwise, if the enabled flag is set and the shift count is non-zero, when the divider outputs a clock, the channel's raw period is set to the shifter's result.

Note that the sweep unit can silence a channel even when the enabled flag is clear. To fully disable a sweep unit, write $08 to turn on the negate flag so that the final shifter result is not greater than the channel's period and therefore not greater than $7FF.