首页 > 解决方案 > Verilog中的频率计数器

问题描述

尝试在 Verilog 中实现频率计数器。我需要的是一个时钟输入、一个计数输出和一个复位输入。行为应该是这样的:

下面给出一个简单的代码:

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

但是,Vivado 不允许这样做,因为计数变量是一个多驱动网络。显然,无法在 2 个不同的始终块中更改计数。你知道我该如何实现吗?谢谢。

标签: verilogcountervivado

解决方案


我在那里重写了你的代码。它是根据行业惯例重新编写的。

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

正如您所提到的,综合工具不支持从 2 个不同的块中驱动“计数”,并在模拟中创建比赛。为避免这种情况,变量的所有驱动都必须使用单个始终块来完成,如我的示例所示。

根据您的代码,您尝试为计数器实现异步重置。在我的示例中,此功能是使用 rst 的否定和if块中的语句的常见做法实现的。

您不需要使用任何额外的触发器来驱动“countout”输出。一个简单的assign陈述就足够了。在verilog中,您只需要确保 lhs 是一个wire

<=而且,您应该在创建翻牌时使用非阻塞分配。

另外,不要在声明时初始化变量。这也会创建多个驱动程序,并且可能无法合成。

在处理 verilog 时,请记住您描述的是由设备和连接组成的硬件。每个 always 块本质上定义了一个带有输入和输出的单独设备。“分配”和模块端口表示这些设备之间的连接。

下面是一个简单的测试平台,可以帮助您测试您的计数器:

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

推荐阅读