序列检测与状态机


记录一些学习心得与经典电路,欢迎大佬批评指正不吝赐教
本篇记录分别采用两段式和三段式状态机的写法,用米里型和摩尔型状态机实现序列检测功能

状态机结构图

两段式状态机结构图

摘自Verilog HDL实用精解

三段式状态机结构图

摘自Verilog HDL实用精解
本文要检测的序列是1101,并且可以实现重复检测,因此要注意最终状态之后不一定回到初始状态。

摩尔型状态机

摩尔型状态机与输入无关,只与当前状态有关

两段式状态机

状态转换图如图所示:
在这里插入图片描述

代码如下:

`timescale 1ns / 1ps
module seq(
input clk,
input rst_n,
input din,
output reg sign
    );
reg [4:0] state;
reg [4:0] state_n;

parameter
    IDLE = 5'b00001,
    s0   = 5'b00010,
	s1   = 5'b00100,
	s2   = 5'b01000,
	s3   = 5'b10000;

always@(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    state <= IDLE;
  else 
    state <= state_n;
end
 
always@(*)
begin 
  case(state)
    IDLE:begin
	       if(din == 1'b1)  state_n = s0;
		   else state_n = IDLE;
		 end
    s0:  begin
	       if(din == 1'b1)  state_n = s1;
		   else state_n = IDLE;
		 end
    s1:  begin
	       if(din == 1'b0)  state_n = s2;
		   else state_n = s1;
		 end
    s2:  begin  
	       if(din == 1'b1)  state_n = s3;
		   else state_n = IDLE;
		 end
	s3:  begin 
	       if(din == 1'b1)  state_n = s1;
		   else state_n = IDLE;		   
		 end
	default: begin
	       state_n = IDLE;
		 end
  endcase
end

always@(*)
begin
  if(!rst_n)
    sign = 1'b0;
  else 
  begin
    if(state == s3)
	  sign = 1'b1;
	else 
	  sign = 1'b0;
  end
end
		 
endmodule

testbench如下:采用了循环的方式重复赋值

`timescale 1ns / 1ps
module tb();

reg clk;
reg rst_n;
wire din;
wire sign;

reg[17:0] data;

initial begin
clk = 0;
rst_n =0;
#40
rst_n = 1;
#3000
$stop;
end
always #5 clk = ~clk;

always@(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    data <= 18'b1101_1011_1001_1011_00;
  else
    data <= {data[16:0],data[17]};
end

assign din = data[17];

seq seq1(
  .clk(clk),
  .rst_n(rst_n),
  .din(din),
  .sign(sign)
);

endmodule

仿真结果如图所示,可以发现当state处于s3状态时,输出sign信号为持续一个周期的高电平,并且第一个sign高电平与第二个sign高电平之间实现了连续检测。此时的sign输出高电平是在1101这个待检测序列已经传递完之后才有效的,注意与下面的米里型进行区分,米里型的sign信号是在收到第四个数字为1的同时就输出为1的。
波形图

三段式状态机

状态转换图同上
代码如下:

`timescale 1ns / 1ps
module seq(
input clk,
input rst_n,
input din,
output reg sign
    );
reg [4:0] state;
reg [4:0] state_n;

parameter
    IDLE = 5'b00001,
    s0   = 5'b00010,
	s1   = 5'b00100,
	s2   = 5'b01000,
	s3   = 5'b10000;

always@(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    state <= IDLE;
  else 
    state <= state_n;
end
 
always@(*)
begin 
  case(state)
    IDLE:begin
	       if(din == 1'b1)  state_n = s0;
		   else state_n = IDLE;
		 end
    s0:  begin
	       if(din == 1'b1)  state_n = s1;
		   else state_n = IDLE;
		 end
    s1:  begin
	       if(din == 1'b0)  state_n = s2;
		   else state_n = s1;
		 end
    s2:  begin  
	       if(din == 1'b1)  state_n = s3;
		   else state_n = IDLE;
		 end
	s3:  begin 
	       if(din == 1'b1)  state_n = s1;
		   else state_n = IDLE;		   
		 end
	default: begin
	       state_n = IDLE;
		 end
  endcase
end

always@(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    sign <= 1'b0;
  else 
  begin
    if(state_n == s3)
	  sign <= 1'b1;
	else 
	  sign <= 1'b0;
  end
end
		 
endmodule

testbench同上
仿真结果如下:
仿真结果
同样可以发现,当状态为s3时候,输出sign为持续一个周期的高电平。

米里型状态机

米里型状态机不仅与当前状态有关,也与输入信号有关

两段式状态机

状态转移图如图所示:
在这里插入图片描述
代码如下:

module seq(
input clk,
input rst_n,
input din,
output reg sign
    );
reg [3:0] state;
reg [3:0] state_n;

parameter
    s0 = 4'b0001,
	s1 = 4'b0010,
	s2 = 4'b0100,
	s3 = 4'b1000;

always@(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    state <= s0;
  else 
    state <= state_n;
end
 
always@(*)
begin 
  case(state)
    s0:  begin
	       if(din == 1'b1)  state_n = s1;
		   else state_n = s0;
		 end
    s1:  begin
	       if(din == 1'b1)  state_n = s2;
		   else state_n = s0;
		 end
    s2:  begin  
	       if(din == 1'b0)  state_n = s3;
		   else state_n = s2;
		 end
	s3:  begin 
	       if(din == 1'b1)  state_n = s1;
		   else state_n = s0;
		 end
	default: begin
	       state_n = s0;
		 end
  endcase
end

always@(*)
begin
  if(!rst_n)
    sign = 1'b0;
  else 
  begin
    if((state == s3) && (din == 1'b1))
	  sign = 1'b1;
	else 
	  sign = 1'b0;
  end
end
		 
endmodule

testbench和摩尔型的一样
仿真结果如图所示:
在这里插入图片描述

三段式状态机

代码如下:

module seq(
input clk,
input rst_n,
input din,
output reg sign
    );
reg [3:0] state;
reg [3:0] state_n;

parameter
    s0 = 4'b0001,
	s1 = 4'b0010,
	s2 = 4'b0100,
	s3 = 4'b1000;

always@(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    state <= s0;
  else 
    state <= state_n;
end
 
always@(*)
begin 
  case(state)
    s0:  begin
	       if(din == 1'b1)  state_n = s1;
		   else state_n = s0;
		 end
    s1:  begin
	       if(din == 1'b1)  state_n = s2;
		   else state_n = s0;
		 end
    s2:  begin  
	       if(din == 1'b0)  state_n = s3;
		   else state_n = s2;
		 end
	s3:  begin 
	       if(din == 1'b1)  state_n = s1;
		   else state_n = s0;
		 end
	default: begin
	       state_n = s0;
		 end
  endcase
end

always@(posedge clk or negedge rst_n)
begin
  if(!rst_n)
    sign <= 1'b0;
  else 
  begin
    if((state_n == s3) && (din == 1'b1))
	  sign <= 1'b1;
	else 
	  sign <= 1'b0;
  end
end
		 
endmodule

此时本来用的依然是上面的testbench,但是仿真后发现sign输出始终为0,经过改正testbench,发现如果采用下面的这种写法或者一位一位激励din都不会有问题,猜测可能是因为原先的这种写法是在时钟上升沿来临时才赋值给对data进行操作,然后再对din进行操作,编译过程中可能会导致在时钟上升沿处判断错误,如果有大佬有不同的想法,欢迎不吝赐教批评指正,万分感谢。
testbench写法:

`timescale 1ns / 1ps
module tb();

reg clk;
reg rst_n;
reg din;
wire sign;
integer i;

reg[17:0] data;

initial begin
clk = 0;
rst_n = 0;
data = 18'b1101_1011_1001_1011_00;
din = 0;
#10
rst_n = 1;
#5

for(i = 17 ; i >= 0 ; i = i-1)
begin
#10
din = data[i];
end
#3000
$stop;
end

always #5 clk = ~clk;

seq seq1(
  .clk(clk),
  .rst_n(rst_n),
  .din(din),
  .sign(sign)
);

endmodule

仿真结果如图所示:
在这里插入图片描述
米里型状态机的检测信号输出的位置是在最后一个1输入的同时拉高的,与摩尔型不同。
如果想实现单独检测的功能,将最后一个状态都指回到最初的状态即可。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先,需要明确Mealy型检测序列器的基本结构和原理。Mealy型检测序列器是一种基于有限状态机的电路,用于检测输入序列是否符合特定的模式,并输出相应的结果。它包含一个输入端口和一个输出端口,输入端口接收输入序列,输出端口输出检测结果。 针对检测1011这个模式,可以使用不同的状态机描述方式。 1. 一段式状态机 一段式状态机只包含一个状态,该状态可以根据输入序列的不同进行转移。对于检测1011的模式,可以使用以下状态转移: ``` 1 0 S0 ------> S0 ------> S1 ------> S2 ------> S3 | 0/0 | 1/0 | 0/1 | 1/1 | +----------+----------+----------+----------+ ``` 其中,S0为初始状态,输入0时保持在S0状态,输入1时转移到S1状态;S1状态输入0时转移到S2状态,输入1时转移到S0状态;S2状态输入0时转移到S0状态,输入1时转移到S3状态;S3状态为接受状态,输入0或1时保持在S3状态。 该状态机对应的状态转移表为: | 状态 | 输入0 | 输入1 | 输出 | |-----|------|------|------| | S0 | S0 | S1 | 0 | | S1 | S2 | S0 | 0 | | S2 | S0 | S3 | 1 | | S3 | S3 | S3 | 1 | 其中,输出为检测结果。 2. 两段式状态机 两段式状态机包含两个状态,分别为等待状态和接受状态。等待状态用于等待输入序列的起始,接受状态用于接受输入序列的结尾。对于检测1011的模式,可以使用以下状态转移: ``` +--- 1 ---+--- 0 ---+--- 1 ---+--- 1 ---+ | | | | | v v v v v S0 ---> S1 ---> S2 ---> S3 ---> S4 ---> S5 ``` 其中,S0为等待状态,输入0或1时保持在S0状态;S1状态输入1时转移到S2状态,输入0时保持在S1状态;S2状态输入0时转移到S1状态,输入1时转移到S3状态;S3状态输入1时转移到S4状态,输入0时保持在S3状态;S4状态输入1时保持在S4状态,输入0时转移到S5状态;S5状态为接受状态,输入0或1时保持在S5状态。 该状态机对应的状态转移表为: | 状态 | 输入0 | 输入1 | 输出 | |-----|------|------|------| | S0 | S0 | S1 | 0 | | S1 | S1 | S2 | 0 | | S2 | S1 | S3 | 0 | | S3 | S3 | S4 | 0 | | S4 | S5 | S4 | 0 | | S5 | S5 | S5 | 1 | 其中,输出为检测结果。 3. 三段式状态机 三段式状态机包含三个状态,分别为等待状态、检测状态和接受状态。等待状态用于等待输入序列的起始,检测状态用于检测输入序列的模式,接受状态用于接受输入序列的结尾。对于检测1011的模式,可以使用以下状态转移: ``` +--- 1 ---+--- 0 ---+--- 1 ---+--- 1 ---+ | | | | | v v v v v S0 ---> S1 ---> S2 ---> S3 ---> S4 ---> S5 | | | +-------- 0 --------+ | | +---------+ | v S6 ``` 其中,S0为等待状态,输入0或1时保持在S0状态;S1状态输入1时转移到S2状态,输入0时保持在S1状态;S2状态输入0时转移到S1状态,输入1时转移到S3状态;S3状态输入1时转移到S4状态,输入0时保持在S3状态;S4状态输入1时保持在S4状态,输入0时转移到S5状态;S5状态为接受状态,输入0或1时保持在S5状态;S2、S3和S4状态均为检测状态,输入0或1时保持在当前状态;S6为错误状态,当输入序列不符合模式1011时转移到S6状态。 该状态机对应的状态转移表为: | 状态 | 输入0 | 输入1 | 输出 | |-----|------|------|------| | S0 | S0 | S1 | 0 | | S1 | S1 | S2 | 0 | | S2 | S1 | S3 | 0 | | S3 | S3 | S4 | 0 | | S4 | S5 | S4 | 0 | | S5 | S5 | S5 | 1 | | S6 | S6 | S6 | 0 | 其中,输出为检测结果。如果输入序列不符合模式1011,则输出0,并转移到S6状态。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值