1
votes

Trying to implement a freq counter in Verilog. What I need is a clock input, a count output, and a reset input. The behaviour should be like this:

  • an internal reg or wire variable counts the clock pulses applied to the clock input
  • whenever a reset pulse comes, it should transfer the count value to output to keep there until the next clock pulse comes, and reset the internal variable.

A simple code is given below:

module counter(

input rst,
input clk,

output [31:0] countout
//output [31:0] count
);

wire rst;
wire clk;

reg [31:0] countout=0;
reg [31:0] count=0; 

always @ (posedge clk)
    begin
        count = count + 1'b1;
    end

always @ ( posedge rst )
    begin
        countout = count;
    end

always @ ( negedge rst )
    begin
        count = 0;
    end
endmodule

However, Vivado won't allow this as the count variable is a multi-driven net. Apparently, count cannot be changed in 2 different always block. Do you have any idea how I can implement this? Thanks.

2

2 Answers

1
votes

I have a re-write of your code down there. It is re-written with accordance to the industry practices.

module counter(

input rst,
input clk,

output wire [31:0] countout // should be wire for assign.
//output [31:0] count
);

wire rst;
wire clk;

reg [31:0] countout; // = 0 -- do not initialize it here
reg [31:0] count; // = 0 

  always @ (posedge clk or negedge rst)
    begin
      if (rst == 0) 
        count <= 0;
      else
        count <= count + 1'b1;
    end

assign  countout = count;

endmodule

As you memtioned, driving 'count' from 2 differrent always block is not suported by synthesis tools and creates races in simulation. To avoid it, all driving of the variable must be done withing a singel always block, as in my example.

According to your code, you tried to implement an asynchronous reset for the counter. This functionality is implemented in my example using common practices with negedge of rst and the if statement in the block.

You do not need to use any additional flop to drive the 'countout' output. A simple assign statement is sufficient. In verilog you just need to be sure that lhs is a wire.

And, you should have used non-blocking assignments <= while creating flops.

Also, do not initialize variables at declarations. This also creates multiple drivers and might not be synthesizable.

When dealing wiht verilog, remember that you describe a hardware which consists of devices and connections. Every always block essentially defines a separate device with inputs and outputs. 'assign' and module ports represent connections between those devices.

Below is a simple testbench which can help you to test your counter:

module tb;
  reg rst;
  reg clk;
  wire[31:0] count;
  integer i;

  counter counter(rst, clk, count);
  
initial begin 
  
  // print counter
  $monitor(count);
  
  clk = 0;
  
  // toggle reset
  rst = 1;
  #5 rst = 0;
  #5 rst = 1;
  
  // run 5 clock cycles
  for (i = 0; i < 10; i = i+1) 
    #5 clk = ~clk;
  
  // done
  $finish;
end
endmodule
0
votes

There are several problems in your design.

First, vivado will find 3 clocks :

  • clk with posedge
  • rst with posedge
  • rst with falling edge.

I think you need only one clock.

Then you should write your process like it :

always @ (posedge clk)
begin
        // your code here
end

Second, you should use non-blocking assignment <= for synchronous register.

Then, as I understand the behaviour of rst is not really a reset but a simple input «button». And you need to know if edge occur.

I think you should change confusing name of rst by something like btn. And you should detect rising edge and falling edge saving previous value like it :

input btn;

reg btn_old, btn_rise, btn_fall;

always @ (posedge clk)
begin
    btn_rise <= 1'b0;
    btn_fall <= 1'b0;
    if(!btn_old && btn) begin
        btn_rise <= 1'b1;
    end
    if(btn_old && !btn) begin
        btn_fall <= 1'b1;
    end
    btn_old <= btn;

Then you can use btn_fall and btn_rise for your counter.