【发布时间】:2011-10-28 16:02:03
【问题描述】:
我正在尝试在 verilog 中创建一个计数器,用于计算已经存在多少个时钟周期,并在一千万后重置并重新开始。
我创建了一个 24 位加法器模块以及另一个包含 24 个 D 触发器的模块,以存储从加法器输出的周期计数。
然后我想要一个处于计数状态的状态机,直到经过一千万个周期然后它进入重置状态。
这听起来对吗?问题是我不确定如何实现状态机。
谁能给我指出一个可以帮助我解决这个问题的网站/书籍?
谢谢
【问题讨论】:
我正在尝试在 verilog 中创建一个计数器,用于计算已经存在多少个时钟周期,并在一千万后重置并重新开始。
我创建了一个 24 位加法器模块以及另一个包含 24 个 D 触发器的模块,以存储从加法器输出的周期计数。
然后我想要一个处于计数状态的状态机,直到经过一千万个周期然后它进入重置状态。
这听起来对吗?问题是我不确定如何实现状态机。
谁能给我指出一个可以帮助我解决这个问题的网站/书籍?
谢谢
【问题讨论】:
正如 Paul S 已经提到的,如果您希望计数器在溢出后继续计数,则不需要状态机。您可以这样做(未经测试,可能包含拼写错误):
module overflow_counter (
clk,
reset,
enable,
ctr_out
);
// Port definitions
input clk, reset, enable;
output [23:0] ctr_out;
// Register definitions
reg [23:0] reg_ctr;
// Assignments
assign ctr_out = reg_ctr;
// Counter behaviour - Asynchronous active-high reset
initial reg_ctr <= 0;
always @ (posedge clk or posedge reset)
begin
if (reset) reg_ctr <= 0;
else if (enable)
begin
if (reg_ctr == 10000000) reg_ctr <= 0;
else reg_ctr <= reg_ctr + 1;
end
end
endmodule
当然,通常您会使用参数,这样您就不必在每次需要溢出计数器时都创建自定义模块。我会把它留给你;)。
[编辑]这里有一些文档可以帮助您进行 FSM。我刚刚在 Google 上搜索了“verilog 状态机”:
我还没有读过第一篇论文,所以我不能对此发表评论。第二个展示了各种编码 FSM 的风格,其中 3 种总是阻塞风格,我强烈推荐,因为它更容易调试(状态转换和 FSM 输出被整齐地分开)。链接好像挂了,所以这里是the cached Google result。
【讨论】:
您不需要状态机。您已经在柜台中有状态。您需要做的就是检测您想要包装的值并将 0 加载到您的计数器中
在伪代码中:
if count == 10000000 then
nextCount = 0;
else
nextCount = count + 1;
...或...
nextCount = count + 1;
if count == 10000000 then
resetCount = 1;
【讨论】:
状态机并不太复杂。使用 localparam (带有宽度,不要忘记宽度,这里没有显示,因为它只是一位)为您的状态定义标签。然后创建两个 reg 变量(state_reg、state_next)。 _reg 变量是您的实际寄存器。 _next 变量是一个“wire reg”(可以分配给组合 always 块内部的线)。要记住的两件事是在组合 always 块中执行 X_next = X_reg;(然后是其余的组合逻辑)和在顺序 always 块中执行 X_reg <= X_next;。您可能会喜欢特殊情况,但如果您坚持这些简单的规则,那么事情应该会奏效。因为 Verilog 对加法器有很好的支持,所以我尽量不要对加法器等非常简单的事情使用实例化。
由于我使用 FPGA,我为我的寄存器分配了初始值,我不使用复位信号。我不确定,但对于 ASIC 设计,我认为情况正好相反。
localparam STATE_RESET = 1'b0, STATE_COUNT = 1'b1;
reg [23:0] cntr_reg = 24'd0, cntr_next;
reg state_reg = STATE_COUNT, state_next;
always @* begin
cntr_next = cntr_reg; // statement not required since we handle all cases
if (cntr_reg == 24'd10_000_000)
cntr_next = 24'd0;
else
cntr_next = cntr_reg + 24'd1;
state_next = state_reg; // statement required since we don't handle all cases
case (state_reg)
STATE_COUNT: if (cntr_reg == 24'd10_000_000) state_next = STATE_RESET;
endcase
end
always @(posedge clk) begin
cntr_reg <= cntr_next;
state_reg <= state_next;
end
我发现this book 很有帮助。这本书还有一个VHDL版本,因此您可以将两者并排用作Rosetta Stone来学习VHDL。
【讨论】: