Question
I am very new to HDL language. I have a question about how to program a shift register. (i know i shift to the other direction). Why does the book use wire[N-1:0] r_next
? what's drawback of my implementation?
thanks
my first try is as following
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
Solution
First of all, don't forget your begin
-end
s 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
statement. This will work, but is considered bad style due to the blocking statements in a sequential logic description...
Second, for modeling sequential blocks, use nonblocking assignments (<=
) or your calculations may 'fall through' (google nonblocking vs blocking for more info). Your example may very well work (did you try it in a simulator?) but if things get more complicated and more variables are added things can 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 the above reason, it is sometimes recommended that combo logic is separated from sequential logic so that you can write nonblocking assignments to registers in sequential blocks, and blocking in combo blocks and never have to worry about the scheduling.
To code in this way, you need to calculate what the next output should be using the current state, hence the r_next
bus in the answer. I think it tends to help the synthesis tool out too if all the flip-flops are separated from surrounding combo logic in this way.
Also, if your reset is active low (ie LOW
resets ) it should be named as such, eg resetb
or reset_n
.
OTHER TIPS
Your implementation produces quite a different output from the book's. You should prove this to yourself by constructing a simple testbench to drive your inputs and run a simulation. You will see that the book's output shifts the input data by a single clock cycle, whereas your output shifts the input data by eight clock cycles.
By the way you have indented your always
block, I am led to believe that it is not what you wanted. This is how your block really behaves:
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
keywords in if/else
statements to avoid this confusion.
The way it simulates, r_reg
is always 0 because you clobber the 1st assignment (r_reg[0]=data;
) with the 2nd (r_reg = r_reg<<1;
). Another difference is that the book assigns data
to the MSB of the shift register, but you assign it to the LSB.
If you are using decent linting and synthesis tools, you would probably get a bunch of warnings for your code. This would alert you to make some changes.