How to create a simple one stage pipeline in Verilog?
The easiest way to create a single state pipeline is create two always block synchronized with piped input(in_pipe) as given below. This work because of how the events are queued in the simulator time cycle.
module pipeline (reset,in,clock,out)
input reset, input, clock;
output out;`
logic reset, input, clock;
reg out, in_pipe;
always #(posedge clock or negedge reset)
begin
if(reset)
begin
in_pipe <= 0;
end
else
begin
in_pipe <= in;
end
end
always #(posedge clock or negedge reset)
begin
if(reset)
begin
out<= 0;
end
else
begin
out<= in_pipe;
end
end
module pipeline#(
parameter PIPE_NUM = 2,
parameter DATA_WIDTH = 32
)(
input clock,
input [DATA_WIDTH-1:0]data_in,
output [DATA_WIDTH-1:0]data_out
);
//synthesis translate_off
initial begin
if(PIPE_NUM < 1) begin
$fatal("Error: PIPE_NUM must be greater than 0!");
end
end
//synthesis translate_on
reg [DATA_WIDTH-1:0]pipeline_reg[PIPE_NUM-1:0]/*synthesis preserve*/;
assign data_out = pipeline_reg[PIPE_NUM-1];
integer p;
always #(posedge clock)begin
pipeline_reg[0] <= data_in;
for(p = 1;p < PIPE_NUM;p = p+1)begin
pipeline_reg[p] <= pipeline_reg[p-1];
end
end
endmodule
Related
The monostable module implements a monostable multivibrator. It takes in three inputs (clk, reset, trigger) and outputs a single (pulse).
The trigger input triggers the module. When triggered, the output signal (pulse) will switch to a high position for a period of clock ticks, and then return to a low position. The pulse width of the output signal can be set via the PULSE_WIDTH parameter, which represents the period in clock ticks that the signal should stay high.
Now, what is happening is when it gets triggered, immediately output signal (pulse) is getting high.
When triggered, the output signal (pulse) should be high on the next active edge of clk. What changes can be done ?
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count = 0;
wire countReset = reset | (count == PULSE_WIDTH);
always #(posedge trigger, posedge countReset) begin
if (countReset) begin
pulse <= 1'b0;
end else begin
pulse <= 1'b1;
end
end
always #(posedge clk, posedge countReset) begin
if(countReset) begin
count <= 0;
end else begin
if(pulse) begin
count <= count + 1'b1;
end
end
end
endmodule
module monostable_tb();
reg clk;
reg reset;
reg trigger;
wire pulse;
parameter PULSE_WIDTH = 20;
monostable imonostable(.*);
initial begin
clk=0;
forever #50 clk=~clk;
end
initial begin
$monitor("trigger=%b pulse=%b, count = %0d",trigger,pulse,imonostable.count);
$dumpfile("monostable_tb.vcd");
$dumpvars(0,monostable_tb);
trigger=1'b0;
reset = 1'b0;
#(posedge clk) reset = 1'b1;
#(posedge clk) reset = 1'b0;
#(posedge clk) trigger=1'b1;
#(posedge clk) trigger=1'b0;
repeat(25) #(posedge clk);
$finish;
end
endmodule
Here is a simplified design which sets the output one cycle after the input trigger pulse, and keeps the output high for 20 cycles:
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count;
always #(posedge clk, posedge reset) begin
if (reset) begin
pulse <= 1'b0;
end else if (trigger) begin
pulse <= 1'b1;
end else if (count == PULSE_WIDTH-1) begin
pulse <= 1'b0;
end
end
always #(posedge clk, posedge reset) begin
if(reset) begin
count <= 0;
end else if (pulse) begin
count <= count + 1'b1;
end
end
endmodule
It now uses a single clock signal, instead of 2. It also uses a simple reset signal, which can avoid potential glitches causing unwanted asynchronous resets.
You should also use nonblocking assignments in the testbench:
#(posedge clk) reset <= 1'b1;
#(posedge clk) reset <= 1'b0;
#(posedge clk) trigger<= 1'b1;
#(posedge clk) trigger<= 1'b0;
If a 1-clock synchronous delay is needed, then run the output thru a flip flop.
module monostable(
input clk,
input reset,
input trigger,
output reg pulse = 0
);
parameter PULSE_WIDTH = 20;
reg [4:0] count = 0;
reg reg_pulse_temp;
wire countReset = reset | (count == PULSE_WIDTH);
always #(posedge trigger, posedge countReset) begin
if (countReset) begin
reg_pulse_temp <= 1'b0;
end else begin
reg_pulse_temp <= 1'b1;
end
end
always #(posedge clk, posedge countReset) begin
if(countReset) begin
count <= 0;
// reset the flop
pulse <= 0;
end else begin
if(pulse) begin
count <= count + 1'b1;
end
end
// flip flop
pulse <= reg_pulse_temp;
end
endmodule
Is following code deterministic? i.e Can it trigger error1 or error2? Is there a recommended way for generating clk2 (same as clk3)
module Test();
reg clk1;
reg clk2;
reg clk3;
reg reset;
initial
begin
clk1 <= 0;
forever
begin
#100;
clk1 <= ~clk1; // 2x freq of clk2/clk3
end
end
always #(posedge clk1)
begin
if(reset) clk2 <= 0;
else clk2 <= ~clk2;
end
initial
begin
clk3 <= 0;
#300;
forever
begin
#200;
clk3 <= ~clk3;
end
end
initial
begin
reset <= 1;
#500;
reset <= 0;
#100;
repeat (20) #(posedge clk1);
$display("Test end");
$finish;
end
always #(posedge clk2)
begin
if(clk1 == 0) $display("Error1");
end
always #(posedge clk3)
begin
if(clk1 == 0) $display("Error2");
end
endmodule;
Your code has problems, but nothing to do with determinism—it is fully deterministic. This is one case where using NBAs <= creates a problem. clk2 gets updated in a delta cycle after clk1 and clk3. That means if you have clock domain crossings from the latter to clk2 like
always_ff #(posedge clk3)
A <= B;
always_ff #(posedge clk2)
C <= A; // A has already been updated with the value of B
So never use NBAs to make assignments to clocks.
I want to build a Verilog module so that the user can select the sensitivity of some input clock signal by a module parameter. As an example, I wrote the following counter which can either count up on posedge or negedge selected by parameter clockEdge.
module Counter (clk, reset, value);
parameter clockEdge = 1; // react to rising edge by default
input clk;
input reset;
output reg [7:0] value;
generate
if(clockEdge == 1) begin
always #(posedge clk or posedge reset) begin
if (reset) begin
value <= 0;
end else begin
value <= value + 1;
end
end
end else begin
always #(negedge clk or posedge reset) begin
if (reset) begin
value <= 0;
end else begin
value <= value + 1;
end
end
end
endgenerate
endmodule
This principle is working, however I don't like that the implementation is basically copy and paste for both variants. What would be a shorter version without duplication?
Simplest is to invert the clock with an exor gate. Then use that clock in an always section:
wire user_clock;
assign user_clock = clk ^ falling_edge;
always #(posedge user_clock) // or posedge/negedge reset/_n etc.
test_signal <= ~ test_signal;
If falling_edge is 0 then user_clock and clk have the same polarity and the data is clocked at nearly the same time as you have a rising edge of clk.
If falling_edge is 1 then user_clock and clk have the opposite polarity and the data is clocked nearly the same time as the falling edge of clk.
Be careful when you change the polarity of falling_edge as it can generate runt clock pulses! Safest is to use a gated clock: stop the clock, switch polarity, then start it again.
In both cases user_clock will lag the system clk by small amount. The amount depends on the delay of the exor-gate.
Here is a simulation+:
+test_signal was set to zero in an initial statement.
I think that cut-n-paste in this tiny example is ok, though verilog has some instruments to make it easier for more complicated cases, namely functions and macros. You can use them as well, i.e.
function newValue(input reset, input reg[7:0] oldValue);
if (reset) begin
newValue = 0;
end else begin
newValue = value + 1;
end
endfunction
generate
if(clockEdge == 1) begin
always #(posedge clk or posedge reset) begin
value <= newValue(reset, value);
end
end else begin
always #(negedge clk or posedge reset) begin
value <= newValue(reset, value);
end
end
endgenerate
the other possibility is to use macros with or without paramenters. Methodology-wise macros are usually worse than functions, though here is an extreme example, though in my opinion it makes the code less readable and could have issues with debugging tools.
`define NEW_VALUE(clk_edge) \
always #(clk_edge clk or posedge reset) begin\
if (reset) begin\
value <= 0;\
end else begin\
value <= value + 1;\
end\
end
generate
if(clockEdge == 1) begin
`NEW_VALUE(posedge)
end else begin
`NEW_VALUE(negedge)
end
endgenerate
Implementing custom clock reg that follows posedge or negedge of clk might be one way to do it. This seems to work well on my machine :)
reg myclk;
always#(clk) begin
if(clk) begin
myclk = clockEdge? 1 : 0; #1 myclk = 0;
end else begin
myclk = clockEdge? 0 : 1; #1 myclk = 0;
end
end
always#(posedge myclk or posedge reset) begin
if(reset)
cnt <= 0;
else
cnt <= cnt+1;
end
The following is a snippet from a code I wrote in verilog for XST. The log is full of errors. How do I correct the code? How and where do I use always#() and #() blocks? Where do I use blocking and non blocking assignments?
input wire CLOCK;
input wire [31:0] OUT_SQRT;
output wire [31:0] IN_SQRT;
input wire [31:0] RANDP;
integer randp;
integer flagp;
integer sqrootp;
integer check_primep;
always #(posedge CLOCK and flagp != 0)
begin
#10
#(posedge and flagp != 0 )
begin
flagp = sqrootp%check_primep;
if(flagp != 0 and check_primep < sqrootp)
begin
check_primep = check_primep + 1;
end
#(posedge and flagp == 0)
begin
flagp = 1;
check_primep = 2;
randp = RANDP;
#5
IN_SQRT = randp;
#10
sqrootp = OUT_SQRT;
end
end
A flip-flop is implied using:
always #(posedge clk) begin
flip_flop_q <= flip_flop_d;
end
To make some thing synchronously (sampled on the clock) enabled:
always #(posedge clk) begin
if (flagp != 0) begin
flip_flop_q <= flip_flop_d;
end
end
Combinatorial logic is implied using:
always #* begin
comb_logic = a + b;
end
Things like the following (delays) are not synthesizable:
#10
#(posedge and flagp != 0 ) // no always just a delay waiting for criteria
Often used in test harnesses to wait for signals like resets etc being released.
initial begin
#(posedge reset_n);
#(posedge clk);
#(posedge clk);
//begin test procedure
end
If you need to wait for a signal in synthesisable verilog you need to build a FSM (Finite State Machine) to sequence your logic.
This is my code to control a RC Servo Motor. The code basically turns the 50MHz frequency to 1KHz.
I am using one of the switches on the FPGA to control the motor. Until the switch is on, none of the program should run.
But that doesn't seem to be happening. I don't know what I'm doing wrong. It's probably a very silly mistake.
module servo(clk,rst,clk_out,switch);
input clk,rst,switch;
output reg clk_out;
reg [15:0] counter;
always #(posedge clk or posedge rst or posedge switch)
if (switch) begin
if(rst) begin
counter <=16'd0;
clk_out <= 1'b0;
end
else if(counter==16'd25000) begin
counter <=16'd0;
clk_out <= ~clk_out;
end
else begin
counter<=counter+1;
end
end
endmodule
Also I tried changing the duty cycle so the motor rotates faster, but this doesn't seem to be working.
module servo (clk,rst,clk_out,switch);
input clk,rst,switch;
output reg clk_out;
reg [15:0] counter;
always #(posedge clk or posedge rst)
if(rst)
begin
counter<=16'd0;
clk_out <= 1'b0;
end
else if (switch)
begin
if(counter==16'd12500)
begin
clk_out <= 1'b1;
counter<=counter+1;
end
else
if(counter==16'd50000)
begin
counter <= 16'd0;
clk_out <= 1'b0;
end
else
begin
counter<=counter+1;
end
end
endmodule
Here's my cut at it - I haven't simulated it, so beware!
module servo(clk,rst,clk_out,switch);
input clk,rst,switch;
output reg clk_out;
reg [15:0] counter;
// clocked blocks should only have the clock and maybe a reset
// in the sensitivity list
always #(posedge clk or posedge rst) begin
if(rst) begin
counter <=16'd0;
clk_out <= 1'b0;
end
else if (switch) begin // 'switch' used as an enable
if(counter==16'd25000) begin
counter <=16'd0;
clk_out <= ~clk_out;
end
else begin
counter<=counter+1;
end
end
else begin
counter <= 16'd0;
end
end
endmodule
First thing I did was to remove the entry for switch in the sensitivity list - for synchronous logic, there should only be a clock and maybe a reset here.
The reset clause for the logic should be first, so I moved the test for switch using it as an enable signal in the main body of the always block. The counter will only run now if switch is high.