序列检测器:状态转移图+Morrer状态机(三段式)+Modelsim仿真 

序列检测器:状态转移图+Morrer状态机(三段式)+Modelsim仿真 

 

目录 

- 1、绘制状态转移图 

- 1.1、在Sublime 中用Graphviz绘制状态转移图 

- 1.2、在Notepad++ 中用Graphviz绘制状态转移图 

- 1.2、Morrer与Mealy型状态机的状态转移图对比 

- 2、Morrer状态机代码 

- 3、仿真TestBench代码 

- 4、Modelsim仿真 

- 5、调试修改代码 

- 6、仿真和调试问题以及解决思路 

 

 

【参考文章】 

1、第6章  如何写好状态机  节选自《Verilog设计与验证》 作者:吴继华、王诚   

下载PDF看原文  http://read.pudn.com/downloads328/ebook/1442931/A.pdf 

或者看总结  Verilog FSM设计的学习心得(二) 

来自 <https://www.cnblogs.com/freeny/archive/2012/04/15/2450168.html

2、【 FPGA 】序列检测器的Moore状态机实现 

https://blog.csdn.net/Reborn_Lee/article/details/85763185 

3、【 FPGA 】序列检测器的Mealy状态机实现 

https://blog.csdn.net/Reborn_Lee/article/details/85798105 

4、Verilog实现--序列检测器、自动饮料售卖机 

https://blog.csdn.net/qq_34070723/article/details/100737225 

5、第一次verilog实验——序列检测器的实现 

来自 <https://www.cnblogs.com/yulongchen/archive/2013/02/13/2911046.html>  

 

【注意】《如何写好状态机》中的模板有适用范围 

Altera模块声明如下: 

module state (  

    nrst,clk, 

    i1,i2, 

    o1,o2, 

);  

input          nrst,clk;  

input          i1,i2, 

output        o1,o2;     

reg             o1,o2;   

 

Xilinx的模块声明如下: 

module state (  

    input nrst,clk, 

    input  i1,i2, 

    output reg o1,o2,err 

);  

 

【目标】设计一个序列检测器(无重叠检测),检测序列1101,检测到输出1,否则输出0 

 

1、绘制状态转移图 

1.1、在Sublime 中用Graphviz绘制状态转移图 

【参考】Graphviz 安装及结合sublime 

来自 <https://zhuanlan.zhihu.com/p/22820399>  

错误是file or directory not found, 

但报告的内容path看起来有些混乱-即它不包括macports放置可执行文件的目录。 

看着https://forum.sublimetext.com/t/how-to-set-path-on-os-x-so-sublime-can-see-it/11842 

重新启动Sublime并解决了问题。 

来自 <https://gist.github.com/olange/6834323ffc613b2ba25f>  

 

1.2、在Notepad++ 中用Graphviz绘制状态转移图 

【参考】NppGraphViz,一个Notepad ++插件,可将当前选项卡的文档发送到GraphViz预览窗口。 

来自 <https://github.com/jrebacz/NppGraphViz>  

【参考】NppGraphViz不添加语法突出显示,但是可以在此处使用该功能: https://github.com/signmotion/graphviz-syntax-highlighting 

 

1.2、Morrer与Mealy型状态机的状态转移图对比 

 

 

Morrer型状态机:摩尔状态机的输出仅仅依赖于当前状态,而与输入条件无关 

Graphviz 代码Sequencer-Moore.gv 如下 

digraph fsm { 

"IDLE" -> "IDLE" [label= "0"] 

"IDLE" -> "S1" [label= "1"]   

 

"S1" -> "IDLE" [label= "0"] 

"S1" -> "S2" [label= "1"]   

  

"S2" -> "S2" [label= "1"] 

"S2" -> "S3" [label= "0"]  

  

"S3" -> "S4" [label= "1"] 

"S3" -> "IDLE" [label= "0"] 

  

"S4" -> "IDLE" [label= "0"] 

"S4" -> "S1" [label= "1"]   

绘图 

 

 

 

米勒状态机:空闲态+中间3态,输出时由当前态S3+输入态,共同决定 

Graphviz 代码Sequencer-Mealy.gv 如下 

digraph fsm { 

"IDLE" -> "IDLE" [label= "0"] 

"IDLE" -> "S1" [label= "1"]   

 

"S1" -> "IDLE" [label= "0"] 

"S1" -> "S2" [label= "1"]   

  

"S2" -> "S2" [label= "1"] 

"S2" -> "S3" [label= "0"]  

  

"S3" -> "IDLE" [label= "1"] 

"S3" -> "IDLE" [label= "0"]   


 

绘图 

 

2、Morrer状态机代码 

Sequencer_Morrer.v 源代码如下: 

`timescale 1ns / 1ps 

SourceCode:Logic 

// Company:  

// Engineer:  

//  

// Create Date: 2019/01/04 11:16:29 

// Design Name:  

// Module Name: seq_det_moore 

// Project Name:  

// Target Devices:  

// Tool Versions:  

// Description: Sequencer Detection - Moore FSM 

// 设计一个序列检测器,检测序列1101,检测到输出1,否则输出0 

// 摩尔状态机的输出仅仅依赖于当前状态,而与输入条件无关 

// Dependencies:  

//  

// Revision: 

// Revision 0.01 - File Created 

// Additional Comments: 

//  

// 

`define UD #1 //定义变量,可跨工程调用 UD user delay,初始化#1 

module seq_det_moore( 

input i_clk, 

input i_rst_n,  //系统复位,低电平有效 

input i_data, 

output reg o_out 

); 

 

//================================================= 

//input dalay:输入打一拍 

//================================================= 

reg i_data_reg = 1'b0; 

always @ (posedge i_clk) 

begin 

// if(i_rst_n) 

i_data_reg <= i_data; 

end 

//================================================= 

// state FSM:状态声明,4个有效状态+1个空闲状态 

//================================================= 

reg [3:0] CS,NS; //CS:Current State; NS:Next State 

localparam [3:0] //one hot with zero idle 

IDLE = 4'b0000, 

S1 = 4'b0001, 

S2 = 4'b0010, 

S3 = 4'b0100, 

S4 = 4'b1000; 

 

//================================================= 

// FSM input 

//================================================= 

//1st always block:sequential state transition 

//现态与次态转换 时序电路 

always @(posedge i_clk)  

begin 

if (!i_rst_n) begin 

CS <= IDLE;  // reset 

// i_data_reg <= 1'b0; //复位态,数据首位,赋值为0,则状态判断延时2clk 

end 

else 

CS <= NS; 

end 

 

//2nd always block:combinational condition judgment  

//第二段:各种状态间的跳变。 组合电路  

always @ (*)  

begin 

case(CS)  //状态转移,判断当前状态"CS" 

IDLE:begin 

if (i_data_reg) NS = S1; //第一位1,din == 1'b1 

else NS = IDLE; //din == 1'b0 

end 

S1: begin 

if (i_data_reg) NS = S2; //1, 11  

else NS = IDLE; //10,回到原点 

end  

S2: begin 

if (~i_data_reg) NS = S3; //0, 110  

else NS = S2; //111,等待/循环,11101 

end  

S3: begin 

if (i_data_reg) NS = S4; //1, 1101  

else NS = IDLE; //1100,回到原点 

end 

S4: begin 

if (i_data_reg) NS = S1; //下一组,第一位1   

else NS = IDLE; //下一组,第一位0,回原点  

end  

default: NS = IDLE; 

endcase 

end 

 

//================================================= 

// FSM output: Moore型,输出只与当前状态有关 

//================================================= 

//3rd always block:the sequential FSM output 

//第三段:确定最终的状态 

always @(posedge i_clk)  

begin 

if ( CS == S4) o_out <= 1; 

else o_out <= 0;  

end 

 

endmodule 

 

 

3、仿真TestBench代码 

TB_Sequencer_Morrer.v 源代码如下: 

`timescale 1ns / 1ps 

//SimulationCode:Test Bench/ 

// Company:  

// Engineer:  

//  

// Create Date: 2019/01/04 15:24:59 

// Design Name:  

// Module Name: seq_det_moore_tb 

// Project Name:  

// Target Devices:  

// Tool Versions:  

// Description:  

// 数据一开始就发送过去,第一个clk上升沿就接到信号,开始判断,但当前状态一直循环为空 

//就等解除复位态,下一个数据过来,进入下一状态 

//最终输出没有延时,相当于前4个clk上升沿输入信号,第5个clk上升沿 输出结果 

// Dependencies:  

//  

// Revision: 

// Revision 0.01 - File Created 

// Additional Comments: 

//  

// 

`define UD #1 

module seq_det_moore_tb; 

 

reg sim_clk; 

reg sim_rst_n; 

reg sim_i_data;  //输入序列,缓冲,赋值 

wire sim_o_out; 

 

// Note: CLK must be defined as a reg when using this method 

parameter CLK_PERIOD = 10;  //仿真周期10ns=100M 

parameter RST_CYCLE = 5; //复位周期数 

parameter RST_TIME = RST_CYCLE * CLK_PERIOD; //复位时间:5个时钟周期 

parameter IN_SEQ = 21'b1_1011_1010_1101_0010_1101; 

//时钟 10ns 

always #(CLK_PERIOD/2) sim_clk = ~sim_clk; 

/* 

//时钟:写法2 

always begin 

     i_clk = 1'b0; 

     #(CLK_PERIOD/2) clk = 1'b1; 

     #(CLK_PERIOD/2); 

end 

*/ 

reg [4:0]cnt; 

//过程赋值,一次性复位信号??????????? 

initial  

begin 

sim_clk = 1'b0; 

sim_rst_n = 1'b0; //复位再拉低,有效,保持足够长时间(5个clk) 

#RST_TIME sim_rst_n = 1'b1; //复位 

sim_i_data = 1'b0; //测试变量,赋初值 

end 

//过程赋值,循环,每次只改变数据的位数cnt 

always @(posedge sim_clk) 

begin 

if(!sim_rst_n) begin 

cnt <= 1'b0; 

// sim_i_data <= 1'b0; //复位态,数据首位,保持0 

end 

else begin 

cnt <= cnt +1'b1; 

sim_i_data <= IN_SEQ[cnt];   

//sim_i_data不输出,sim_i_data与IN_SEQ[cnt]有1个clk的延时,仅用于原始信号变化 

end 

end 

//模块实例,调用 

seq_det_moore u1( 

.i_clk ( sim_clk ),//input clk, 

.i_rst_n ( sim_rst_n ),//input rstn, 

.i_data ( IN_SEQ[cnt] ), 

//每次送一位数据,第0位数据在复位态就已经发送,第1位数据在解除复位后发送 

//.i_data ( sim_i_data ), 

//解除复位后,才发送数据 

.o_out ( sim_o_out ) 

); 

endmodule 

 

4、Modelsim仿真 

【参考】Modelsim的简单使用 

来自 <https://mp.weixin.qq.com/s/rTdjYNQV8Q1OnIuFYI0IPA>  

 

 

5、调试修改代码 

【参考】修改代码后如何使用 modelsim 仿真 

来自 <https://blog.csdn.net/qq_40793742/article/details/82830513>  

 

6、仿真和调试问题以及解决思路 

主要问题是输入序列到输出结果之间有延时 

下图写错了,应该是检测1101,延时分别为3.5clk 与 1.5clk 

 

原因1、Testbench文件中,赋值为循环,一次性送完数据,时间长 

 

2、改为循环中每次只改变送的数据位,每次送一位数据 

 

还是有延时 

Q1、复位态不发送数据,解除复位态后才发送, 

输入数据打一拍,FSM第二阶段判断也要clk等,延时有4个clk 

 

改为以下方法,延时消失 

Q2: 数据一开始就发送过去,第一个clk上升沿就接到信号,开始判断,但当前状态一直循环为空 

就等解除复位态,下一个数据过来,进入下一状态 

最终输出没有延时,相当于前4个clk上升沿输入信号,第5个clk上升沿 输出结果