1. 实验内容
• 使用FSM有限状态机进行序列检测
• 使用状态机检测“1011”,串行输入的测试序列为“1110110110111011”,输出信号为valid有效信号,检测到时输出高,否则为低,考虑序列叠加情况,比如“1011011”,则有两个“1011”,这需要输出两个valid有效信号
2. 实验过程
- 设计有限状态机 (FSM)
- 定义状态机状态:S0, S1, S2, S3, S4,其中:
- S0:初始状态。
- S1、S2、S3:检测到部分匹配的状态。
- S4:完全检测到目标序列“1011”。
- 当检测到目标序列“1011”时,状态机进入 S4,并将
flag
信号设为高电平。 - 状态迁移关系定义为:
- S0 -> S1:检测到第一个“1”。
- S1 -> S2:检测到“0”。
- S2 -> S3:检测到“1”。
- S3 -> S4:检测到最后一个“1”。
- S4 -> S1 或 S2:根据输入序列进行状态转换,以处理重叠序列。
- 画出状态机转移图:
- 状态机实现代码
// Verilog代码实现有限状态机序列检测
module sequence_test2 (
input clk, // 时钟信号
input rst, // 复位信号(高有效)
input data, // 串行输入数据
output reg flag // 有效信号输出,当检测到 "1011" 时为高
);
// 定义有限状态机的各个状态
parameter S0 = 2'd0; // 初始状态,等待第一个 '1'
parameter S1 = 2'd1; // 检测到第一个 '1'
parameter S2 = 2'd2; // 检测到 '10'
parameter S3 = 2'd3; // 检测到 '101'
// 当前状态和下一个状态寄存器
reg [1:0] current_state;
reg [1:0] next_state;
// 状态转换逻辑:在时钟上升沿或复位时更新当前状态
always @(posedge clk or posedge rst) begin
if (rst) begin
current_state <= S0; // 复位时回到初始状态
end else begin
current_state <= next_state; // 根据下一个状态更新当前状态
end
end
// 下一个状态的逻辑:根据当前状态和输入数据决定下一个状态
always @(*) begin
case (current_state)
S0: begin
if (data == 1'b1)
next_state = S1; // 检测到 '1',转到 S1
else
next_state = S0; // 仍然在 S0
end
S1: begin
if (data == 1'b0)
next_state = S2; // 检测到 '0',转到 S2
else
next_state = S1; // 连续的 '1',保持在 S1
end
S2: begin
if (data == 1'b1)
next_state = S3; // 检测到 '1',转到 S3
else
next_state = S0; // 检测到 '0',回到 S0
end
S3: begin
if (data == 1'b1)
next_state = S1; // 检测到 '1',完成 "1011",转到 S1 处理叠加
else
next_state = S0; // 检测到 '0',回到 S0
end
default: next_state = S0; // 默认回到 S0
endcase
end
// 输出逻辑:当在 S3 状态且输入为 '1' 时,输出 flag 高电平
always @(posedge clk or posedge rst) begin
if (rst) begin
flag <= 1'b0; // 复位时 flag 低电平
end else begin
if (current_state == S3 && data == 1'b1)
flag <= 1'b1; // 检测到 "1011",flag 置高
else
flag <= 1'b0; // 其他情况,flag 置低
end
end
endmodule
- 状态转换逻辑:
- 使用Verilog代码实现状态转换逻辑,利用always模块定义状态机的当前状态和下一个状态。在时钟上升沿时,依据输入数据决定状态的转移。
- 在完成对“1011”的检测后,FSM会继续保持检测,以便处理序列的重叠情况,例如在输入序列为“1011011”时,状态机会检测出两个有效的“1011”并输出两个高电平flag信号。
- 测试验证:
- 使用Testbench编写测试代码,对状态机进行仿真验证。输入的测试序列为
1110110110111011
,以验证状态机是否能够正确检测出所有的“1011”序列。 - 时钟周期设置为10ns,利用vivado查看波形
// Testbench代码验证状态机
module tb_sequence_test2;
reg clk;
reg rst;
reg data;
wire flag;
// 实例化被测试模块
sequence_test2 uut (
.clk(clk),
.rst(rst),
.data(data),
.flag(flag)
);
// 时钟信号生成:10ns 时钟周期
initial begin
clk = 1;
forever #5 clk = ~clk; // 每5ns翻转一次,10ns周期
end
// 测试序列:1110_1101_1011_1011
reg [15:0] test_sequence = 16'b1110_1101_1011_1011;
integer i;
initial begin
// 初始化信号
rst = 0;
data = 0;
#10;
rst = 1; // 激活复位
#10;
rst = 0; // 释放复位
// 发送测试序列,从最高位(bit 15)开始
for (i = 15; i >= 0; i = i - 1) begin
data = test_sequence[i];
#10; // 每位持续10ns
end
// 结束仿真
#20;
$stop;
end
// 监视信号变化,打印输出
initial begin
$monitor("Time: %0t | rst: %b | data: %b | flag: %b", $time, rst, data, flag);
end
endmodule
3. 结果分析
利用Vivado得到波形如图:
在仿真过程中,状态机顺利完成了对输入序列的检测,测试结果如下:
- 复位信号的影响:
- 在复位信号(rst)置高时,状态机正确回到初始状态(S0),flag信号也被置低。
- 复位信号释放后,FSM按设计从输入数据流中逐步进行状态转移,直至检测到完整的“1011”序列。
- 序列检测:
- 在输入序列中,FSM能够正确识别到4个“1011”序列。
- 在每次完成“1011”的检测后,flag信号在输出高电平后会再次回到低电平,表明状态机成功检测到并标识了有效的序列。
- 对于测试序列中的重叠序列,状态机也正确地输出了有效信号,证明了其对重叠序列的处理能力。
- 输出信号验证:
- flag信号的输出在4个检测到“1011”的位置正确置高,符合预期的实验结果。这说明状态机的状态转换和输出逻辑都能够很好地实现序列检测的需求。
4. 总结
通过本次实验,我们熟悉了Xilinx Vivado软件及仿真流程,掌握了时序逻辑的基本概念,了解了状态机的设计和使用。设计的FSM能够有效检测输入序列中的“1011”并处理重叠情况,仿真结果波形与预期一致。本实验展示了有限状态机在序列检测中的实用性,适用于通信协议中的帧头识别等场景。进一步的实验可以考虑更复杂的序列检测任务。