verilog - Verilog中的频率计数器
问题描述
尝试在 Verilog 中实现频率计数器。我需要的是一个时钟输入、一个计数输出和一个复位输入。行为应该是这样的:
- 内部 reg 或 wire 变量对应用于时钟输入的时钟脉冲进行计数
- 每当一个复位脉冲到来时,它应该将计数值传送到输出并保持在那里直到下一个时钟脉冲到来,并复位内部变量。
下面给出一个简单的代码:
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 个不同的始终块中更改计数。你知道我该如何实现吗?谢谢。
解决方案
我在那里重写了你的代码。它是根据行业惯例重新编写的。
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
推荐阅读
- c++ - 为什么我们不能重用具有不同模板参数的别名模板标识符?
- sql - CONNECT BY PRIOR 和父子层次结构的串联
- swift - Xcode 11.4 beta 在@Published 属性订阅上崩溃。这是怎么回事?
- java - 为什么我的 Java 短片被无符号右移的 1 填满?
- java - 如何使用 flespi 连接和发布 Java Hive MQTTClient?
- javascript - 电子锻造,打包的应用程序显示空白屏幕
- types - 是否可以在 OCaml/ReasonML 上实现值索引数据类型?
- amazon-web-services - 有什么方法可以在 Athena 数据库中同时运行多个 SQL 查询
- docker - 充当代理的 Docker 注册表不提取图像
- jms - ActiveMQ如何以编程方式重新发送/重试DLQ消息