如何计算 Verilog 中的特定序列?
How do I count a specific sequence in Verilog?
我需要设计一个可以计算 1011
位序列的电路。例如,如果序列如图所示,计数应该是1
,但不是。我知道我正在读取输入 w
不是按顺序,但我也不知道该怎么做。
w
is our input sequence and CS
and NS
are current state and
next state. and parameters are our states. second picture's second state machine is what I used there is a slight difference between those two SMs.
主要逻辑:
module serialCounter(w,clk,resetn,z);
input w,clk,resetn;
output reg z;
reg [2:0] CS,NS;
reg [7:0] count;
parameter S0=3'b000, S1=3'b001, S2=3'b010, S3=3'b011, S4=3'b100;
always @(w,CS)
case(CS)
S0:if(w==1)
begin
NS=S1;
end
else
begin
NS=S0;
end
S1:if(w==1)
begin
NS=S2;
end
else
begin
NS=S0;
end
S2:if(w==1)
begin
NS=S2;
end
else
begin
NS=S3;
end
S3:if(w==1)
begin
NS=S4;
end
else
begin
NS=S0;
end
S4:begin NS=S0;end
endcase
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
CS<=S0;
else
CS<=NS;
end
always @(CS)
begin
if(CS==S4)
begin
z=1;
count<=count+1;
end
end
endmodule
测试台:
`timescale 1ns/1ns
module counterTB();
reg w,clk,resetn;
reg [2:0] CS,NS;
wire z;
wire [7:0] count;
integer i;
serialCounter sk(.w(w),.clk(clk),.resetn(resetn),.z(z));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
end
initial
begin
for(i=0;i<255;i=i+1)
@(posedge clk, negedge resetn) w=i;
end
always #5 clk = ~clk;
always @(posedge clk, negedge resetn) $monitor("w=%b, z=%b, count=%d", w,z,count);
endmodule
有几个问题。
您断言重置,但您从未释放它(resetn
保持为 0)。您需要在几个时钟周期后将其设置为 1。
您需要在测试台中以不同方式驱动您的输入w
。您的设计总是在它为 0 时对其进行采样。一种快速的方法是随机驱动它。
您错误地建模了 z
输出,我认为这是您的“检测”信号。我还从 always
块中删除了 count
逻辑,因为它似乎没有做任何重要的事情。
这是现在运行并检测 w
上的 1011
模式的代码:
module serialCounter(w,clk,resetn,z);
input w,clk,resetn;
output reg z;
reg [2:0] CS,NS;
reg [7:0] count;
parameter S0=3'b000, S1=3'b001, S2=3'b010, S3=3'b011, S4=3'b100;
always @(w,CS)
case(CS)
S0:if(w==1)
begin
NS=S1;
end
else
begin
NS=S0;
end
S1:if(w==1)
begin
NS=S2;
end
else
begin
NS=S0;
end
S2:if(w==1)
begin
NS=S2;
end
else
begin
NS=S3;
end
S3:if(w==1)
begin
NS=S4;
end
else
begin
NS=S0;
end
S4:begin NS=S0;end
endcase
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
CS<=S0;
else
CS<=NS;
end
always @* begin
if(CS==S4) begin
z=1;
end else begin
z=0;
end
end
endmodule
module counterTB();
reg w,clk,resetn;
reg [2:0] CS,NS;
wire z;
wire [7:0] count;
integer i;
serialCounter sk(.w(w),.clk(clk),.resetn(resetn),.z(z));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
#30 resetn=1;
#5000 $finish;
end
always #5 clk = ~clk;
always @(posedge clk, negedge resetn) $monitor("w=%b, z=%b, count=%d", w,z,count);
always @(posedge clk, negedge resetn) begin
w <= $random;
end
endmodule
对代码进行了一些修复,首先,我们应该去掉主逻辑(z 和 count)中的推断锁存器,这样结束:
module serialCounter(w,clk,resetn,z);
input w,clk,resetn;
output reg z;
reg [2:0] CS,NS;
reg [7:0] count;
parameter S0=3'b000, S1=3'b001, S2=3'b010, S3=3'b011, S4=3'b100;
always @(w,CS)
case(CS)
S0:if(w==1)
begin
NS=S1;
end
else
begin
NS=S0;
end
S1:if(w==1)
begin
NS=S2;
end
else
begin
NS=S0;
end
S2:if(w==1)
begin
NS=S2;
end
else
begin
NS=S3;
end
S3:if(w==1)
begin
NS=S4;
end
else
begin
NS=S0;
end
S4:begin NS=S0;end
default: NS=S0;
endcase
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
CS<=S0;
else
CS<=NS;
end
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
begin
z<=0;
count<=0;
end
if(CS==S4)
begin
z<=1;
count<=count+1;
end
end
endmodule
其次,在测试台模块中,resetn 从未从 0 变为 1,因为我们有一个异步低电平有效复位,它始终处于复位状态,同样,如果你用最少的驱动“w”计数器的重要位,它将在每个周期切换。我把它改成一个带位计数器的移位寄存器。测试台是这样工作的:
`timescale 1ns/1ns
module counterTB();
localparam WIDTH = 8;
reg clk,resetn;
reg [2:0] CS,NS;
wire w;
wire z;
wire [WIDTH-1:0] count;
reg [WIDTH-1:0] w_reg;
reg [WIDTH-1:0] w_nxt;
reg [$clog2(WIDTH)-1:0] bit_count;
integer i;
serialCounter sk(.w(w),.clk(clk),.resetn(resetn),.z(z));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
w_reg = 0;
w_nxt = 0;
end
//DISABLE RESET
always #10 resetn = 1'b1;
always @ (posedge clk, negedge resetn) begin
if(resetn == 0) begin
w_reg <= 0;
w_nxt <= 1;
bit_count <= 0;
end
else begin
if(bit_count == (WIDTH-1)) begin
if(&w_nxt) begin
$finish;
end
else begin
w_reg <= w_nxt;
w_nxt <= w_nxt + 1;
bit_count <= 0;
end
end
else begin
w_reg <= w_reg >> 1;
bit_count <= bit_count + 1;
end
end
end
assign w = w_reg[0];
always #5 clk = ~clk;
always @(posedge clk, negedge resetn) $monitor("w=%b, z=%b, count=%d, w_reg=%x, w_nxt=%h, bit_count=%d, reset=%b", w,z,sk.count,w_reg,w_nxt,bit_count,resetn);
endmodule
模拟输出的最后一部分(累计到255):
w=0, z=1, count=104, w_reg=fa, w_nxt=fb, bit_count=0, reset=1
w=1, z=1, count=104, w_reg=7d, w_nxt=fb, bit_count=1, reset=1
w=0, z=1, count=104, w_reg=3e, w_nxt=fb, bit_count=2, reset=1
w=1, z=1, count=105, w_reg=1f, w_nxt=fb, bit_count=3, reset=1
w=1, z=1, count=105, w_reg=0f, w_nxt=fb, bit_count=4, reset=1
w=1, z=1, count=105, w_reg=07, w_nxt=fb, bit_count=5, reset=1
w=1, z=1, count=105, w_reg=03, w_nxt=fb, bit_count=6, reset=1
w=1, z=1, count=105, w_reg=01, w_nxt=fb, bit_count=7, reset=1
w=1, z=1, count=105, w_reg=fb, w_nxt=fc, bit_count=0, reset=1
w=1, z=1, count=105, w_reg=7d, w_nxt=fc, bit_count=1, reset=1
w=0, z=1, count=105, w_reg=3e, w_nxt=fc, bit_count=2, reset=1
w=1, z=1, count=105, w_reg=1f, w_nxt=fc, bit_count=3, reset=1
w=1, z=1, count=105, w_reg=0f, w_nxt=fc, bit_count=4, reset=1
w=1, z=1, count=106, w_reg=07, w_nxt=fc, bit_count=5, reset=1
w=1, z=1, count=106, w_reg=03, w_nxt=fc, bit_count=6, reset=1
w=1, z=1, count=106, w_reg=01, w_nxt=fc, bit_count=7, reset=1
w=0, z=1, count=106, w_reg=fc, w_nxt=fd, bit_count=0, reset=1
w=0, z=1, count=106, w_reg=7e, w_nxt=fd, bit_count=1, reset=1
w=1, z=1, count=106, w_reg=3f, w_nxt=fd, bit_count=2, reset=1
w=1, z=1, count=106, w_reg=1f, w_nxt=fd, bit_count=3, reset=1
w=1, z=1, count=106, w_reg=0f, w_nxt=fd, bit_count=4, reset=1
w=1, z=1, count=106, w_reg=07, w_nxt=fd, bit_count=5, reset=1
w=1, z=1, count=106, w_reg=03, w_nxt=fd, bit_count=6, reset=1
w=1, z=1, count=106, w_reg=01, w_nxt=fd, bit_count=7, reset=1
w=1, z=1, count=106, w_reg=fd, w_nxt=fe, bit_count=0, reset=1
w=0, z=1, count=106, w_reg=7e, w_nxt=fe, bit_count=1, reset=1
w=1, z=1, count=106, w_reg=3f, w_nxt=fe, bit_count=2, reset=1
w=1, z=1, count=106, w_reg=1f, w_nxt=fe, bit_count=3, reset=1
w=1, z=1, count=107, w_reg=0f, w_nxt=fe, bit_count=4, reset=1
w=1, z=1, count=107, w_reg=07, w_nxt=fe, bit_count=5, reset=1
w=1, z=1, count=107, w_reg=03, w_nxt=fe, bit_count=6, reset=1
w=1, z=1, count=107, w_reg=01, w_nxt=fe, bit_count=7, reset=1
w=0, z=1, count=107, w_reg=fe, w_nxt=ff, bit_count=0, reset=1
w=1, z=1, count=107, w_reg=7f, w_nxt=ff, bit_count=1, reset=1
w=1, z=1, count=107, w_reg=3f, w_nxt=ff, bit_count=2, reset=1
w=1, z=1, count=108, w_reg=1f, w_nxt=ff, bit_count=3, reset=1
w=1, z=1, count=108, w_reg=0f, w_nxt=ff, bit_count=4, reset=1
w=1, z=1, count=108, w_reg=07, w_nxt=ff, bit_count=5, reset=1
w=1, z=1, count=108, w_reg=03, w_nxt=ff, bit_count=6, reset=1
w=1, z=1, count=108, w_reg=01, w_nxt=ff, bit_count=7, reset=1
w=1, z=1, count=108, w_reg=01, w_nxt=ff, bit_count=7, reset=1
我想,有一种更简单的方法来创建这个状态机。下面的示例 reg [3:0]
模式寄存器保留了模式的 4 位。然后它只是将模式与所需模式(在本例中为 seq)进行比较。
module serialCounter(w, clk, resetn, z, counter);
input w, clk, resetn;
output reg z;
output reg[7:0] counter;
reg[3:0] pattern, tmp;
parameter seq = 4'b1011;
always@(posedge clk) begin
if (!resetn) begin
pattern <= 0;
counter <= 0;
end
else begin
tmp = (pattern << 1) | w;
if (tmp == seq) begin
counter <= counter + 1;
z <= 1;
end
else
z <= 0;
pattern <= tmp;
end
end
endmodule
module counterTB();
reg w,clk,resetn;
reg [2:0] CS,NS;
wire z;
reg [7:0] count;
integer i;
serialCounter sk(.w(w), .clk(clk), .resetn(resetn), .z(z), .counter(count));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
#30 resetn=1;
#5000 $finish;
end
always #5 clk = ~clk;
initial $monitor("clk=%b, w=%b, z=%b, count=%d pattern=%b", clk, w,z, count, sk.pattern);
initial begin
w = 0;
forever #10 w = $random;
end
endmodule
我还修复了 tb 模块中的一些问题,例如$monitor 应该在初始块中使用。我也更改了您生成 w
的方式。
我需要设计一个可以计算 1011
位序列的电路。例如,如果序列如图所示,计数应该是1
,但不是。我知道我正在读取输入 w
不是按顺序,但我也不知道该怎么做。
w
is our input sequence andCS
andNS
are current state and next state. and parameters are our states. second picture's second state machine is what I used there is a slight difference between those two SMs.
主要逻辑:
module serialCounter(w,clk,resetn,z);
input w,clk,resetn;
output reg z;
reg [2:0] CS,NS;
reg [7:0] count;
parameter S0=3'b000, S1=3'b001, S2=3'b010, S3=3'b011, S4=3'b100;
always @(w,CS)
case(CS)
S0:if(w==1)
begin
NS=S1;
end
else
begin
NS=S0;
end
S1:if(w==1)
begin
NS=S2;
end
else
begin
NS=S0;
end
S2:if(w==1)
begin
NS=S2;
end
else
begin
NS=S3;
end
S3:if(w==1)
begin
NS=S4;
end
else
begin
NS=S0;
end
S4:begin NS=S0;end
endcase
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
CS<=S0;
else
CS<=NS;
end
always @(CS)
begin
if(CS==S4)
begin
z=1;
count<=count+1;
end
end
endmodule
测试台:
`timescale 1ns/1ns
module counterTB();
reg w,clk,resetn;
reg [2:0] CS,NS;
wire z;
wire [7:0] count;
integer i;
serialCounter sk(.w(w),.clk(clk),.resetn(resetn),.z(z));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
end
initial
begin
for(i=0;i<255;i=i+1)
@(posedge clk, negedge resetn) w=i;
end
always #5 clk = ~clk;
always @(posedge clk, negedge resetn) $monitor("w=%b, z=%b, count=%d", w,z,count);
endmodule
有几个问题。
您断言重置,但您从未释放它(resetn
保持为 0)。您需要在几个时钟周期后将其设置为 1。
您需要在测试台中以不同方式驱动您的输入w
。您的设计总是在它为 0 时对其进行采样。一种快速的方法是随机驱动它。
您错误地建模了 z
输出,我认为这是您的“检测”信号。我还从 always
块中删除了 count
逻辑,因为它似乎没有做任何重要的事情。
这是现在运行并检测 w
上的 1011
模式的代码:
module serialCounter(w,clk,resetn,z);
input w,clk,resetn;
output reg z;
reg [2:0] CS,NS;
reg [7:0] count;
parameter S0=3'b000, S1=3'b001, S2=3'b010, S3=3'b011, S4=3'b100;
always @(w,CS)
case(CS)
S0:if(w==1)
begin
NS=S1;
end
else
begin
NS=S0;
end
S1:if(w==1)
begin
NS=S2;
end
else
begin
NS=S0;
end
S2:if(w==1)
begin
NS=S2;
end
else
begin
NS=S3;
end
S3:if(w==1)
begin
NS=S4;
end
else
begin
NS=S0;
end
S4:begin NS=S0;end
endcase
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
CS<=S0;
else
CS<=NS;
end
always @* begin
if(CS==S4) begin
z=1;
end else begin
z=0;
end
end
endmodule
module counterTB();
reg w,clk,resetn;
reg [2:0] CS,NS;
wire z;
wire [7:0] count;
integer i;
serialCounter sk(.w(w),.clk(clk),.resetn(resetn),.z(z));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
#30 resetn=1;
#5000 $finish;
end
always #5 clk = ~clk;
always @(posedge clk, negedge resetn) $monitor("w=%b, z=%b, count=%d", w,z,count);
always @(posedge clk, negedge resetn) begin
w <= $random;
end
endmodule
对代码进行了一些修复,首先,我们应该去掉主逻辑(z 和 count)中的推断锁存器,这样结束:
module serialCounter(w,clk,resetn,z);
input w,clk,resetn;
output reg z;
reg [2:0] CS,NS;
reg [7:0] count;
parameter S0=3'b000, S1=3'b001, S2=3'b010, S3=3'b011, S4=3'b100;
always @(w,CS)
case(CS)
S0:if(w==1)
begin
NS=S1;
end
else
begin
NS=S0;
end
S1:if(w==1)
begin
NS=S2;
end
else
begin
NS=S0;
end
S2:if(w==1)
begin
NS=S2;
end
else
begin
NS=S3;
end
S3:if(w==1)
begin
NS=S4;
end
else
begin
NS=S0;
end
S4:begin NS=S0;end
default: NS=S0;
endcase
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
CS<=S0;
else
CS<=NS;
end
always @(posedge clk, negedge resetn)
begin
if(resetn == 0)
begin
z<=0;
count<=0;
end
if(CS==S4)
begin
z<=1;
count<=count+1;
end
end
endmodule
其次,在测试台模块中,resetn 从未从 0 变为 1,因为我们有一个异步低电平有效复位,它始终处于复位状态,同样,如果你用最少的驱动“w”计数器的重要位,它将在每个周期切换。我把它改成一个带位计数器的移位寄存器。测试台是这样工作的:
`timescale 1ns/1ns
module counterTB();
localparam WIDTH = 8;
reg clk,resetn;
reg [2:0] CS,NS;
wire w;
wire z;
wire [WIDTH-1:0] count;
reg [WIDTH-1:0] w_reg;
reg [WIDTH-1:0] w_nxt;
reg [$clog2(WIDTH)-1:0] bit_count;
integer i;
serialCounter sk(.w(w),.clk(clk),.resetn(resetn),.z(z));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
w_reg = 0;
w_nxt = 0;
end
//DISABLE RESET
always #10 resetn = 1'b1;
always @ (posedge clk, negedge resetn) begin
if(resetn == 0) begin
w_reg <= 0;
w_nxt <= 1;
bit_count <= 0;
end
else begin
if(bit_count == (WIDTH-1)) begin
if(&w_nxt) begin
$finish;
end
else begin
w_reg <= w_nxt;
w_nxt <= w_nxt + 1;
bit_count <= 0;
end
end
else begin
w_reg <= w_reg >> 1;
bit_count <= bit_count + 1;
end
end
end
assign w = w_reg[0];
always #5 clk = ~clk;
always @(posedge clk, negedge resetn) $monitor("w=%b, z=%b, count=%d, w_reg=%x, w_nxt=%h, bit_count=%d, reset=%b", w,z,sk.count,w_reg,w_nxt,bit_count,resetn);
endmodule
模拟输出的最后一部分(累计到255):
w=0, z=1, count=104, w_reg=fa, w_nxt=fb, bit_count=0, reset=1
w=1, z=1, count=104, w_reg=7d, w_nxt=fb, bit_count=1, reset=1
w=0, z=1, count=104, w_reg=3e, w_nxt=fb, bit_count=2, reset=1
w=1, z=1, count=105, w_reg=1f, w_nxt=fb, bit_count=3, reset=1
w=1, z=1, count=105, w_reg=0f, w_nxt=fb, bit_count=4, reset=1
w=1, z=1, count=105, w_reg=07, w_nxt=fb, bit_count=5, reset=1
w=1, z=1, count=105, w_reg=03, w_nxt=fb, bit_count=6, reset=1
w=1, z=1, count=105, w_reg=01, w_nxt=fb, bit_count=7, reset=1
w=1, z=1, count=105, w_reg=fb, w_nxt=fc, bit_count=0, reset=1
w=1, z=1, count=105, w_reg=7d, w_nxt=fc, bit_count=1, reset=1
w=0, z=1, count=105, w_reg=3e, w_nxt=fc, bit_count=2, reset=1
w=1, z=1, count=105, w_reg=1f, w_nxt=fc, bit_count=3, reset=1
w=1, z=1, count=105, w_reg=0f, w_nxt=fc, bit_count=4, reset=1
w=1, z=1, count=106, w_reg=07, w_nxt=fc, bit_count=5, reset=1
w=1, z=1, count=106, w_reg=03, w_nxt=fc, bit_count=6, reset=1
w=1, z=1, count=106, w_reg=01, w_nxt=fc, bit_count=7, reset=1
w=0, z=1, count=106, w_reg=fc, w_nxt=fd, bit_count=0, reset=1
w=0, z=1, count=106, w_reg=7e, w_nxt=fd, bit_count=1, reset=1
w=1, z=1, count=106, w_reg=3f, w_nxt=fd, bit_count=2, reset=1
w=1, z=1, count=106, w_reg=1f, w_nxt=fd, bit_count=3, reset=1
w=1, z=1, count=106, w_reg=0f, w_nxt=fd, bit_count=4, reset=1
w=1, z=1, count=106, w_reg=07, w_nxt=fd, bit_count=5, reset=1
w=1, z=1, count=106, w_reg=03, w_nxt=fd, bit_count=6, reset=1
w=1, z=1, count=106, w_reg=01, w_nxt=fd, bit_count=7, reset=1
w=1, z=1, count=106, w_reg=fd, w_nxt=fe, bit_count=0, reset=1
w=0, z=1, count=106, w_reg=7e, w_nxt=fe, bit_count=1, reset=1
w=1, z=1, count=106, w_reg=3f, w_nxt=fe, bit_count=2, reset=1
w=1, z=1, count=106, w_reg=1f, w_nxt=fe, bit_count=3, reset=1
w=1, z=1, count=107, w_reg=0f, w_nxt=fe, bit_count=4, reset=1
w=1, z=1, count=107, w_reg=07, w_nxt=fe, bit_count=5, reset=1
w=1, z=1, count=107, w_reg=03, w_nxt=fe, bit_count=6, reset=1
w=1, z=1, count=107, w_reg=01, w_nxt=fe, bit_count=7, reset=1
w=0, z=1, count=107, w_reg=fe, w_nxt=ff, bit_count=0, reset=1
w=1, z=1, count=107, w_reg=7f, w_nxt=ff, bit_count=1, reset=1
w=1, z=1, count=107, w_reg=3f, w_nxt=ff, bit_count=2, reset=1
w=1, z=1, count=108, w_reg=1f, w_nxt=ff, bit_count=3, reset=1
w=1, z=1, count=108, w_reg=0f, w_nxt=ff, bit_count=4, reset=1
w=1, z=1, count=108, w_reg=07, w_nxt=ff, bit_count=5, reset=1
w=1, z=1, count=108, w_reg=03, w_nxt=ff, bit_count=6, reset=1
w=1, z=1, count=108, w_reg=01, w_nxt=ff, bit_count=7, reset=1
w=1, z=1, count=108, w_reg=01, w_nxt=ff, bit_count=7, reset=1
我想,有一种更简单的方法来创建这个状态机。下面的示例 reg [3:0]
模式寄存器保留了模式的 4 位。然后它只是将模式与所需模式(在本例中为 seq)进行比较。
module serialCounter(w, clk, resetn, z, counter);
input w, clk, resetn;
output reg z;
output reg[7:0] counter;
reg[3:0] pattern, tmp;
parameter seq = 4'b1011;
always@(posedge clk) begin
if (!resetn) begin
pattern <= 0;
counter <= 0;
end
else begin
tmp = (pattern << 1) | w;
if (tmp == seq) begin
counter <= counter + 1;
z <= 1;
end
else
z <= 0;
pattern <= tmp;
end
end
endmodule
module counterTB();
reg w,clk,resetn;
reg [2:0] CS,NS;
wire z;
reg [7:0] count;
integer i;
serialCounter sk(.w(w), .clk(clk), .resetn(resetn), .z(z), .counter(count));
initial
begin
resetn = 1'b0;
clk = 1'b0;
CS=3'b000;
#30 resetn=1;
#5000 $finish;
end
always #5 clk = ~clk;
initial $monitor("clk=%b, w=%b, z=%b, count=%d pattern=%b", clk, w,z, count, sk.pattern);
initial begin
w = 0;
forever #10 w = $random;
end
endmodule
我还修复了 tb 模块中的一些问题,例如$monitor 应该在初始块中使用。我也更改了您生成 w
的方式。