APU Sweep: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
(Make calculation of target period more distinct as a step in the sweep unit's operation; reiterate approximate rate of APU Frame Counter)
(ch1/ch2 differences and muting are more related to the target period than to updates)
Line 19: Line 19:
|colspan=2| Side effects || Sets the reload flag
|colspan=2| Side effects || Sets the reload flag
|}
|}
== Calculating the target period ==


The sweep unit continuously calculates each channel's '''target period''' in this way:
The sweep unit continuously calculates each channel's '''target period''' in this way:
Line 25: Line 27:
# The target period is the sum of the current period and the change amount.
# The target period is the sum of the current period and the change amount.


Thus whenever the current period changes for any reason, whether by $400x writes or by sweep, the target period also changes.
For example, if the negate flag is false, the change amount equals the current period, making the target period equal to twice the current period.
 
The two pulse channels have their adders' carry inputs wired differently, which produces different results when each channel's change amount is made negative:
* Pulse 1 adds the [[wikipedia:Ones' complement|ones' complement]] (''−c − 1''). Making 20 negative produces a change amount of −21.
* Pulse 2 adds the [[wikipedia:Two's complement|two's complement]] (''−c''). Making 20 negative produces a change amount of −20.
 
Whenever the current period changes for any reason, whether by $400x writes or by sweep, the target period also changes.
 
== Muting ==
 
Two conditions cause the '''sweep unit to mute the channel''': 0 is sent to the [[APU Mixer|mixer]] instead of the current volume.
Muting is regardless of the enable flag and regardless of whether the sweep divider is not outputting a clock signal.
 
If at any time the ''target'' period is greater than $7FF, the channel is muted.
In particular, if the negate flag is false, the shift count is zero, and the current period is at least $400, the target period will be large enough to mute the channel.
(This is why several publishers' NES games never seem to use the bottom octave of the pulse waves.)
 
Because the target period is computed continuously, a target period overflow from the sweep unit's adder can silence a channel ''even when the enabled flag is clear'' and even when the sweep divider is not outputting a clock signal.
Thus to fully disable the sweep unit, a program must turn off enable and turn on negate, such as by writing $08.
This ensures that the target period is not greater than the current period and therefore not greater than $7FF.
 
If the ''current'' period is less than 8, the channel is also muted.
This avoids sending harmonics in the hundreds of kHz through the audio path.
This muting cannot be overridden because it is based on the current period.
 
== Updating the period ==


When the [[APU Frame Counter|frame counter]] sends a half-frame clock (at 120 or 96 Hz), one of three things happens:
When the [[APU Frame Counter|frame counter]] sends a half-frame clock (at 120 or 96 Hz), one of three things happens:
Line 33: Line 60:
* If the reload flag is clear and the divider's counter is zero and the sweep is enabled, the counter is set to P and the pulse's period is adjusted (if the target period is in range; see below).
* If the reload flag is clear and the divider's counter is zero and the sweep is enabled, the counter is set to P and the pulse's period is adjusted (if the target period is in range; see below).


When the channel's ''current'' period is less than 8 or the target period is greater than $7FF, the channel is silenced (0 is sent to the [[APU Mixer|mixer]]) but the channel's current period remains unchanged. Otherwise, if the enable flag is set and the shift count is non-zero, when the divider outputs a clock, the channel's period is updated.
When the sweep unit is muting the channel, the channel's current period remains unchanged. Otherwise, if the enable flag is set and the shift count is non-zero, when the divider outputs a clock, the channel's period is updated.
 
If the shift count is zero, the channel's period is never updated, but the channel will ''still'' be silenced if the sweep is in add mode and the target period (i.e., the current period added to itself) is greater than $7FF.
 
Because the target period is computed continuously, a target period overflow from the sweep unit's adder can silence a channel ''even when the enabled flag is clear'' and even when the sweep divider is not outputting a clock signal. To fully disable a sweep unit, write $08 to turn on the negate flag so that the target period is not greater than the channel's period and therefore not greater than $7FF. (This behavior of silencing the channel even when the sweep unit is disabled is only relevant for adder overflow; the pulse channels are ''always'' silenced when the period is less than eight, regardless of whether a sweep period update or an explicit setting of the period was involved.)


For reasons unknown, pulse channel 1 hardwires its adder's 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). As a result, a negative sweep on pulse channel 1 will subtract the shifted period value '''minus 1'''.
If the shift count is zero, the channel's period is never updated, but muting logic still applies.

Revision as of 17:03, 28 December 2016

An 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
0: add to period, sweeping toward lower frequencies
1: subtract from period, sweeping toward higher frequencies
bits 2-0 ---- -SSS Shift count (number of bits)
Side effects Sets the reload flag

Calculating the target period

The sweep unit continuously calculates each channel's target period in this way:

  1. A barrel shifter shifts the channel's 11-bit raw timer period right by the shift count, producing the change amount.
  2. If the negate flag is true, the change amount is made negative.
  3. The target period is the sum of the current period and the change amount.

For example, if the negate flag is false, the change amount equals the current period, making the target period equal to twice the current period.

The two pulse channels have their adders' carry inputs wired differently, which produces different results when each channel's change amount is made negative:

  • Pulse 1 adds the ones' complement (−c − 1). Making 20 negative produces a change amount of −21.
  • Pulse 2 adds the two's complement (−c). Making 20 negative produces a change amount of −20.

Whenever the current period changes for any reason, whether by $400x writes or by sweep, the target period also changes.

Muting

Two conditions cause the sweep unit to mute the channel: 0 is sent to the mixer instead of the current volume. Muting is regardless of the enable flag and regardless of whether the sweep divider is not outputting a clock signal.

If at any time the target period is greater than $7FF, the channel is muted. In particular, if the negate flag is false, the shift count is zero, and the current period is at least $400, the target period will be large enough to mute the channel. (This is why several publishers' NES games never seem to use the bottom octave of the pulse waves.)

Because the target period is computed continuously, a target period overflow from the sweep unit's adder can silence a channel even when the enabled flag is clear and even when the sweep divider is not outputting a clock signal. Thus to fully disable the sweep unit, a program must turn off enable and turn on negate, such as by writing $08. This ensures that the target period is not greater than the current period and therefore not greater than $7FF.

If the current period is less than 8, the channel is also muted. This avoids sending harmonics in the hundreds of kHz through the audio path. This muting cannot be overridden because it is based on the current period.

Updating the period

When the frame counter sends a half-frame clock (at 120 or 96 Hz), one of three things happens:

  • If the reload flag is set, the divider's counter is set to the period P. If the divider's counter was zero before the reload and the sweep is enabled, the pulse's period is also adjusted (if the target period is in range; see below). The reload flag is then cleared.
  • If the reload flag is clear and the divider's counter is non-zero, it is decremented.
  • If the reload flag is clear and the divider's counter is zero and the sweep is enabled, the counter is set to P and the pulse's period is adjusted (if the target period is in range; see below).

When the sweep unit is muting the channel, the channel's current period remains unchanged. Otherwise, if the enable flag is set and the shift count is non-zero, when the divider outputs a clock, the channel's period is updated.

If the shift count is zero, the channel's period is never updated, but muting logic still applies.