Author Topic: LFSR  (Read 2134 times)

0 Members and 1 Guest are viewing this topic.

Offline NivagSwerdnaTopic starter

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
LFSR
« on: May 17, 2022, 10:51:46 am »
I'm about to embark on my first FPGA project and have decided on verilog...

So one of the first things I have to build is a LFSR where various taps combine to feedback...

This got me thinking...

If the LSFR is represented by a series of flip flops each feeding each other and sharing a common clock with the input either the output of the previous gate or a combinatorial function of various prior taps...

Is this inevitably a race condition because the inputs are based on the outputs which change at the same clock edge?

I have seen code like...

out <= { out[6:0], feedback }

Does that guarantee that it works atomically even when feedback is derived from the values of out on the RHS?

Maybe I am overthinking this?

Thanks in advance
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4228
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: LFSR
« Reply #1 on: May 17, 2022, 11:07:13 am »
No, it's OK - this is why vendors' synthesis tools are used.

I speak VHDL, not Verilog, but the basic premise is the same - in synchronous logic, any reference to the state of a signal means the state of that signal at the instant just before the active clock edge.

The synthesis tool contains a timing model of the FPGA, which the manufacturer guarantees across voltage, temperature and part-to-part variation. Provided the tool's timing analyser indicates positive setup & hold slack, you compile your code for the correct variant of the device, and you use that device within the manufacturer's recommended spec, then your design will meet timing.

In more complex designs - especially those with multiple clocks - then you do need to very carefully consider how signals cross clock domains, and you must create a timing constraints file (.SDC) which describes the relationships between your clocks and other important signals. Some people make a career out of this.

Incidentally, it's also why open source FPGA tools aren't really a thing. There have been a few attempts, but in the absence of a guaranteed (proprietary) timing model for the device, there's no way to ensure that setup times are met at any particular clock frequency, or that hold times are met at all.
 
The following users thanked this post: NivagSwerdna

Offline NivagSwerdnaTopic starter

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: LFSR
« Reply #2 on: May 17, 2022, 11:33:36 am »
That's interesting. So there is a contract in there somewhere where the LHS relies on the RHS being fixed at some time and the subsequent assignment propagating to the LHS.

I don't know how a FF with feedback actually guarantees this behaviour but it must do otherwise shift registers wouldn't work!

In my example above the feedback is derived by a continuous net assignment ..

E.g.

feedback = out[0] ^ out[2]

Which gives an interesting mix of combinatorial and sequential in the assignment of the register.

This is obviously a trivial case but it is interesting that you mention the implicit rules being applied to the synthesis... I guess I have a lot to learn.

Thanks
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4228
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: LFSR
« Reply #3 on: May 17, 2022, 11:56:41 am »
There's really two parts to this.

Firstly, you need to be able to write code that has a clear, well defined, guaranteed meaning, and that's down to the language itself.

Second, this has to be physically implemented in a way that behaves as per your intent. This is down to causality; a signal cannot, in practice, change until some time after a clock edge has been received. Every logic gate, and the connections between its output and any inputs to other gates (including itself), takes time to switch state because of parasitic capacitance. This, helpfully, guarantees that the input to a gate won't change until *after* a clock has been received, provided the clock itself isn't delayed.

FPGAs contain global clock nets, hard wired into the silicon, for this very reason. It helps ensure that every logic cell gets a clock at more or less the same time, and the data inputs change later - by which time these inputs have already been latched.

 
The following users thanked this post: NivagSwerdna

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4427
  • Country: dk
Re: LFSR
« Reply #4 on: May 17, 2022, 12:45:42 pm »
That's interesting. So there is a contract in there somewhere where the LHS relies on the RHS being fixed at some time and the subsequent assignment propagating to the LHS.

I don't know how a FF with feedback actually guarantees this behaviour but it must do otherwise shift registers wouldn't work!

In my example above the feedback is derived by a continuous net assignment ..

E.g.

feedback = out[0] ^ out[2]

Which gives an interesting mix of combinatorial and sequential in the assignment of the register.

This is obviously a trivial case but it is interesting that you mention the implicit rules being applied to the synthesis... I guess I have a lot to learn.

Thanks


the simplest explanation is that nothing can happen instantly, so an FF output cannot change until some time after the clock edge, reacting on what the input was right before the clock edge

 
 
The following users thanked this post: NivagSwerdna

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: LFSR
« Reply #5 on: May 17, 2022, 02:45:29 pm »
.
« Last Edit: August 19, 2022, 05:29:48 pm by emece67 »
 
The following users thanked this post: NivagSwerdna

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: LFSR
« Reply #6 on: May 17, 2022, 03:05:26 pm »
That's interesting. So there is a contract in there somewhere where the LHS relies on the RHS being fixed at some time and the subsequent assignment propagating to the LHS.

I don't know how a FF with feedback actually guarantees this behaviour but it must do otherwise shift registers wouldn't work!

In my example above the feedback is derived by a continuous net assignment ..

E.g.

feedback = out[0] ^ out[2]

Which gives an interesting mix of combinatorial and sequential in the assignment of the register.

This is obviously a trivial case but it is interesting that you mention the implicit rules being applied to the synthesis... I guess I have a lot to learn.

Thanks

You need to understand how synchronous logic is described in Verilog. You will use synchronous logic to design this LFSR. Let's code up a simple (standard) shift register, which shifts left on each tick of the clock.

Code: [Select]

reg [7:0] sr;
reg          inbit;

always @(posedge clk or negedge rst_l) begin   // 1
    if (~rst_l) begin                                                // 2
        sr <= 0;                                                        // 3     
    end
    else begin                                                        // 4
        sr<= { sr[6:0], inbit };                                 // 5
    end
end

Let's look at this in detail.

Line 1 is the start of the block and includes the sensitivity list. The sensitivity list details all signals that trigger the block. Changes on any other signals are ignored. In this case, our block is sensitive to the rising edge of the clock and the falling edge of an asynchronous reset.

Line 2: test for the assertion of the async reset. How do we know it's an asynchronous reset? It doesn't care about the clock. And we wrote it first in our block, so it has precedence over the clock. If the reset is low, then the shift register is cleared and the block suspends until the next event on the sensitivity list. Do note the use of the <= non-blocking assignment operator. it's not the same as the standard blocking assignment = and "non-blocking" means that the assignment is scheduled and could be overwritten if there is a later assignment to the same signal in the block. The last assignment wins. It is vital that you understand the difference. "Blocking" means that the left-hand-side signal takes on the new value immediately and in real hardware with a flip-flop, that is not what happens.

Also note that in a synchronous system, the clock is always running. You can -- and likely will -- get a rising edge of clk when the reset is asserted. The code above says, "OK, fine, I saw a rising edge on the clock. But reset is active, so I will clear the shift register and basically ignore the clock." This is exactly the behavior you want.

Line 3 is where we clear the shift register.

Line 4: "else." Since the block is triggered by only two events -- rising clock, falling reset -- and we've already tested for the assertion of reset, then the only possible reason the block was triggered is because we saw the clock rising edge.

Line 5: on the clock rising edge: look at the current state of the signals sr and inbit. What are their values at the instant the clock edge occurred? Take those values and use them to schedule an assignment to sr. And when you've finished evaluating all right-hand sides of all statements in your block, sr is updated and now has the new value you assigned.

Since our block is sensitive only to the clock and reset, the change in the value of sr does not trigger the block and all is well.

Really, all of the above is fundamental Verilog and you must understand it if you are to be successful.

(Also, VHDL works the same way, with the exception that all assignments are non-blocking unless you specifically use variables, and variables don't exist outside of the process in which they are declared.)

Hope this helps.
« Last Edit: May 17, 2022, 03:07:34 pm by Bassman59 »
 
The following users thanked this post: edavid, NivagSwerdna, ch_scr

Offline NivagSwerdnaTopic starter

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: LFSR
« Reply #7 on: May 17, 2022, 06:05:56 pm »
Thanks all.  I'm teaching myself this so it isn't always obvious what I don't know!

The various points made above have been very helpful!

Specifically I hadn't appreciated the significance of tSetup and tHold but now I appreciate those I can also appreciate the issue with clock skew in the context of synchronous logic!  That all makes sense now.

I also spent some quality time with the IEEE Verilog Standard and this does describe the semantics that I had anticipated... i.e in temporal terms the RHS is evaluated prior to assignment to the LHS so that seems to fit my mental model.

There is an example here... https://www.nandland.com/vhdl/modules/lfsr-linear-feedback-shift-register.html

I'm quite intrigued by... (Assuming 8 bits)...

Code: [Select]
  always @(posedge i_Clk)
    begin
           ...
           r_LFSR <= {r_LFSR[8-1:1], r_XNOR};
           ...
    end


and

Code: [Select]
  always @(*)
    begin
          r_XNOR = r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4];
    end // always @ (*)

My remaining questions:
  • In the first always block the use of = and <= would produce the same result?
  • The feedback value is separated into a different block, couldn't it be evaluated in the same block or would that halve the cycle rate?
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: LFSR
« Reply #8 on: May 17, 2022, 06:24:05 pm »
Here is a 43 bit LFSR & 37 bit CASR examples, synchronous logic with XOR feedback at selected bits.  You can easily regenerate an 8bit / or any other size from this example:
always @(posedge clk) begin...
                    CASR[36:0] <= ( {CASR[35:0],CASR[36]} ^ {CASR[0],CASR[36:1]} ^ CASR[27]<<27 ) ;
                    LFSR[42:0] <= ( {LFSR[41:0],LFSR[42]} ^ LFSR[42]<<41 ^ LFSR[42]<<20 ^ LFSR[42]<<1 ) ;

                    out [31:0] <= ( LFSR [31:0] ^ CASR[31:0] );

The parts in red contain the circulating buffer.  The parts in green select which bits are xored at which bit position when injected back into the oscillator.  Remember, you need a power-up or reset set point which does not equal '0'. Note that to improve random coverage, even though my final 'out' is only a 32 bit number, I do require a larger width LFSR than 32 bits to achieve all possible numbers.  Example, with a 8 bit LFSR, do not expect every possible 8 bit number out as a result.  You probably need a well tuned 13 bit LFSR to get every possible 8bit result out of it.  Mixing 2 types of random number generators at different widths does improve the fine spectrum granularity of the white noise output but LFSR all by itself is fine for many applications.


Full code:
Code: [Select]
module rnd ( clk, rst, ena, load, seed, out );

input             clk, rst, ena, load;
input      [31:0] seed ;
output reg [31:0] out ;

reg[36:0] CASR;
reg[42:0] LFSR;
always @(posedge clk) begin

   if ( rst ) begin

                    CASR  <= (37'h100000000); // Random starting point.
                    LFSR  <= (43'h100000000); // Random starting point.

   end else if (load) begin

                    CASR  <= 37'(seed) | 33'h100000000 ; // Load seed, protect from a seed of 0.
                    LFSR  <= 43'(seed) | 33'h100000000 ; // Load seed, protect from a seed of 0.

   end else if (ena) begin

                    CASR[36:0] <= ( {CASR[35:0],CASR[36]} ^ {CASR[0],CASR[36:1]} ^ CASR[27]<<27 ) ;
                    LFSR[42:0] <= ( {LFSR[41:0],LFSR[42]} ^ LFSR[42]<<41 ^ LFSR[42]<<20 ^ LFSR[42]<<1 ) ;

                    out [31:0] <= ( LFSR [31:0] ^ CASR[31:0] );

    end
end
endmodule
« Last Edit: May 17, 2022, 06:38:20 pm by BrianHG »
 
The following users thanked this post: NivagSwerdna

Offline NivagSwerdnaTopic starter

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: LFSR
« Reply #9 on: May 17, 2022, 06:49:01 pm »
So @BrianHG this is a great example... 

Taking just the CASR...

Does it tick once per clock?  i.e. is the expression within the RHS

CASR[36]} ^ {CASR[0]
CASR[36:1]} ^ CASR[27]
<<27
concatenation
assignment

All done in one cycle?

(I guess that is a slightly loaded question since it probably depends on the propagation time evaluating the expressions to fit within cycle time)

PS
I did say I was over thinking this!
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: LFSR
« Reply #10 on: May 17, 2022, 06:53:07 pm »
Also, google LFSR and Xilinx.  They have a white paper with the optimum xor mixing bit positions for LFSR width from 5 bit through at least 16 bits if not 24 from memory.  You would just edit my above code to their table of optimum XOR points for each width.  The also cover the topic of output coverage and you will notice that you will see it is never 100%, otherwise a seed of '0' should run the random number generator, yet it wont.
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4427
  • Country: dk
Re: LFSR
« Reply #11 on: May 17, 2022, 07:01:36 pm »
Also, google LFSR and Xilinx.  They have a white paper with the optimum xor mixing bit positions for LFSR width from 5 bit through at least 16 bits if not 24 from memory.  You would just edit my above code to their table of optimum XOR points for each width.  The also cover the topic of output coverage and you will notice that you will see it is never 100%, otherwise a seed of '0' should run the random number generator, yet it wont.

xapp052 list the taps for LFSRs with 3 to 168 bits
 
The following users thanked this post: BrianHG

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: LFSR
« Reply #12 on: May 17, 2022, 07:03:55 pm »
In verilog programming, everything on the right side of the ' <= ' is instantly evaluated all as instant logic gates and wires, including the concatenation.  The reg on the left side of the ' <= ' is a block of D-flipflops clocked by the always @(posedge clk) since it is contained within that always.  Everything happens in parallel.

It is the FPGA compiler's job to worry about every D- input of the reg on the left side being ready in time by the next clock which is where you eventually end up running into an FMAX bottle neck with huge formulas with huge bits on the right side.

Note that in my example which uses 2 random number generators in parallel, because my 'out' has its own ' <= ', my out result is delayed 1 additional clock compared to the LFSR and CASR generators.  If you do not want this delay, my code would have looked like this:

Code: [Select]
module rnd ( clk, rst, ena, load, seed, out );

input             clk, rst, ena, load;
input         [31:0] seed ;
output wire [31:0] out ;

reg[36:0] CASR;
reg[42:0] LFSR;

assign  out [31:0] = ( LFSR [31:0] ^ CASR[31:0] );

always @(posedge clk) begin

   if ( rst ) begin

                    CASR  <= (37'h100000000); // Random starting point.
                    LFSR  <= (43'h100000000); // Random starting point.

   end else if (load) begin

                    CASR  <= 37'(seed) | 33'h100000000 ; // Load seed, protect from a seed of 0.
                    LFSR  <= 43'(seed) | 33'h100000000 ; // Load seed, protect from a seed of 0.

   end else if (ena) begin

                    CASR[36:0] <= ( {CASR[35:0],CASR[36]} ^ {CASR[0],CASR[36:1]} ^ CASR[27]<<27 ) ;
                    LFSR[42:0] <= ( {LFSR[41:0],LFSR[42]} ^ LFSR[42]<<41 ^ LFSR[42]<<20 ^ LFSR[42]<<1 ) ;

    end
end
endmodule

This version of my code returns the result 1 clock sooner at the expense of a slightly lower potential FMAX when wired to the next module in the system.  This is because the ' assign out = ' is not a register and clocked, it is immediate hard wired async XOR gates.  However, this is only an issue when you want to run this random number generator above 250MHz on a slow FPGA.
« Last Edit: May 17, 2022, 07:16:32 pm by BrianHG »
 
The following users thanked this post: NivagSwerdna

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: LFSR
« Reply #13 on: May 17, 2022, 07:54:29 pm »
Specifically I hadn't appreciated the significance of tSetup and tHold but now I appreciate those I can also appreciate the issue with clock skew in the context of synchronous logic!  That all makes sense now.

For purposes of functional and behavioral modeling, setup and hold times actually don't matter.  The FPGA timing analysis takes them into account when determining whether your design meets your clock period constraint. Inside the FPGA, you actually have no idea what the set-up and hold time need to be, but you don't care. The tools manage all of it.

(Of course it's different when interface the FPGA to some external peripheral logic. That's not what we are concerned with here.)

Quote
I also spent some quality time with the IEEE Verilog Standard and this does describe the semantics that I had anticipated... i.e in temporal terms the RHS is evaluated prior to assignment to the LHS so that seems to fit my mental model.

Yes, exactly, but remember when they are evaluated. Also understand that conditionals (if statements, for example) are considered to be on the right-hand-side of any assignment.

Quote
I'm quite intrigued by... (Assuming 8 bits)...

Code: [Select]
  always @(posedge i_Clk)
    begin
           ...
           r_LFSR <= {r_LFSR[8-1:1], r_XNOR};
           ...
    end


and

Code: [Select]
  always @(*)
    begin
          r_XNOR = r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4];
    end // always @ (*)

Well, the differences between the two are quite obvious from their sensitivity lists: the former is a synchronous process, triggered only with a rising edge on the clock, and the latter is combinatorial. The sensitivity list shortcut * means "every signal on the right-hand side of the assignment in this block." So the block is triggered when any of the four signals on your RHS change.

And do note the different assignment operators! In the synchronous block we use <= and in the combinatorial block we use =. Why? Because we want the combinatorial result to update immediately after evaluation.

(This simple example really doesn't make it clear why, but when you get into more complex synchronous processes you will appreciate the difference.)


Quote
My remaining questions:
  • In the first always block the use of = and <= would produce the same result?

This is a "gotcha" question. The answer is: yes. But only because the design is so simple. When you have a lot of always blocks in parallel, all synchronous to the clock, the idea is that all left-hand sides update simultaneously. The non-blocking assignment guarantees that. The blocking assignment does not.

There is a classic paper on this topic. Read it. Grok it. I cannot stress enough how important it is to understand this.

Quote
  • The feedback value is separated into a different block, couldn't it be evaluated in the same block or would that halve the cycle rate?

I would roll the feedback calculation into the same synchronous block that calculates the result. I don't see the point of separating them.

In reality, what will happen is that the synchronous block will, after a rising edge, give you a new r_LFSR, and immediately after the combinatorial block gives you a new r_XNOR. But! The synchronous block won't look at that new r_XNOR until the next clock edge.

You should simulate this to convince yourself that it's true.
« Last Edit: May 17, 2022, 07:56:37 pm by Bassman59 »
 
The following users thanked this post: NivagSwerdna

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4427
  • Country: dk
Re: LFSR
« Reply #14 on: May 17, 2022, 08:38:45 pm »
Specifically I hadn't appreciated the significance of tSetup and tHold but now I appreciate those I can also appreciate the issue with clock skew in the context of synchronous logic!  That all makes sense now.

For purposes of functional and behavioral modeling, setup and hold times actually don't matter.  The FPGA timing analysis takes them into account when determining whether your design meets your clock period constraint. Inside the FPGA, you actually have no idea what the set-up and hold time need to be, but you don't care. The tools manage all of it.

(Of course it's different when interface the FPGA to some external peripheral logic. That's not what we are concerned with here.)

Quote
I also spent some quality time with the IEEE Verilog Standard and this does describe the semantics that I had anticipated... i.e in temporal terms the RHS is evaluated prior to assignment to the LHS so that seems to fit my mental model.

Yes, exactly, but remember when they are evaluated. Also understand that conditionals (if statements, for example) are considered to be on the right-hand-side of any assignment.

Quote
I'm quite intrigued by... (Assuming 8 bits)...

Code: [Select]
  always @(posedge i_Clk)
    begin
           ...
           r_LFSR <= {r_LFSR[8-1:1], r_XNOR};
           ...
    end


and

Code: [Select]
  always @(*)
    begin
          r_XNOR = r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4];
    end // always @ (*)

Well, the differences between the two are quite obvious from their sensitivity lists: the former is a synchronous process, triggered only with a rising edge on the clock, and the latter is combinatorial. The sensitivity list shortcut * means "every signal on the right-hand side of the assignment in this block." So the block is triggered when any of the four signals on your RHS change.

And do note the different assignment operators! In the synchronous block we use <= and in the combinatorial block we use =. Why? Because we want the combinatorial result to update immediately after evaluation.

(This simple example really doesn't make it clear why, but when you get into more complex synchronous processes you will appreciate the difference.)


Quote
My remaining questions:
  • In the first always block the use of = and <= would produce the same result?

This is a "gotcha" question. The answer is: yes. But only because the design is so simple. When you have a lot of always blocks in parallel, all synchronous to the clock, the idea is that all left-hand sides update simultaneously. The non-blocking assignment guarantees that. The blocking assignment does not.

There is a classic paper on this topic. Read it. Grok it. I cannot stress enough how important it is to understand this.

Quote
  • The feedback value is separated into a different block, couldn't it be evaluated in the same block or would that halve the cycle rate?

I would roll the feedback calculation into the same synchronous block that calculates the result. I don't see the point of separating them.

In reality, what will happen is that the synchronous block will, after a rising edge, give you a new r_LFSR, and immediately after the combinatorial block gives you a new r_XNOR. But! The synchronous block won't look at that new r_XNOR until the next clock edge.

You should simulate this to convince yourself that it's true.

for simulation, something like: 

r_LFSR <= #1 {r_LFSR[8-1:1], r_XNOR};


will help illustrate that r_LFSR doesn't change until after the clock edge

 

Offline NivagSwerdnaTopic starter

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: LFSR
« Reply #15 on: May 17, 2022, 10:37:31 pm »
It seems to work... thanks for the help people...

Code: [Select]
module lsfr (
    input i_clk,
    input i_reset,
    input i_sample,
    output [15:0] o_lfsr_data,
    output [31:0] o_lfsr_counter
);

reg [15:0] r_lfsr = 0;
reg [31:0] r_counter = 0;

reg r_feedback;

 always @(posedge i_clk)
    begin
      if (i_reset == 1)
        begin
r_lfsr = 0;
            r_counter = 0;
        end
else
begin
r_lfsr <= {r_lfsr[14:0], r_feedback};
            r_counter <= r_counter + 1;
end
    end

  always @(*)
    begin
r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
end

     assign o_lfsr_data = r_lfsr;
     assign o_lfsr_counter = r_counter;

endmodule
« Last Edit: May 17, 2022, 10:58:57 pm by NivagSwerdna »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: LFSR
« Reply #16 on: May 17, 2022, 11:21:16 pm »
Why didn't you:

Code: [Select]
module lsfr (
    input i_clk,
    input i_reset,
    input i_sample,
    output [15:0] o_lfsr_data,
    output [31:0] o_lfsr_counter
);

reg [15:0] r_lfsr = 0;
reg [31:0] r_counter = 0;

// *** Option 1 ***
wire   r_feedback ;
assign r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
// *** Option 2 ***
wire r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
// *** Option 3 ***
wire r_feedback = (1)'( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) ^ i_sample;
// *** Option 4 ***
wire r_feedback = r_lfsr[15] ^ r_lfsr[11] ^ r_lfsr[8] ^ r_lfsr[6] ^  i_sample;

 always @(posedge i_clk)
    begin
      if (i_reset == 1)
        begin
r_lfsr = 0;
            r_counter = 0;
        end
else
begin
r_lfsr <= {r_lfsr[14:0], r_feedback};
            r_counter <= r_counter + 1;
end
    end

     assign o_lfsr_data = r_lfsr;
     assign o_lfsr_counter = r_counter;

endmodule


Note that your code only shifts in a random bit and slides everything to the left every clock.  You have no flipping bits in the middle.
Also note that when you reset your LFSR, you make it 0, so unless your input is 1 when clocking, the output will remain 0.
« Last Edit: May 17, 2022, 11:23:04 pm by BrianHG »
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: LFSR
« Reply #17 on: May 18, 2022, 12:17:50 am »
One really neat project to play with LFSRs is making a self-synchronizing scrambler and descrambler. They are used to convert data into what looks to be pseudo-random bits, and then make the original data reappear from the 'noise' again! It really does seem like magic...

The source data stream is combined with an LFSR, and transmitted. At the receiving end the 'scrambled' bits are put into a second LFSR, and the original bits pop out again!

https://en.wikipedia.org/wiki/Scrambler

They are pretty much used wherever high speed serial comms is used (10GbE, DisplayPort, PCI, SDI, SATA, later HDMI standards, 64B66B coding...). It is used because it ensures that even if the data stream is all 1s or 0s the scrambled version has lots of bit transitions. This allows the receiver's clock recovery to work.

It is the sort of project where the learnings will pop up over and over again in different domains.

10/10 - highly recommended.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline NivagSwerdnaTopic starter

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: LFSR
« Reply #18 on: May 18, 2022, 07:39:47 am »
Code: [Select]
// *** Option 1 ***
wire   r_feedback ;
assign r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
// *** Option 2 ***
wire r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
// *** Option 3 ***
wire r_feedback = (1)'( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) ^ i_sample;
// *** Option 4 ***
wire r_feedback = r_lfsr[15] ^ r_lfsr[11] ^ r_lfsr[8] ^ r_lfsr[6] ^  i_sample;
Option 1 & 2 appear identical?
Option 3 is intereresting, I wonder if that differs
Option 4... I'm not sure about that... I'm not sure it is equivalent.
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 4427
  • Country: dk
Re: LFSR
« Reply #19 on: May 18, 2022, 08:16:08 am »
One really neat project to play with LFSRs is making a self-synchronizing scrambler and descrambler. They are used to convert data into what looks to be pseudo-random bits, and then make the original data reappear from the 'noise' again! It really does seem like magic...

The source data stream is combined with an LFSR, and transmitted. At the receiving end the 'scrambled' bits are put into a second LFSR, and the original bits pop out again!

https://en.wikipedia.org/wiki/Scrambler

They are pretty much used wherever high speed serial comms is used (10GbE, DisplayPort, PCI, SDI, SATA, later HDMI standards, 64B66B coding...). It is used because it ensures that even if the data stream is all 1s or 0s the scrambled version has lots of bit transitions. This allows the receiver's clock recovery to work.

It is the sort of project where the learnings will pop up over and over again in different domains.

10/10 - highly recommended.

and also https://en.wikipedia.org/wiki/Direct-sequence_spread_spectrum
 

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 19504
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: LFSR
« Reply #20 on: May 18, 2022, 08:44:58 am »
FSMs are the key starting point for digital logic design.

Just as with computer programming languages, there are "design patterns" for hardware programming languages.

One of the most useful ones for FSMs is the "two process" pattern, where you conceptually and logically separate the (asynchronous) combinatorial logic from the (synchronous) storage - and encode them separately.

The thinking is along the lines of:
  • combinatorial logic encodes the "given the current state and the inputs", the next state should be". That's where the interesting design and implementation occurs, and can be arbitrarily complex - and slow
  • the flip flop logic is "when the clock occurs the current state becomes the next state". That's trivial to code!
You will be aware that HDLs have different syntax and constructs for the asynchronous and synchronous parts.

Oddly enough that pattern is also very useful in real-time software systems, but few softies are taught it :(

(BTW, are you going to the Dunstable Downs hamfest on Sunday?)
« Last Edit: May 18, 2022, 08:47:07 am by tggzzz »
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: LFSR
« Reply #21 on: May 18, 2022, 07:16:04 pm »
One of the most useful ones for FSMs is the "two process" pattern, where you conceptually and logically separate the (asynchronous) combinatorial logic from the (synchronous) storage - and encode them separately.

Again with the two-process latch-generator.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: LFSR
« Reply #22 on: May 18, 2022, 07:45:13 pm »
Code: [Select]
// *** Option 1 ***
wire   r_feedback ;
assign r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
// *** Option 2 ***
wire r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
// *** Option 3 ***
wire r_feedback = (1)'( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) ^ i_sample;
// *** Option 4 ***
wire r_feedback = r_lfsr[15] ^ r_lfsr[11] ^ r_lfsr[8] ^ r_lfsr[6] ^  i_sample;
Option 1 & 2 appear identical?
Option 3 is intereresting, I wonder if that differs
Option 4... I'm not sure about that... I'm not sure it is equivalent.
Ok, fine, but there was a larger point I was making.

Your :
Code: [Select]
reg r_feedback;
...
  always @(*)
    begin
r_feedback = (( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample;
end

You requested that an un-clocked register / logic cell 'r_feedback' buffer was to be generated.  Now, most modern compilers like Altera and Xilinx will see this and automatically remove the redundant logic cell and convert the r_feedback into a wire changing what you wrote :

r_lfsr <= {r_lfsr[14:0], r_feedback};

into this :
r_lfsr <= {r_lfsr[14:0], ((( r_lfsr[15] + r_lfsr[11] + r_lfsr[8] + r_lfsr[6]) % 2) ^ i_sample) };

However, if you were to use a dumber FPGA compiler or, say within Altera, in the compile options, set the feature 'remove redundant logic cells' to 'OFF', compiling your design will generate a different result.  The compiler will create an UN-clocked logic cell whose inputs are connected to a structure of gates equaling what you write inside your 'always @(*)', and that 'r_feedback' logic cell's output will feed the your 'r_lfsr <= ' adding FPGA routing, and slowing down your maximum possible FMAX.  My 'wire r_feedback =' will not suggest to the compiler that you wish to deliberately slow down and add the extra logic cell and routing involved in your design.
« Last Edit: May 18, 2022, 07:47:58 pm by BrianHG »
 

Offline NivagSwerdnaTopic starter

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: LFSR
« Reply #23 on: May 19, 2022, 04:51:07 pm »
Ah. Yes. I meant wire for feedback. That was not intentional!

The part about being optimised away is especially interesting.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf