Conflicting info on APU Noise Channel's RNG taps

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

Conflicting info on APU Noise Channel's RNG taps

Post by jwdonal »

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! :)
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

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).
User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

Hmmm...OK, but...

Post by jwdonal »

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! :)
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

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..?
User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 521
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Post by Jarhmander »

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.
User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

Nice catch

Post by jwdonal »

~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
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Nice catch

Post by tepples »

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.
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

- Done, but it's subject to un-do. -_-;;
User avatar
Zepper
Formerly Fx3
Posts: 3264
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

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

Code: Select all

unsigned short shift_reg; //is more usual than...
unsigned shift_reg : 14;
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

~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 :)
Last edited by blargg on Sun Feb 21, 2010 9:39 pm, edited 1 time in total.
User avatar
jwdonal
Posts: 719
Joined: Sat Jun 27, 2009 11:05 pm
Location: New Mexico, USA
Contact:

2 different paradigms

Post by jwdonal »

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. :)
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

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.
User avatar
Banshaku
Posts: 2404
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Post by Banshaku »

Good to see you back Blargg ;)
User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 521
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Post by Jarhmander »

Yeah, good to see ya blargg :)

A little off-topic, but here's a possible implementation of a variable sized int :

Code: Select all

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: Select all

...
   UInt<7> a = 33, b = 14.5, c = a * b;
   cout << c; // will print 78
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

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.
Post Reply