简体   繁体   中英

Shortests version to choose posedge/negedge sensitivity from module parameter?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM