计数器在时钟的两个边缘变化
Counter changing on both edges of clock
下面的代码是向上计数器。代码没有错误,但是图形有一些错误,比如计数应该只在 posedge 但即使在 clk 的负边计数也在计数。
module countergate (clk,rst,current,next);
input clk,rst;
input [2:0] current;
output reg [2:0] next;
always@(*)
begin
if (rst==1)
{next[2],next[1],next[0]} <= 3'b000;
else
begin
next[2] <= ((~current[2])&(current[1])&(current[0]) | (current[2])&(~current[0]) | (current[2])&(~current[1]));
next[1] <= ((~current[1])&(current[0]) | (current[1])&(~current[0]));
next[0] <= (~current[0]);
end
end
endmodule
测试台
`include "countergate.v"
module tb1();
reg clk,rst;
reg [2:0] current;
wire [2:0] next;
countergate DUT (clk,rst,current,next);
initial
begin
clk = 1;
forever #1 clk = ~clk;
end
initial
begin
rst = 1;
repeat (2) @(posedge clk);
rst = 0;
end
initial
begin
#4;
{current[2],current[1],current[0]} = 3'b000;
#1;
{current[2],current[1],current[0]} = 3'b001;
#1;
{current[2],current[1],current[0]} = 3'b010;
#1;
{current[2],current[1],current[0]} = 3'b011;
#1;
{current[2],current[1],current[0]} = 3'b100;
#1;
{current[2],current[1],current[0]} = 3'b101;
#1;
{current[2],current[1],current[0]} = 3'b110;
#1;
{current[2],current[1],current[0]} = 3'b111;
#1;
$finish;
end
initial
begin
$monitor("%t :clk = %b , rst = %b , current = %b, next = %b", $time,clk,rst,current,next);
end
endmodule
如Comment中所述,如果您希望计数值仅在时钟的上升沿而不是在时钟的两个边沿发生变化,则应使用顺序always
块.变化:
always@(*)
至:
always @(posedge clk or posedge rst)
您还需要更改测试平台,因为它也在时钟的两个边沿上驱动 current
输入。你应该只在时钟的姿势上驾驶它。由于您正在递增输入,因此可以使用 for
循环大大简化代码。此外,您可以像使用 rst
信号一样将其与时钟对齐,而不是使用 #
延迟。
integer i;
initial
begin
repeat (2) @(posedge clk);
for (i=0; i<8; i=i+1) begin
current = i;
@(posedge clk);
end
$finish;
end
您必须明确指出您希望在时钟的位置评估 always 块:
always @ (posedge clk)...
如果您还想包括“异步”复位,这意味着不关心时钟周期的复位,您还应该将其包括在敏感列表中:
always @ (posedge clk, posedge rst)...
因此,always 块将在两种情况下触发,在 posedge clk或者在 posedge rst.
下面的代码是向上计数器。代码没有错误,但是图形有一些错误,比如计数应该只在 posedge 但即使在 clk 的负边计数也在计数。
module countergate (clk,rst,current,next);
input clk,rst;
input [2:0] current;
output reg [2:0] next;
always@(*)
begin
if (rst==1)
{next[2],next[1],next[0]} <= 3'b000;
else
begin
next[2] <= ((~current[2])&(current[1])&(current[0]) | (current[2])&(~current[0]) | (current[2])&(~current[1]));
next[1] <= ((~current[1])&(current[0]) | (current[1])&(~current[0]));
next[0] <= (~current[0]);
end
end
endmodule
测试台
`include "countergate.v"
module tb1();
reg clk,rst;
reg [2:0] current;
wire [2:0] next;
countergate DUT (clk,rst,current,next);
initial
begin
clk = 1;
forever #1 clk = ~clk;
end
initial
begin
rst = 1;
repeat (2) @(posedge clk);
rst = 0;
end
initial
begin
#4;
{current[2],current[1],current[0]} = 3'b000;
#1;
{current[2],current[1],current[0]} = 3'b001;
#1;
{current[2],current[1],current[0]} = 3'b010;
#1;
{current[2],current[1],current[0]} = 3'b011;
#1;
{current[2],current[1],current[0]} = 3'b100;
#1;
{current[2],current[1],current[0]} = 3'b101;
#1;
{current[2],current[1],current[0]} = 3'b110;
#1;
{current[2],current[1],current[0]} = 3'b111;
#1;
$finish;
end
initial
begin
$monitor("%t :clk = %b , rst = %b , current = %b, next = %b", $time,clk,rst,current,next);
end
endmodule
如Comment中所述,如果您希望计数值仅在时钟的上升沿而不是在时钟的两个边沿发生变化,则应使用顺序always
块.变化:
always@(*)
至:
always @(posedge clk or posedge rst)
您还需要更改测试平台,因为它也在时钟的两个边沿上驱动 current
输入。你应该只在时钟的姿势上驾驶它。由于您正在递增输入,因此可以使用 for
循环大大简化代码。此外,您可以像使用 rst
信号一样将其与时钟对齐,而不是使用 #
延迟。
integer i;
initial
begin
repeat (2) @(posedge clk);
for (i=0; i<8; i=i+1) begin
current = i;
@(posedge clk);
end
$finish;
end
您必须明确指出您希望在时钟的位置评估 always 块:
always @ (posedge clk)...
如果您还想包括“异步”复位,这意味着不关心时钟周期的复位,您还应该将其包括在敏感列表中:
always @ (posedge clk, posedge rst)...
因此,always 块将在两种情况下触发,在 posedge clk或者在 posedge rst.