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, ie
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 technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.