bfirsh / bfirsh/jsnes

APU: various channel bugs (sequencer reset, length counter gating, timer stepping, noise LFSR)

Open
#609 0 comments 0 reactions 0 assignees View on GitHub
accuracy bug component: apu difficulty: medium priority: medium
Dominant language
JavaScript
Stars
6.4k
Forks
857
PR merge metrics
No merged PRs in 30d

Description

## Summary

Several APU channel bugs:

### 1. Square sequencer not reset on $4003/$4007 write

Per [nesdev APU Pulse](https://www.nesdev.org/wiki/APU_Pulse), writing the 4th register ($4003 or $4007) resets the duty cycle sequencer to step 0. The code (`channel-square.js:158-168`) only sets `envReset = true` but never resets `squareCounter`. This affects note attack timing.

### 2. Triangle/Noise length counters loaded when channel disabled

`channel-triangle.js:72` and `channel-noise.js:85` load the length counter without checking `isEnabled`. Per the wiki, the length counter should only be loaded when the channel's enable flag ($4015) is set.

### 3. Square timer uses `if` instead of `while` (papu/index.js:256, 266)

The triangle channel correctly uses `while` for its timer, but the square channels use `if`. At high frequencies with long CPU instructions, multiple sequencer steps can be missed within a single timer period.

### 4. Noise LFSR shifts left instead of right (papu/index.js:286)

Real hardware shifts the 15-bit LFSR right with feedback from bit 0. The code shifts left and tests bit 15. While both produce pseudo-random sequences, the exact output differs.

## References

- [APU Pulse](https://www.nesdev.org/wiki/APU_Pulse)
- [APU Triangle](https://www.nesdev.org/wiki/APU_Triangle)
- [APU Noise](https://www.nesdev.org/wiki/APU_Noise)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.