题解 | 不重叠序列检测
1、示意图显示结果需在本组数据传完的下一个周期立即得出,所以必须是组合逻辑,但题目给的reg型,故需使用always@(*)
2、需要比较数据结果,故需新建变量check用于储存一组数据;同时需一个计数器记录周期;时钟同步;
3、题目要求用状态机:
A:将结果与状态绑定:因为结果需要在6次传输完成才能判断,而次态的判断需要在前一状态内确定,所以【结果态】和【读数态】不能直接相连,所以需要添加一个过渡态。
B:将结果与状态分离:那么只需要读数和判断两种状态就行。
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input data,
output reg match,
output reg not_match
);
// 状态定义
parameter READ = 0, WAIT=1, MATCH = 2, NOT_MATCH = 3;
wire R2W,W2M,W2N,C2R;
reg [1:0] state_c; // 当前状态
reg [1:0] state_n; // 下一个状态
reg [3:0] cnt ;
reg [5:0] check ;
// 状态更新逻辑:每个时钟上升沿或复位信号有效时更新当前状态
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_c <= READ; // 复位时回到空闲状态
end else begin
state_c <= state_n; // 更新为下一个状态
end
end
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
cnt <= 4'd0 ;
end else if (cnt == 4'd5) begin
cnt <= 4'd0 ;
end else begin
cnt <= cnt + 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
check <= 6'd0 ;
end else begin
check <= {check[4:0],data};
end
end
// 状态转移逻辑:根据当前状态和条件计算下一个状态
always @(*) begin
case (state_c)
READ: begin
if (R2W) begin
state_n = WAIT;
end else begin
state_n = state_c;
end
end
WAIT: begin
if (W2M) begin
state_n = MATCH;
end else if (W2N) begin
state_n = NOT_MATCH;
end else begin
state_n = state_c;
end
end
MATCH: begin
if (C2R) begin
state_n = READ;
end else begin
state_n = state_c;
end
end
NOT_MATCH: begin
if (C2R) begin
state_n = READ;
end else begin
state_n = state_c;
end
end
default: begin
state_n = READ;
end
endcase
end
// 状态转移条件定义
assign R2W = cnt == 4'd5;
assign W2M = check == 6'b011100;
assign W2N = check != 6'b011100;
assign C2R = cnt == 4'd1; //因为判断状态需要被捕获,所以需要持续一个时钟周期,即cnt==0由WAIT开始MATCH/NOT_MATCH收尾;cnt在边沿之后,所以state_n的状态变化也会在边沿之后;
// 输出逻辑:根据当前状态生成输出信号
always @(*) begin
if (!rst_n) begin
match = 1'b0;
not_match = 1'b0;
end else begin
match = state_n == MATCH; //此处不能用 state_c,因为需要即时出结果,而此时state_c == WAIT;
not_match = state_n == NOT_MATCH;
end
end
endmodule
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input data,
output reg match,
output reg not_match
);
// 状态定义
parameter READ = 0, CHECK = 1;
wire R2C,C2R;
reg state_c; // 当前状态
reg state_n; // 下一个状态
reg [3:0] cnt ;
reg [5:0] check ;
// 状态更新逻辑:每个时钟上升沿或复位信号有效时更新当前状态
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_c <= READ; // 复位时回到空闲状态
end else begin
state_c <= state_n; // 更新为下一个状态
end
end
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
cnt <= 4'd0 ;
end else if (cnt == 4'd5) begin
cnt <= 4'd0 ;
end else begin
cnt <= cnt + 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
check <= 6'd0 ;
end else begin
check <= {check[4:0],data};
end
end
// 状态转移逻辑:根据当前状态和条件计算下一个状态
always @(*) begin
case (state_c)
READ: begin
if (R2C) begin
state_n = CHECK;
end else begin
state_n = state_c;
end
end
CHECK: begin
if (C2R) begin
state_n = READ;
end else begin
state_n = state_c;
end
end
default: begin
state_n = READ;
end
endcase
end
// 状态转移条件定义
assign R2C = cnt == 4'd5;
assign C2R = cnt == 4'd0;
// 输出逻辑:根据当前状态生成输出信号
always @(*) begin
if (!rst_n) begin
match = 1'b0;
not_match = 1'b0;
end else begin
match = (state_c == CHECK) & (check == 6'b011100);
not_match = (state_c == CHECK) & (check != 6'b011100);
end
end
endmodule
写完了,还是两种状态的划分简单点啊~不过这两种实际上都有点像骡子了,都用计数器了,再搞个状态机。。。。这题目设计有点怪怪的,强行要求状态机,分0-6的状态实际上也是个计数器嘛