该题出自牛客27题
最一开始的程序:(在vivado仿真程序,为了方便观看,将中间变量也作为输出)
`timescale 1ns/1ns
module test2(
input clk,
input rst_n,
input data,
output reg match,
output reg not_match,
output reg [5:0] adata,
output reg [2:0] num
);
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
adata <= 6'b0;
end
else begin
adata <= {adata[4:0],data};
end
end
// counter 6
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
num <= 3'b0;
end
else if(num == 5 ) begin
num <= 3'b0;
end
else begin
num <= num + 1;
end
end
// match test
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
match <= 0;
not_match <= 0;
end
else if(num == 5 && adata == 6'b011100) begin
match <= 1;
not_match <= 0;
end
else if(num == 5 && adata != 6'b011100) begin
match <= 0;
not_match <= 1;
end
else begin
match <= 0;
not_match <= 0;
end
end
endmodule
激励函数为:(我习惯写成计数器的形式,而不是一个个值写入initial中)
其中初始值为100的目的也就是第一个值为000,这样的序列顺序就对上了。
`timescale 1ns / 1ns
module testbench(
);
reg clk=0,rst_n;
reg a;
reg Q2,Q1;
wire match;
wire not_match;
wire [5:0] adata;
wire [2:0] num;
//wire [5:0] adata;
always #5 clk = ~clk;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
a <= 0;
Q1 <= 0;
Q2 <= 1;
end
else begin
Q2 <= Q1;
Q1 <= a;
a <= ~Q2;
end
end
initial begin
rst_n=0;
#1 rst_n = 1;
#150 $finish;
end
test2 dut(
.clk(clk),
.rst_n(rst_n),
.data(a),
.match(match),
.not_match(not_match),
.num(num),
.adata(adata)
);
endmodule
时序图为:
很明显是不对的,因为判定时刻理应是正确时刻的下一个时刻,因此需要判定当下时刻。
所以将上一时刻判定序列(上面的代码)
else if(num == 5 && adata == 6'b011100) begin
match <= 1;
not_match <= 0;
end
else if(num == 5 && adata != 6'b011100) begin
match <= 0;
not_match <= 1;
end
改为当下时刻判定:
else if(num == 5 && {adata[4:0],data} == 6'b011100) begin
match <= 1;
not_match <= 0;
end
else if(num == 5 && {adata[4:0],data} != 6'b011100) begin
match <= 0;
not_match <= 1;
end
还有一种改发,就是让adata立马等于{adata[4:0],data}。这样下面就不需要改,将
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
adata <= 6'b0;
end
else begin
adata <= {adata[4:0],data};
end
end
中的非阻塞赋值变成阻塞赋值:
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
adata = 6'b0;
end
else begin
adata = {adata[4:0],data};
end
end
但是不建议这么使用:虽然牛客也可以成功通过测试例,但是不建议时序电路用阻塞赋值,因为容易产生竞争关系。
所以综上所述,可以这里一下阻塞赋值和非阻塞赋值:
非阻塞赋值操作右端操作数使用的是上一个时钟周期的旧值
而阻塞赋值右端操作数会立马赋值给当下值,而非阻塞会在下一个时序再用到这个值。这个思想有的像i++和++i的区别。
就比如:
always @ ( posedge clk ) begin
a = b ;
end
always @ ( posedge clk ) begin
b = a ;
end
会产生竞争。
但是:
always @ ( posedge clk ) begin
a <= b ;
end
always @ ( posedge clk ) begin
b <=a ;
end
就相当于a^(n+1) = b ^n
b^(n+1) = a ^n