Conflicting info on APU Noise Channel's RNG taps

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Conflicting info on APU Noise Channel's RNG taps
by on (#56857)
Hello all! It's good to be back!! I took quite a long hiatus from my SystemVerilog-based NES-on-an-FPGA emulator development. I was extremely busy with some job-related work trying to meet our delivery date for MISSE-8 (Materials International Space Station Experiment). But that's all finished now.

Rather than iron out bugs in the CPU and PPU (which are mostly complete and functional) I'm going to start working on the APU (I need a change of scenery!). Then I want to implement at least a few of the most common mappers. But right off the bat I've already met with some conflicting APU information - which is to be expected.

Specifically, in Blargg's "NES APU Sound Hardware Reference" http://nesdev.com/apu_ref.txt it says the RNG (Random Number Generator) taps for the Noise channel are "bits 0 and 1 (mode = 0) or bits 0 and 6 (mode = 1)". And in this example I can't tell if Blargg is using Big/Little-Endian notation (i.e. 14-0 or 0-14). From the posts I've seen on NesDev I would tend to trust Blargg's documentation over anyone else's since he is extremely knowledgeable about APU stuff and is very active in the forums.

In Brad Taylor's "2A03 Technical Reference" it says the taps are bits 14 and 13 (mode = 0) and bits 8 and 2 (mode 1).

And these are just two examples of the many documents out there with APU information. Does anyone have the FINAL word on which are the _exact_ RNG tap bits used in the original 2A03? And please specify how you are numbering the bits (0-14) or (14-0).

Yes, maybe I'm being a little nit-picky on which bits to use, but as I've said in other posts I want my hardware emulator to be as absolutely accurate and true to the original implementation as possible.

Thanks in advance! :)

by on (#56865)
From earlier in apu_ref.txt: "Bits are numbered from 0 to 7, corresponding with the least to most significant bits of a byte; bit n has a binary weight of 2^n." though I suppose binary weight has no meaning in the noise LFSR...

The wiki page has a little diagram that seems clearer.

Shift register bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

1) Bit 15 of the shift register is replaced with the exclusive-OR of bit 0 and one other bit: bit 6 if loop is set, otherwise bit 1.

2) Then, the shift register is shifted one bit right (bit 0 is lost).
Hmmm...OK, but...
by on (#56866)
Okay, that does help. But now I'm confused on something else. :-P

Is the shift register actually 16 bits (15-0) as you state above (and as said in the Wiki) or is it 15 bits (14-0) as you state in your APU Reference doc?

Thanks for your help! :)

by on (#56881)
blargg wrote:
Shift register bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0


- So, 16 bits unsigned short.

APU ref wrote:
The noise channel starts at register $400C and contains the following: Length Counter, Envelope Generator, Timer, 15-bit right shift register with feedback, 4-bit DAC.


- Hmm, got it. Should it be 16-bit..?

by on (#56890)
blargg was subject to off-by-one error when counting bits, but he actually said that there's 15 bits to the LFSR (14-0) because it'd have required 2 more taps for 16 bits. And anyways, with 16 bits the maximum sequence would have been 65535 bits, which would be incorrect.
Nice catch
by on (#56892)
~J-@D!~ wrote:
but he actually said that there's 15 bits to the LFSR (14-0) because it'd have required 2 more taps for 16 bits.


This is an excellent catch. Yes, two more taps would be required for a 16-bit LFSR - I should've caught that one! Grrr. Haha.

I think someone should fix the Wiki page then since it says the shift register is 16 bits, and refers to bit 15 which does not even exist. Any takers? I don't feel I have enough seniority here yet to be messing with the NesDev wiki pages. :-P
Re: Nice catch
by on (#56895)
jwdonal wrote:
I think someone should fix the Wiki page then since it says the shift register is 16 bits, and refers to bit 15 which does not even exist. Any takers? I don't feel I have enough seniority here yet to be messing with the NesDev wiki pages. :-P

Mess all you want. If you can demonstrate that your changes are constructive, you don't need forum seniority; you can build wiki seniority.

by on (#56896)
- Done, but it's subject to un-do. -_-;;

by on (#56897)
- For my best, the "-" means unused bits, not properly the length of a number. Anyway, for PC programming and general thinks:

Code:
unsigned short shift_reg; //is more usual than...
unsigned shift_reg : 14;

by on (#56904)
~J-@D!~ wrote:
blargg was subject to off-by-one error when counting bits, but he actually said that there's 15 bits to the LFSR (14-0)

I don't see any off-by-one errors [wait, now I see that the Wiki page is wrong, describing it as if it only has 14 bits... corrected now]. In apu_ref, I used what I consider a slightly more confusing description:
apu-ref.txt wrote:
The noise channel starts at register $400C and contains the following: [...] 15-bit right shift register with feedback [...]

The shift register is clocked by the timer and the vacated bit 14 is filled with the exclusive-OR of *pre-shifted* bits 0 and 1 (mode = 0) or bits 0 and 6 (mode = 1), resulting in 32767-bit and 93-bit sequences, respectively.

It requires the concept of the "vacated bit 14" and "pre-shifted bits". When doing the wiki, I simplified this by breaking it into two steps. In the first, you do the XOR and replace a bit, then shift right. If you run it in your mind, you will see that while it uses 16 bits between the two steps, you only need 15 bits of state for the LFSR otherwise. Replacing bit 15 (the left-most) and shifting right clearly shows it's not long-term state.

As usual, drawing a picture helps a lot in understanding these things :)
2 different paradigms
by on (#56906)
I think we're all talking about the same thing here but we're running into a paradigm shift (i.e. we're looking at the same problem from 2 different perspectives). I personally am looking at the shift register from a strictly hardware (HDL) perspective, whereas others are looking at it from a software (C language) perspective.

In Verilog, you would never say something like "unsigned short" since you are not limited to pre-defined data types when designing custom hardware in HDL. In Verilog I would simply say:

reg [14:0] shift_reg;

This will give me an exactly 15-bit register, no more, no less. Similarly, I could make a 3-bit register, 7-bit register, 10-bit register. Doesn't matter. And all those different sizes could be treated as simple shift registers, unsigned numbers, signed numbers, floating point, etc, etc. That's the beauty of programming in HDL and creating your own custom hardware. :)

by on (#56907)
It would be interesting to implement an emulator like that, with n-width integers. I think byuu is doing something like this in bsnes, with something like Int<width> in C++. For the rest of us, all that matters is the end result: the correct bit sequence out of the noise generator.

by on (#56909)
Good to see you back Blargg ;)

by on (#56916)
Yeah, good to see ya blargg :)

A little off-topic, but here's a possible implementation of a variable sized int :
Code:
template<unsigned N>
class UInt
{
    unsigned long long val : N;
public:
    inline UInt() {}
    inline UInt(unsigned long long num) : val(num) {}
    inline operator unsigned long long() { return val; }
};


Now, it almost just looks like an ordinary int:
Code:
...
   UInt<7> a = 33, b = 14.5, c = a * b;
   cout << c; // will print 78

by on (#56917)
Haha, nifty implementation of a variable-width int. I wouldn't have thought of using a bitfield in a template like that, but it's perfect.

BTW, I noticed that the Wiki page was in fact in error. It described the LFSR as if it only had 14 bits (pus a 15th extra temporary bit). I've corrected it, and clarified how it only has 15 bits in actuality, even though 16 are used in the description of shifting.

by on (#56946)
- One question: regarding this...
Quote:
The mixer receives the current envelope volume except when

A) Bit 0 of the shift register is set, or
B) The length counter is zero


- As I'm producing signed samples, if A is true => negative value; else, positive. Is this ok?

by on (#56948)
If the length counter is 0 or the lowest bit of channel 4's polynomial counter is 1, channel 4's DAC receives a zero. Otherwise, channel 4's DAC receives the volume from the envelope unit.

All DACs in the NES produce unsigned output, and an analog high-pass filter after the mixer turns it into signed output on the RCA connector. Trying to produce "symmetric" output will make some audio demos based on timed writes sound inaccurate. If you want signed samples, do the same thing the NES does: use a high-pass filter on the master output.

by on (#56957)
- Done. :) Thanks for the info.