Results 1 to 12 of 12

Thread: Linear Feedback Shift Register

  1. #1

    Thread Starter
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Linear Feedback Shift Register

    I'm a bit baffled, not to mention frustrated beyond comprehension and hopefully I can explain this right or I just once again created a dead thread noone can answer due to the advanced nature of what I'm about to write.

    Theres a type of randomness out there called a Linear Feedback Shift Register, or for short, LFSR. A LFSR is a shift register whose input bit is a linear function of its previous state. Basically it works at a binary level. With that said, the most commonly used linear function of single bits of the LFSR is an XOR. The XOR gate of the LFSR shifts the bits either left or right. Just to give you an idea, take a look at this image of a 4 bit LFSR


    And you can read more up on it through wikipedia HERE

    I actually need this because I wrote an NES Emulator in VB6, which you can find in my signature. The Nintendo Entertainment System used this LFSR in one of their sound channels called Noise. The Noise sound channel is used in things such as percussion, explosions, bricks breaking, someone being hit, etc. However, this monstrosity uses a 15 bit size LFSR numbered from bit 14 to bit 0. Although I implemented it, it only half works. And I have no idea why. Some games it sounds great such as Double Dragon, but games like Super Mario Bros, I hear only half the percussion, and don't hear the bricks breaking. Just a thump. So it all boils down to only half the LFSR working. And mods, don't move this to the Games and Graphics section as it is regarding a programming problem. Just hear me out. The NES does Noise through 3 8-bit registers in memory which are (in Hex) $400C, $400E, and $400F. $400D is not used. Noise goes through a pseudo-random bit sequence and has 2 modes. The modes are determined by Bit 7 of register $400E which can be either 0 or 1, shown here:

    Bits
    7 6 5 4 3 2 1 0
    M - - - - - - -

    Where M is Mode. If its 0, the Noise is 32767 steps long. If its 1, then Noise is only 93 steps long. However, the particular 93-step sequence depends on where in the 32767-step sequence the shift register was when Mode flag was set. I personally have a feeling that one of my modes are not being executed. Probably the 32767 step sequence. Now before this sequence can be produced, it must go through a series of rules, which are:

    Code:
    The shift register is 15 bits wide, with bits numbered
    14 - 13 - 12 - 11 - 10 - 9 - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
    When the timer clocks the shift register, the following actions occur in order:
    
        1. Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1.
        2. The shift register is shifted right by one bit.
        3. Bit 14, the leftmost bit, is set to the feedback calculated earlier.
    You can find all the information on this here:
    http://wiki.nesdev.com/w/index.php/APU_Noise

    as well as even more information on it through a few of the links I put up in one of my posts in my NES Emulator thread. The code I used to execute this is here, with a lot of comments:

    vb Code:
    1. Public Function Noise_Channel_Render_Sample() As Long
    2.    
    3.     Dim Bit0 As Long
    4.     Dim Bit1 As Long
    5.     Dim Bit6 As Long
    6.    
    7.         'if (Noise.datatype)
    8.         '    Noise.CurD = (Noise.CurD << 1) | (((Noise.CurD >> 14) ^ (Noise.CurD >> 8)) & 0x1);
    9.         'else    Noise.CurD = (Noise.CurD << 1) | (((Noise.CurD >> 14) ^ (Noise.CurD >> 13)) & 0x1);
    10.    
    11.     With Noise_Channel
    12.         If .Length_Counter > 0 And .Enabled Then
    13.             '.SampleCount = Within_Range(.SampleCount + 1, 0, LONG_RANGE) 'causes minor slowdown
    14.             .SampleCount = .SampleCount + 1
    15.             If .SampleCount >= .RenderedWavelength Then
    16.                 .SampleCount = .SampleCount - .RenderedWavelength
    17.                 If .Noise_Random_Generator_Mode = True Then '93 bits long
    18.                     'According to [url]http://wiki.nesdev.com/w/index.php/APU_Noise[/url]
    19.                    
    20.                     'The shift register is 15 bits wide, with bits numbered
    21.                     '14 - 13 - 12 - 11 - 10 - 9 - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
    22.                    
    23.                     'Step 1) Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1.
    24.                     '        Note: Exclusive Or is Xor, not Or! Or is Inclusive.
    25.                         Bit0 = (.NoiseShiftData) \ Power_Of_2(14) 'Right Shifts it to bit 0 by right shifting 14 bits (see shift register table above)
    26.                         Bit6 = (.NoiseShiftData) \ Power_Of_2(8) 'Right Shifts it to bit 6 by right shifting 8 bits (see shift register table above)
    27.                         .Noise_Feedback = (Bit0 Xor Bit6)
    28.                 Else '32767 bits long
    29.                     'According to [url]http://wiki.nesdev.com/w/index.php/APU_Noise[/url]
    30.                    
    31.                     'The shift register is 15 bits wide, with bits numbered
    32.                     '14 - 13 - 12 - 11 - 10 - 9 - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
    33.                    
    34.                     'Step 1) Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1.
    35.                     '        Note: Exclusive Or is Xor, not Or! Or is Inclusive.
    36.                         Bit0 = (.NoiseShiftData) \ Power_Of_2(14) 'Right Shifts it to bit 0 by right shifting 14 bits (see shift register table above)
    37.                         Bit1 = (.NoiseShiftData) \ Power_Of_2(13) 'Right Shifts it to bit 1 by right shifting 13 bits (see shift register table above)
    38.                         .Noise_Feedback = (Bit0 Xor Bit1)
    39.                 End If
    40.                
    41.                 'Step 2) The shift register is shifted right by one bit.
    42.                     .NoiseShiftData = .NoiseShiftData * 2
    43.                 'Step 3) Bit 14, the leftmost bit, is "set" to the feedback calculated earlier.
    44.                 '        Note: You set it using the Or operator, not the And operator like you would see in most emulators' source code
    45.                     '.Noise_Feedback = .Noise_Feedback Or BIT_14
    46.                 'Then the Noise shift gets updated and prepared to be outputed for sound.
    47.                     .NoiseShiftData = .NoiseShiftData Or (.Noise_Feedback And &H1&)
    48.             End If
    49.            
    50.             If .Envelope_Decay_Disable Then
    51.                 Noise_Channel_Render_Sample = ((.NoiseShiftData And &H1&) * &H40&) * .Volume
    52.                 Exit Function
    53.             Else
    54.                 Noise_Channel_Render_Sample = ((.NoiseShiftData And &H1&) * &H40&) * .Envelope
    55.                 Exit Function
    56.             End If
    57.         Else
    58.             .Volume = 0
    59.         End If
    60.         Noise_Channel_Render_Sample = 0
    61.         Exit Function
    62.     End With
    63. End Function

    Seems like my code is consistent with the documentation thus far, unless I missed something. But here is another thing I noticed. The NesDev site also mentioned the shift register is 15 bits wide. However in my sound debugger of my emulator, Im seeing the shift register numbers far exceed that in the millions range randomly in either positive or negative. If you do the math, 15 bits is $8000 in hex, or in other words, 32768 in decimal. Im not sure if I should keep the shift register within the range of 32767 as I didn't ever find any other open source emulator do this. So through all this advanced crap thats probably making all of you scratch your heads and be like "huh?" , my 2 problems are basically:

    1. Only one of the modes are being heard, especially in super mario bros. Why is this? Could there be a bug in my code I overlooked in that function?

    2. I'm not so sure if I should keep the LFSR within the range of 32767 (15 bits) as it really isnt done in any other emulator.

    Hopefully I did the LFSR right. I given all the information I could at the moment as its super late but if anyone has any questions, let me know, or if any of you all have some bright ideas on how to properly do it, I would appreciate it. Thanks in advance. (Crosses my fingers)

  2. #2
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Linear Feedback Shift Register

    I wont pretend to understand what you're trying to do but this looks 'funny'
    Code:
    'Step 2) The shift register is shifted right by one bit.
    42.                    .NoiseShiftData = .NoiseShiftData * 2
    Doesn't that shift it to the left by one bit ? (or am I demonstrating my complete ignorance?)

  3. #3

    Thread Starter
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Linear Feedback Shift Register

    Wow how could I've missed that! The funny thing is that now I don't hear sound at all because the shift register is brought down to 0. So I'm not sure if the documentation is wrong. In Double Dragon, using a Left Shift produces accurate noise emulation, and stays in 32767 mode throughout the game. So it wasnt 32767 mode it seems, but instead 93 mode.

    Also I have a feeling I need to use a lookup table because I have another NES emulator written in C++ that setup the LFSR like this:

    Code:
    static void shift_register15(int8 *buf, int count)
    {
       static int sreg = 0x4000;
       int bit0, bit1, bit6, bit14;
    
       if (count == APU_NOISE_93)
       {
          while (count--)
          {
             bit0 = sreg & 1;
             bit6 = (sreg & 0x40) >> 6;
             bit14 = (bit0 ^ bit6);
             sreg >>= 1;
             sreg |= (bit14 << 14);
             *buf++ = bit0 ^ 1;
          }
       }
       else /* 32K noise */
       {
          while (count--)
          {
             bit0 = sreg & 1;
             bit1 = (sreg & 2) >> 1;
             bit14 = (bit0 ^ bit1);
             sreg >>= 1;
             sreg |= (bit14 << 14);
             *buf++ = bit0 ^ 1;
          }
       }
    }
    Where *buf is the array being stored data, and count either is the constant 93, or the constant 32767. Then while it plays the sound, it saves the position the XOR tap has been produced using this function:

    Code:
    INLINE int8 shift_register15(uint8 xor_tap)
    {
       static int sreg = 0x4000;
       int bit0, tap, bit14;
    
       bit0 = sreg & 1;
       tap = (sreg & xor_tap) ? 1 : 0;
       bit14 = (bit0 ^ tap);
       sreg >>= 1;
       sreg |= (bit14 << 14);
       return (bit0 ^ 1);
    }
    But it bugs me because none of this stuff is consistent with the documentation with the exception of the xor position. Yet the sheer thought of a look up table does sound intriguing. So I'm gonna see what I can do. Thanks for the possible flaw Doogle. But if it doesn't work I'm gonna have to go back to left shift and assume the docs were wrong.

  4. #4
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Linear Feedback Shift Register

    One other thing I noticed, and this might be a comment error
    Code:
    26.                        Bit6 = (.NoiseShiftData) \ Power_Of_2(8) 'Right Shifts it to bit 6 by right shifting 8 bits (see shift register table above)
    Bit 6 would be 'isolated' by shifting 6 bits rather than 8 (?)

    I think If I were doing this I'd be using Ands and in 'small steps' (so I could follow what's going on):
    Code:
    Bit0 = .NoiseShiftData And &H1&             'Isolate Bit0 of NoiseShiftData into bit0 of Bit0
    Bit6 = (.NoiseShiftData And &H40&) / &H40&  'Isolate Bit6 of NoiseShiftData into bit0 of Bit6
    ' If the Comment is incorrect and you really need Bit8:
    ' Bit8 = (.NoiseShiftData And &H100&) / &H100&
    Bit1 = (.NoiseShiftData And &H2&) / &H2&    'Isolate Bit1 of NoiseShiftData into bit0 of Bit1
    '
    ' Xor the values depending on Mode
    '
    If Noise_Random_Generator_Mode = True Then
        .NoiseFeedBack = Bit0 Xor Bit6          '
    Else
        .NoiseFeedBack = Bit0 Xor Bit1
    End If
    '
    ' At this point .NoiseFeedBack is either '1' or '0'
    ' Shift the result into bit14 of .NoiseFeedBack
    '
    .NoiseFeedBack = .NoiseFeedBack * Power_Of_2(14)
    '
    ' NoiseFeedback is now either '16384'(2^14) or '0'
    ' Right shift NoiseShiftData by one bit
    '
    .NoiseShiftData = .NoiseShiftData / 2
    '
    ' Set Bit14 of NoiseShiftData to the value of bit14 of .NoiseFeedBack
    '
    .NoiseShiftData = .NoiseShiftData Or .NoiseFeedBack
    Last edited by Doogle; May 17th, 2013 at 01:05 AM. Reason: Missed out the 'Or'

  5. #5

    Thread Starter
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Linear Feedback Shift Register

    In the site http://wiki.nesdev.com/w/index.php/APU_Noise, it clearly states "Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1. " It all starts at Bit 14. To get to Bit 6 you have to right shift 8 bits:
    ------------------------>
    14-13-12-11-10-9-8-7-6-5-4-3-2-1-0

    And I technically already small stepped it. Take a look at this C# code from another emulator that was commented inside the function:
    Code:
            'if (Noise.datatype)
            '    Noise.CurD = (Noise.CurD << 1) | (((Noise.CurD >> 14) ^ (Noise.CurD >> 8)) & 0x1);
            'else    Noise.CurD = (Noise.CurD << 1) | (((Noise.CurD >> 14) ^ (Noise.CurD >> 13)) & 0x1);
    Although ugly, if you break it down, its actually

    Code:
            'if (Noise.datatype){
            '    Bit_0 = (Noise.CurD >> 14);
            '    Bit_6 = (Noise.CurD >> 8);
            '    Feedback = (Bit_0 ^ Bit_6);
            '    Noise.CurD = (Noise.CurD << 1) | (Feedback & 0x1);
            '}
            'else {   
            '    Bit_0 = (Noise.CurD >> 14);
            '    Bit_1 = (Noise.CurD >> 13);
            '    Feedback = (Bit_0 ^ Bit_1);
            '    Noise.CurD = (Noise.CurD << 1) | (Feedback & 0x1);
            '}
    And even though I did it a tad different, the results were the same either way. Removing &H1 in any of those places resulted in a much higher pitched Noise.

    [EDIT] I was playing around with my emulators noise code and, not sure if you have or not but download my NES Emulator, and remove the ".Length_Counter > 0" if statement in the beginning of the function. Play Super Mario Bros, ignor the Noise sound for a minute (youll see why), grab a mushroom, and break a brick block. Youll hear something that was missing. The sound of bricks breaking with a nice bass thump. Although the length counter code is correct, I may have to do what the C++ emulator did, and actually use a lookup table that I can XOR tap.

  6. #6
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Linear Feedback Shift Register

    Quote Originally Posted by Jacob Roman View Post
    It all starts at Bit 14. To get to Bit 6 you have to right shift 8 bits
    (EDIT: If you wanted to put bit6 into bit 14 then you'd have to shift it 8 bits to the left)

    I think we're talking at cross purposes. To get the value of Bit 6 there's no 'shift' involved. To 'isolate' bit6, as suggested in my last Post, you 'And' it with 2^6 (&H40), if the result is zero bit6 is not set, otherwise it is; or as I did, calculate (value And &H40&) / &H40&), if the result is 0 bit6 is not set if it's 1 it is set.

    If you take a value of 2^6 = 64 and shift it right by 8 bits (256) using a calculation such as: (2^6) \ (2^8) the result will be zero, whereas you actually want '1' (which you'd get by shifting it right by 6 bits i.e. (2^6) \ (2^6) = 1
    .
    Just shifting does not necessarily 'isolate' the bit you're looking for.

    For example: take a value of Binary '000001001000000' (2,176) shift it right by 6 bits gives '000000000001001' (9). All that's done is moved all the bits right by 6 bits. To determine whether the original bit6 was set you'd have to And the result with &H1& which would give you '000000000000001'

    I knocked up a very simple emulator using the 'rules' from the site you quoted and the 'And' methodology for 'isolating' the necessary bits. I haven't run it for more than 32,767 steps but it certainly repeats the pseudo-random sequence after 93 steps when 'Mode' is set. It's attached for your amusement.
    Attached Files Attached Files
    Last edited by Doogle; May 18th, 2013 at 12:13 AM.

  7. #7

    Thread Starter
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Linear Feedback Shift Register

    Ok I'll take a look at it.

    I setup a Look up table and placed them in a listbox. You can see the ones and zeros created. Although I'm pretty sure it goes against the docs, it'll give me something to XOR tap. Just create a new project, and add a listbox:

    vb Code:
    1. Option Explicit
    2.  
    3. Private Const APU_MODE_32k As Long = &H7FFF&
    4. Private Const APU_MODE_93 As Long = 93
    5.  
    6. Private Noise_Long_LUT() As Long
    7. Private Noise_Short_LUT() As Long
    8.  
    9. Private Function Linear_Feedback_Shift_Register_Lookup_Table(ByRef LUT() As Long, ByVal Count As Long)
    10.  
    11.     Dim Bit0 As Long
    12.     Dim Bit1 As Long
    13.     Dim Bit6 As Long
    14.     Dim Bit14 As Long
    15.     Dim Shift_Register As Long
    16.     Dim Inc As Long
    17.    
    18.     If Count = APU_MODE_93 Then
    19.         ReDim LUT(APU_MODE_93) As Long
    20.         Shift_Register = &H4000
    21.         While Count >= 0
    22.             Count = Count - 1
    23.             Bit0 = Shift_Register And &H1&
    24.             Bit6 = (Shift_Register And &H40&) \ &H40&
    25.             Bit14 = (Bit0 Xor Bit6)
    26.             Shift_Register = Shift_Register \ &H2&
    27.             Shift_Register = Shift_Register Or (Bit14 * &H4000)
    28.             LUT(Inc) = Bit0 Xor &H1
    29.             List1.AddItem Inc & ": " & LUT(Inc)
    30.             Inc = Inc + 1
    31.         Wend
    32.     ElseIf Count = APU_MODE_32k Then
    33.         ReDim LUT(APU_MODE_32k) As Long
    34.         Shift_Register = &H4000
    35.         While Count >= 0
    36.             Count = Count - 1
    37.             Bit0 = Shift_Register And &H1&
    38.             Bit1 = (Shift_Register And &H2&) \ &H2&
    39.             Bit14 = (Bit0 Xor Bit1)
    40.             Shift_Register = Shift_Register \ &H2&
    41.             Shift_Register = Shift_Register Or (Bit14 * &H4000)
    42.             LUT(Inc) = Bit0 Xor &H1&
    43.             Inc = Inc + 1
    44.         Wend
    45.     End If
    46.  
    47. End Function
    48.  
    49. Private Sub Form_Load()
    50.     Me.Show
    51.     Linear_Feedback_Shift_Register_Lookup_Table Noise_Short_LUT(), APU_MODE_93
    52.     Linear_Feedback_Shift_Register_Lookup_Table Noise_Long_LUT(), APU_MODE_32k
    53. End Sub

  8. #8
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Linear Feedback Shift Register

    I think we're now in violent agreement

  9. #9

    Thread Starter
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Linear Feedback Shift Register

    Well I like how you executed your project but I had to make a minor change in the variable names to avoid confussion because "Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1. ". See the Shift function:

    vb Code:
    1. Option Explicit
    2.  
    3. Private Feedback As Long
    4. Private Shift_Register As Long
    5. Private lngCount As Long
    6.  
    7. Private Sub cmdStart_Click()
    8.     Dim lngVal As Long
    9.     lngVal = 1
    10.     Call Shift
    11.     Timer1.Enabled = True
    12. End Sub
    13.  
    14. Private Sub cmdStop_Click()
    15.     Timer1.Enabled = False
    16. End Sub
    17.  
    18. Private Sub Form_Load()
    19.     Dim intI As Integer
    20.     Dim lngVal As Long
    21.     lngVal = 0
    22.     For intI = 13 To 0 Step -1
    23.         Load labB(intI)
    24.         labB(intI).Left = labB(intI + 1).Left + labB(intI + 1).Width
    25.         labB(intI).Top = labB(intI + 1).Top
    26.         labB(intI).Caption = "Bit" & CStr(intI)
    27.         labB(intI).Visible = True
    28.         Load labBit(intI)
    29.         labBit(intI).Left = labBit(intI + 1).Left + labBit(intI + 1).Width
    30.         labBit(intI).Top = labBit(intI + 1).Top
    31.         labBit(intI).Caption = "0"
    32.         labBit(intI).Visible = True
    33.     Next intI
    34.     labBit(14).Caption = "0"
    35.     lv.ColumnHeaders.Add , , "Step"
    36.     lv.ColumnHeaders.Add , , "Shift Register Value"
    37.     DisplayBits Feedback
    38.     Timer1.Interval = 500
    39.     Shift_Register = 1
    40. End Sub
    41.  
    42. Private Sub DisplayBits(lngVal As Long)
    43.     Dim lngI As Long
    44.     Dim intI As Integer
    45.     For intI = 14 To 0 Step -1
    46.         If (lngVal And (2 ^ intI)) = 0 Then
    47.             labBit(intI).Caption = "0"
    48.         Else
    49.             labBit(intI).Caption = "1"
    50.         End If
    51.     Next intI
    52. End Sub
    53.  
    54. Private Sub Timer1_Timer()
    55.     Timer1.Enabled = False
    56.     Shift
    57.     Timer1.Enabled = True
    58. End Sub
    59.  
    60. Private Sub Shift()
    61.  
    62.     Dim lvi As ListItem
    63.     Dim lngBit0 As Long
    64.     Dim lngBit1 As Long
    65.     Dim lngBit6 As Long
    66.     lngBit0 = Shift_Register And &H1&
    67.     lngBit1 = (Shift_Register And &H2&) \ &H2
    68.     lngBit6 = (Shift_Register And &H40&) \ &H40
    69.     If chkMode.Value = vbChecked Then
    70.         Feedback = lngBit0 Xor lngBit6
    71.     Else
    72.         Feedback = lngBit0 Xor lngBit1
    73.     End If
    74.     Feedback = Feedback * (2 ^ 14)
    75.     Shift_Register = Shift_Register \ 2
    76.     Shift_Register = Shift_Register Or Feedback
    77.     DisplayBits Shift_Register
    78.     lngCount = lngCount + 1
    79.     labS.Caption = CStr(lngCount)
    80.     Set lvi = lv.ListItems.Add(, , CStr(lngCount))
    81.     lvi.SubItems(1) = Shift_Register
    82. End Sub

    The only difference between your project and my project is that mine returns ones and zeros in the lookup table with one bit per index in the array, while yours returns shift register values.

  10. #10
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Linear Feedback Shift Register

    Yes, I did make a small modification to display the Binary value in the ListView as well, really just for interest to see the 'pattern'.

  11. #11

    Thread Starter
    Elite Hacker Jacob Roman's Avatar
    Join Date
    Aug 2004
    Location
    Miami Beach, FL
    Posts
    5,349

    Re: Linear Feedback Shift Register

    Another thing is that I had to make a minor change in mine as well to be more consistent with the docs because the shift register starts with a value of one, not bit 14. I have 2 open source nintendo emulators in C# and C++ that started at bit 14. Now Im not sure if thats true but here are the changes Ive made. I may need to change the LUT receiving (Bit0 Xor &H1&) To (Shift_Register And &H1&) Xor &H1&, but not sure till I actually hear sound with this thing once I splice it into my emulator:

    vb Code:
    1. Private Function Linear_Feedback_Shift_Register_Lookup_Table(ByRef LUT() As Long, ByVal Count As Long)
    2.  
    3.     Dim Bit0 As Long
    4.     Dim Bit1 As Long
    5.     Dim Bit6 As Long
    6.     Dim Feedback As Long
    7.     Dim Inc As Long
    8.    
    9.     If Count = APU_MODE_93 Then
    10.         ReDim LUT(APU_MODE_93) As Long
    11.         While Count >= 0
    12.             Count = Count - 1
    13.             Bit0 = Shift_Register And &H1&
    14.             Bit6 = (Shift_Register And &H40&) \ &H40&
    15.             Feedback = (Bit0 Xor Bit6)
    16.             Feedback = Feedback * &H4000&
    17.             Shift_Register = Shift_Register \ &H2&
    18.             Shift_Register = Shift_Register Or Feedback
    19.             LUT(Inc) = Bit0 Xor &H1
    20.             List1.AddItem Inc & ": " & LUT(Inc)
    21.             Inc = Inc + 1
    22.         Wend
    23.     ElseIf Count = APU_MODE_32k Then
    24.         ReDim LUT(APU_MODE_32k) As Long
    25.         While Count >= 0
    26.             Count = Count - 1
    27.             Bit0 = Shift_Register And &H1&
    28.             Bit1 = (Shift_Register And &H2&) \ &H2&
    29.             Feedback = (Bit0 Xor Bit1)
    30.             Feedback = Feedback * &H4000&
    31.             Shift_Register = Shift_Register \ &H2&
    32.             Shift_Register = Shift_Register Or Feedback
    33.             LUT(Inc) = Bit0 Xor &H1&
    34.             Inc = Inc + 1
    35.         Wend
    36.     End If
    37.  
    38. End Function

    [EDIT] I see why there is so much misinformation out there. The famous emulation textfile to the NES called everynes.txt says this about the Noise channel:

    Code:
    The random number generator consists of a 15bit shift register. The MSB (Bit14)
    is output/inverted (1=Low/Zero, 0=High/Decay/Volume). At the specified
    frequency, Bit14 is XORed with Bit13 (32767-bit mode) or with Bit8 (93-bit
    mode), the register is then shifted to the left, with the result of the XOR
    operation shifted-in to Bit0.

  12. #12
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Linear Feedback Shift Register

    That description in your last post will do exactly the same thing but will start at a different value in the sequence and with a '1' in bit14. The problem with shifting left in VB is that there's no Unsigned Long type, so you have to clear out bits 15 to 31 before / after you shift to stop a '1' propagating to bit31 and the value becoming 2's compliment (i.e. negative). I'd stick with shifting right - it appears to work.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width