Reputation: 153
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:
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.
Upvotes: 1
Views: 3897
Reputation: 3751
There are several problems in your design.
First, vivado will find 3 clocks :
clk
with posedgerst
with posedgerst
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.
Upvotes: 0
Reputation: 12344
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
Upvotes: 1