Verilog shift registers

I am very new to HDL. I have a question on how to program a shift register. (I know that I am moving in a different direction). Why wire[N-1:0] r_next book use wire[N-1:0] r_next ? what is the drawback of my implementation? thanks

My first attempt is as follows:

 module lesson04#(parameter N=8)( input wire clk, reset, input wire data, output wire out ); reg [N-1: 0] r_reg; always @(posedge clk or negedge reset) begin if(!reset) r_reg =0; else r_reg[0]=data; r_reg = r_reg<<1; end assign out =r_reg[N-1]; endmodule 

but the book gives:

 module lesson04#(parameter N=8)( input wire clk, reset, input wire data, output wire out ); reg [N-1: 0] r_reg; wire[N-1:0] r_next; always @(posedge clk or negedge reset) begin if(!reset) r_reg =0; else r_reg <= r_next; end assign r_next= {data, r_reg[N-1:1]}; assign out =r_reg[N-1]; endmodule 
+4
source share
2 answers

First of all, don't forget about begin - end around sections of code:

 else begin r_reg[0]=data; r_reg = r_reg<<1; end 

Without this, only r_reg[0]=data will be in the else clause of the if . This will work, but is considered bad style due to blocking statements in a consistent logical description ...

Secondly, to simulate sequential blocks, use non-blocking assignments ( <= ), or your calculations may fail (google non-blocking and blocking for more information). Your example may work very well (did you try it in the simulator?), But if the situation gets complicated and more variables are added, everything may break.

 always @(posedge clk or negedge reset) begin if(!reset) r_reg <= 0; else begin // This is horrible! Don't write code like this! r_reg[0] = data; // blocking r_reg <= r_reg<<1; // non-blocking end end 

For this reason, it is sometimes recommended that combined logic be separated from sequential logic so that you can write non-blocking assignments to registers in sequential blocks and block in combined blocks and never worry about scheduling.

To program this way, you need to calculate which next output should use the current state, and therefore the r_next bus in the response. I think this also helps the synthesis tool if all the triggers are separated from the surrounding combo logic in this way.

Also, if your reset is active low (i.e., LOW resets), it should be named as such, e.g. resetb or reset_n .

+6
source

Your implementation produces a very different conclusion from the book. You have to prove it to yourself by building a simple test bench to control your inputs and run the simulation. You will see that the output of the book shifts the input data in one clock cycle, while your output shifts the input data by eight clock cycles.

By the way, you stepped back from your always block, I am convinced that this is not what you wanted. This is what your block does:

 always @(posedge clk or negedge reset) begin if(!reset) begin r_reg =0; end else begin r_reg[0]=data; end r_reg = r_reg<<1; end 

I always explicitly use the begin/end in if/else to avoid this confusion.

The way it mimics r_reg always 0 because you clobber the first assignment ( r_reg[0]=data; ) with the second ( r_reg = r_reg<<1; ). Another difference is that the book assigns the shift register MSB data , but you assign it an LSB.

If you use decent casting and synthesis tools, you'll probably get a bunch of warnings for your code. This will warn you of some changes.

+3
source

All Articles