参考:https://blog.csdn.net/Reborn_Lee/article/details/85763185
序列检测器经常出现在笔试题目当中,其实其中的主要思想还是状态机的设计,因此本文也借着序列检测器这一点,讲讲状态机的设计。
一、序列检测器要是实现什么功能?
序列检测器主要是实现输入的一串序列是否是特定的序列。比如设计一个序列检测器,检测序列“11001”,检测到就输出1,否则输出0。
二、设计状态机来检测序列
首先要设计状态机,最好是先把状态转换图先画出来,有了状态转换图一切设计就很好办了。
根据状态转换图很容易就写出状态机了。状态机代码如下。
源文件:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/04/01 16:29:18
// Design Name:
// Module Name: seq_det_moore
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module seq_det_moore(
input Clk,
input Rst_n,
input Din,
output reg Dout
);
//
localparam [2:0] S0 = 3'b000;
localparam [2:0] S1 = 3'b001;
localparam [2:0] S2 = 3'b010;
localparam [2:0] S3 = 3'b011;
localparam [2:0] S4 = 3'b100;
localparam [2:0] S5 = 3'b101;
reg [2:0] Current_State;
reg [2:0] Next_State;
[email protected](posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
Current_State <= S0;
end
else begin
Current_State <= Next_State;
end
end
[email protected](Current_State or Din)begin
case(Current_State)
S0:begin
if(Din==1'b1)
Next_State = S1;
else
Next_State = S0;
end
S1:begin
if(Din==1'b1)
Next_State = S2;
else
Next_State = S0;
end
S2:begin
if(Din==1'b0)
Next_State = S3;
else
Next_State = S2;
end
S3:begin
if(Din==1'b0)
Next_State = S4;
else
Next_State = S1;
end
S4:begin
if(Din==1'b1)
Next_State = S5;
else
Next_State = S0;
end
S5:begin
if(Din==1'b1)
Next_State = S1;
else
Next_State = S0;
end
default:
Next_State = S0;
endcase
end
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//这里有四种四处方式,使用时需要去掉对应的注释
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//第一种组合状态输出
[email protected](Current_State) begin
if(Current_State==S5)
Dout = 1'b1;
else
Dout = 1'b0;
end
//第二种组合状态输出
// [email protected](posedge Clk) begin
// if(Current_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
//end
//第三种组合状态输出
//[email protected](posedge Clk) begin
// if(Next_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
//end
//第四种组合状态输出
//[email protected](Next_State) begin
// if(Next_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
// end
endmodule
测试文件:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/04/01 16:53:46
// Design Name:
// Module Name: tb_seq
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_seq;
reg Clk;
reg Rst_n;
reg Din;
reg [20:0] din_mid;
wire Dout;
integer i;
parameter CLK_PERIOD = 10;
always # (CLK_PERIOD/2) Clk = ~Clk;
initial begin
Clk = 0;
end
initial begin
Rst_n = 1'b0;
din_mid = 21'b1100_0101_1100_1010_11101;
Din = 0;
#20;
Rst_n = 1'b1;
#5;
for(i=20;i>=0;i=i-1) begin
#CLK_PERIOD;
Din = din_mid[i];
end
end
seq_det_moore uut(
.Clk(Clk),
.Rst_n(Rst_n),
.Din(Din),
.Dout(Dout)
);
endmodule
第一种组合输出的波形图:
//1
//[email protected](Current_State) begin
// if(Current_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
//end
第二种组合输出的波形图:
//2
// [email protected](posedge Clk) begin
// if(Current_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
//end
第三种组合输出波形图:
////3
//[email protected](posedge Clk) begin
// if(Next_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
//end
第四种组合输出波形图:
////4
//[email protected](Next_State) begin
// if(Next_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
// end
三、状态机的输出的写法
借助这个序列检测器说一下状态机如何写,只说三段式状态机。
1、说明部分(也就是定义各种状态)
localparam [2:0] S0 = 3'b000;
localparam [2:0] S1 = 3'b001;
localparam [2:0] S2 = 3'b010;
localparam [2:0] S3 = 3'b011;
localparam [2:0] S4 = 3'b100;
localparam [2:0] S5 = 3'b101;
reg [2:0] Current_State;
reg [2:0] Next_State;
2、三段状态机
第一段,次态到现态的转换。
[email protected](posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
Current_State <= S0;
end
else begin
Current_State <= Next_State;
end
end
第二段:状态译码过程
[email protected](敏感表),敏感表中是输入和当前状态。这个过程只能是组合逻辑,里面的赋值用‘=’号。
[email protected](Current_State or Din)begin
case(Current_State)
S0:begin
if(Din==1'b1)
Next_State = S1;
else
Next_State = S0;
end
S1:begin
if(Din==1'b1)
Next_State = S2;
else
Next_State = S0;
end
S2:begin
if(Din==1'b0)
Next_State = S3;
else
Next_State = S2;
end
S3:begin
if(Din==1'b0)
Next_State = S4;
else
Next_State = S1;
end
S4:begin
if(Din==1'b1)
Next_State = S5;
else
Next_State = S0;
end
S5:begin
if(Din==1'b1)
Next_State = S1;
else
Next_State = S0;
end
default:
Next_State = S0;
endcase
end
第三段:输出过程
这一段的输出有很多种写法,主要分为当前状态和下一状态输出,也就是在上面讨论的四种输出波形。其中,常用的输出方式如下:
第一种:
[email protected](Current_State) begin
if(Current_State==S5)
Dout = 1'b1;
else
Dout = 1'b0;
end
第二种:
////3
//[email protected](posedge Clk) begin
// if(Next_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
//end
这两种输出波形是一样的,都是在当前周期输出结果。
如果要延缓一个周期就需要用种方式:
// [email protected](posedge Clk) begin
// if(Current_State==S5)
// Dout = 1'b1;
// else
// Dout = 1'b0;
//end