图形输入法打出的图形状态机实验

第1页/共2页
Quartus II 的图形化状态机输入工具
Quartus II 自带图形化状态机输入工具,该工具有向导,可以输入状态、输入输出端口、状态转移条件,然后生成HDL文件。生成的HDL文件中,状态机设计为两段式,默认状态编码为二进制。有不定状态。
需要注意,使用该工具生成状态机逻辑,不能使用&&、||操作符,+、-等运算符来作为状态转移条件的一部分。条件必须是很简单的高、低电平、比较、取反等符号。如果不希望生成锁存器逻辑,那么需要为每一个状态指定OTHERS条件。
第1页/共2页
寻找更多 ""有限状态机,也称为 FSM(Finite State Machine) ,其在任意时刻都处于有限状态集合中的某一状态。当其获得一个输入字符 时,将从
当前状态 转换到 另一个状态 ,或者仍然保持在当前状态 。任何一个FSM都可以用状态转换图来描述,图中的节点表示FSM中的一个状态,有向加权边表示输入字符时状态的变化。如果图中不存在与当前状态与输入字符对应的有向边,则FSM将进入“消亡状态 (Doom State) ”,此后FSM将一直保持“消亡状态”。状态转换图中还有两个特殊状态:状态1称为
“起始状态” ,表示FSM的初始状态。状态6称为 “结束状态” ,表示成功识别了所输入的字符序列。
在启动一个FSM时,首先必须将FSM置于“起始状态”,然后输入一系列字符,最终,FSM会到达“结束状态”或者“消亡状态”。
在通常的FSM模型中,一般还存在一个“接受状态”,并且FSM可以从“接受状态”转换到另一个状态,只有在识别最后一个字符后,才会根据最终状态来决定是否接受所输入的字符串。此外,也可以将“其实状态”也作为接受状态,因此空的输入序列也是可以接受的。
程序设计思路大致如下:
使用状态转换图描述FSM 状态转换图中的结点对应不同的状态对象 每个状态对象通过一个输入字符转换到另一个状态上,或者保持原状态不变。
通过输入字符从一个状态切换到另一个状态的过程,我们称之为一个 映射 。在计算机程序设计中, 我们可以有两种表示映射的方法:
通过算法表示,即“可执行代码(Executable Code)”方式 通过一张映射表,即“被动数据(Passive Data)”方式
如下详细介绍这两种实现方式:
通过Executable Code 实现映射的FSM :
这种方式主要是通过条件分支来处理不同的字符,如if或者switch语句块,如
State* State1::Transition(char c)
return &s2;
return &s3;
return &s4;
return &s5;
case '\0':
return NULL;
return NULL;
// fsm_with_executable_code.h
#ifndef FSM_WITH_EXECUTABLE_CODE_H
#define FSM_WITH_EXECUTABLE_CODE_H
#include &string.h&
class State
virtual State* Transition(char c) = 0;
void Reset();
// move to start state
void Advance(char c);
// advance one transition
int EndState();
int DoomState();
// &s1, &s2, ..., &s6; NULL ==& doom
class State1 : public State
State* Transition(char c);
class State2 : public State
State* Transition(char c);
class State3 : public State
State* Transition(char c);
class State4 : public State
State* Transition(char c);
class State5 : public State
State* Transition(char c);
class State6 : public State
State* Transition(char c);
#endif // FSM_WITH_EXECUTABLE_CODE_H
// fsm_with_executable_code.cc
#include &fsm_with_executable_code.h&
State1 s1;
State2 s2;
State3 s3;
State4 s4;
State5 s5;
State6 s6;
Fsm::Fsm()
p_current = NULL;
void Fsm::Reset()
p_current = &s1;
void Fsm::Advance(char c)
if (p_current != NULL)
p_current = p_current-&Transition(c);
int Fsm::EndState()
return p_current == &s6;
int Fsm::DoomState()
return p_current == NULL;
State* State1::Transition(char c)
return &s2;
return &s3;
return &s4;
return &s5;
case '\0':
return NULL;
return NULL;
State* State2::Transition(char c)
return &s2;
return &s6;
case '\0':
return NULL;
return NULL;
State* State3::Transition(char c)
return &s3;
return &s4;
return &s6;
case '\0':
return NULL;
return NULL;
State* State4::Transition(char c)
return &s4;
return &s6;
case '\0':
return NULL;
return NULL;
State* State5::Transition(char c)
return &s2;
return &s5;
return &s6;
return &s4;
case '\0':
return NULL;
return NULL;
State* State6::Transition(char c)
return NULL;
// test_with_executable_code.cc
#include &fsm_with_executable_code.h&
#include &stdio.h&
// printf, scanf
#include &stdlib.h& // system
void test_fsm()
char input_string[80];
printf(&Enter input expression: &);
scanf(&%s&, input_string);
fsm.Reset();
int index = 0;
fsm.Advance(input_string[index++]);
while (!fsm.EndState() && !fsm.DoomState())
fsm.Advance(input_string[index++]);
if (fsm.EndState())
printf(&\nValid input expression&);
printf(&\nInvalid input expression&);
int main()
test_fsm();
system(&pause&);
& 通过Passive Data 实现映射的FSM :
在如上的switch分支中,其使用类型大致相同,因此,我们可以考虑将相似的信息保存到一张表中,这样就可以在程序中避免很多函数调用。在每个状态中都使用一张转换表来表示映射关系,转换表的索引使用输入字符来表示。此外,由于通过转换表就可以描述不同状态之间的变化,那么就没有必要将每种状态定义为一个类了,即不需要多余的继承和虚函数了,仅使用一个State即可。
#include &limits.h&
class State
State* transition[range];
对于任意一个状态state和输入字符c,后续状态都可以通过state.transition[c]来确定。
类Fsm中的成员state包含6个状态,为了对应方便,我们将结束状态放在state[0]中,每个状态都使用一个三元组 { 当前状态,输入字符,下一个状态 } 来表示:
struct TransGraph
// use triple to describe map
int current_
char input_
};如此,使用了转换表代替了虚函数,简化了程序的设计。
// fsm_with_passive_data.h
#ifndef FSM_WITH_PASSIVE_DATA_H
#define FSM_WITH_PASSIVE_DATA_H
#include &string.h&
#include &limits.h&
// CHAR_MAX
const int range = CHAR_MAX + 1;
class State
State* transition[range];
struct TransGraph
// use triple to describe map
int current_
char input_
void Reset();
// move to start state
void Advance(char c);
// advance one transition
int EndState();
int DoomState();
// &s1, &s2, ..., &s6; NULL ==& doom
State state[6];
// 6 states, state[0] is end state
#endif // FSM_WITH_PASSIVE_DATA_H
// fsm_with_passive_data.cc
#include &fsm_with_passive_data.h&
State::State()
for (int i = 0; i & ++i)
transition[i] = NULL;
Fsm::Fsm()
static TransGraph graph[] =
{1, 'A', 2}, {1, 'B', 3}, {1, 'C', 4}, {1, 'D', 5},
{2, 'E', 2}, {2, 'I', 0},
{3, 'F', 3}, {3, 'J', 0}, {3, 'M', 4},
{4, 'G', 4}, {4, 'K', 0},
{5, 'H', 5}, {5, 'L', 0}, {5, 'O', 2}, {5, 'N', 4},
for (TransGraph* p_tg = p_tg-&current_state != 0; ++p_tg)
state[p_tg-&current_state].transition[p_tg-&input_char] = &state[p_tg-&next_state];
p_current = NULL;
void Fsm::Reset()
p_current = &state[1];
void Fsm::Advance(char c)
if (p_current != NULL)
p_current = p_current-&transition[c];
int Fsm::EndState()
return p_current == &state[0];
int Fsm::DoomState()
return p_current == NULL;
// test_with_passive_data.cc
#include &fsm_with_passive_data.h&
#include &stdio.h&
// printf, scanf
#include &stdlib.h& // system
void test_fsm()
char input_string[80];
printf(&Enter input expression: &);
scanf(&%s&, input_string);
fsm.Reset();
int index = 0;
fsm.Advance(input_string[index++]);
while (!fsm.EndState() && !fsm.DoomState())
fsm.Advance(input_string[index++]);
if (fsm.EndState())
printf(&\nValid input expression&);
printf(&\nInvalid input expression&);
int main()
test_fsm();
system(&pause&);
通用FSM的设计
如果类Fsm可以表示任意类型的FSM,那么就更符合程序设计的要求了。在构造函数中执行的具体配置应该被泛化为一种机制,我们通过这种机制来建立任意的FSM。在Fsm的构造函数中,应该将转换表作为一个参数传入,而非包含具体的转换表,如此,则不需要将转换表的大小硬编码到Fsm中了。因此,在构造函数中必须动态地创建这个存放转换表的内存空间,在析构函数中记着销毁这块内存。
Fsm(TransGraph* p_tg);
virtual ~Fsm();
void Reset();
void Advance(char c);
int EndState();
int DoomState();
Fsm::Fsm(TransGraph* p_tg)
int max_state = 0;
// size for dynamically allocated graph
for (TransGraph* p_temp = p_ p_temp-&current_state != 0; ++p_temp)
if (p_temp-&current_state & max_state)
max_state = p_temp-&current_
if (p_temp-&next_state & max_state)
max_state = p_temp-&next_
p_state = new State[max_state + 1];
for (TransGraph* p_temp = p_ p_temp-&current_state != 0; ++p_temp)
p_state[p_temp-&current_state].transition[p_temp-&input_char] = &p_state[p_temp-&next_state];
p_current = NULL;
Fsm::~Fsm()
delete []p_
// fsm_with_generalization.h
#ifndef FSM_WITH_GENERALIZATION_H
#define FSM_WITH_GENERALIZATION_H
#include &string.h&
#include &limits.h&
// CHAR_MAX
const int range = CHAR_MAX + 1;
class State
State* transition[range];
struct TransGraph
int current_
char input_
Fsm(TransGraph* p_tg);
virtual ~Fsm();
void Reset();
void Advance(char c);
int EndState();
int DoomState();
#endif // FSM_WITH_GENERALIZATION_H
// fsm_with_generalization.cc
#include &fsm_with_generalization.h&
State::State()
for (int i = 0; i & ++i)
transition[i] = NULL;
Fsm::Fsm(TransGraph* p_tg)
int max_state = 0;
// size for dynamically allocated graph
for (TransGraph* p_temp = p_ p_temp-&current_state != 0; ++p_temp)
if (p_temp-&current_state & max_state)
max_state = p_temp-&current_
if (p_temp-&next_state & max_state)
max_state = p_temp-&next_
p_state = new State[max_state + 1];
for (TransGraph* p_temp = p_ p_temp-&current_state != 0; ++p_temp)
p_state[p_temp-&current_state].transition[p_temp-&input_char] = &p_state[p_temp-&next_state];
p_current = NULL;
Fsm::~Fsm()
delete []p_
void Fsm::Reset()
p_current = &p_state[1];
void Fsm::Advance(char c)
if (p_current != NULL)
p_current = p_current-&transition[c];
int Fsm::EndState()
return p_current == &p_state[0];
int Fsm::DoomState()
return p_current == NULL;
// test_with_generalization.cc
#include &fsm_with_generalization.h&
#include &stdio.h&
// printf, scanf
#include &stdlib.h& // system
void test_fsm()
char input_string[80];
printf(&Enter input expression: &);
scanf(&%s&, input_string);
TransGraph graph[] =
{1, 'A', 2}, {1, 'B', 3}, {1, 'C', 4}, {1, 'D', 5},
{2, 'E', 2}, {2, 'I', 0},
{3, 'F', 3}, {3, 'J', 0}, {3, 'M', 4},
{4, 'G', 4}, {4, 'K', 0},
{5, 'H', 5}, {5, 'L', 0}, {5, 'O', 2}, {5, 'N', 4},
Fsm fsm(graph);
fsm.Reset();
int index = 0;
fsm.Advance(input_string[index++]);
while (!fsm.EndState() && !fsm.DoomState())
fsm.Advance(input_string[index++]);
if (fsm.EndState())
printf(&\nValid input expression&);
printf(&\nInvalid input expression&);
int main()
test_fsm();
system(&pause&);
当然也可以将上述程序中的转换表不放在主程序中,而是由一个派生自Fsm的子类SpecificFsm提供,在SpecificFsm中设置具体的转换表,然后通过SpecificFsm的初始化列表传到基类Fsm中,这样在主程序中就可以使用SpecificFsm来进行操作了。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:9317次
排名:千里之外
原创:13篇
转载:10篇
(1)(3)(3)(1)(1)(1)(3)(3)(3)(1)(2)(1)君,已阅读到文档的结尾了呢~~
广告剩余8秒
文档加载中
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
EDA实验六-用状态图输入法实现序列检测器.doc
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口状态机的设计与实现
状态机的设计与实现
作者:zhsj&&&&
在数字逻辑电路中,状态机是一个非常重要的概念,也是常用的一种结构,状态机常常用于序列检测、序列信号的产生以及时序产生等方面。利用Verilog语言也可以编写出可综合的状态机,并有多种编写格式和编写原则,本文主要整理的是状态机的一般编写方法和形式,以及可综合的状态机的一些设计原则。
一、状态机的结构
状态机的组成
状态机是组合逻辑和寄存器逻辑的特殊组合,一般包括两个部分:组合逻辑部分和寄存器逻辑部分。寄存器用于存储状态,组合电路用于状态译码和产生输出信号。状态机的下一个状态及输出不仅与输入信号有关,还与寄存器当前状态有关,其基本要素有三个,即状态、输入和输出。
状态也叫做状态变量。在逻辑设计中,使用状态划分逻辑顺序和时序规律。例如,要设计一个交通灯控制器可以用允许通行、慢行和禁止通行作为状态;设计一个电梯控制器,每层就是一个状态等。
输入是指状态机中进入每个状态的条件。有的状态机没有输入条件,其中的状态转移比较简单;有的状态机有输入条件,当某个输入条件存在时,才能转移到相应的状态。例如,交通灯控制器就没有输入条件,状态随着时间的改变而自动跳转;电梯控制器是存在输入的,每层的上下按键,以及电梯内的层数选择按键都是输入,会对电梯的下一个状态产生影响。
输出是指在某一状态时特定发生的事件。例如,交通灯控制器在允许通行状态输出绿色,缓行状态输出黄色,禁止通行状态输出红色;电梯控制器在运行时一直会输出当前所在的层数及当前运行的方向(上升或下降)。
状态机的分类
根据输出是否与输入信号有关,状态机可以划分为Mealy型状态机和Moore型状态机两种;根据输出是否与输入信号同步,状态机可以划分为异步状态机和同步状态机两种。由于目前的电路设计中以同步设计为主,所以本文只介绍同步状态机。
1.2.1 &Mealy型状态机
Mealy型状态机的输出同时依赖于当前的状态和输入信号,其结构如图1.1所示。输出可以在输入发生变化后立即改变,而与时钟信号无关。因此Mealy型状态机具有异步输出特性。在实际中,Mealy型状态机的应用比较广泛,该类型常常能够减少状态机的状态数。
Mealy型状态机结构
1.2.2 &Moore型状态机
Moore型状态机的输出仅依赖于当前的状态,其逻辑结构如图1.2所示。组合逻辑块将输入和当前状态映射为适当的次态,作为状态寄存器的输入,并在下一个时钟周期覆盖当前状态,使得状态机状态发生变化。输出是通过组合逻辑块计算得到的,本质上是当前状态的函数。其中,输出的变化和状态的变化都与时钟信号变化沿保持同步。
Moore型状态机结构
二、用Verilog描述状态机
状态编码方式
状态编码又称为状态分配。通常有多种编码方法,如果编码方案选择得当,设计的电路可以简单;反之,电路会占用过多的逻辑或降低速度。设计时,必须综合考虑电路复杂度和电路性能这两个因素。下面主要介绍二进制编码、格雷编码和独热码。
2.1.1 &二进制编码
二进制编码和格雷编码都是压缩状态编码。二进制编码的优点是使用的状态向量最少,但从一个状态转换到相邻状态时,可能会有多个位发生变化,瞬变次数多,易产生毛刺。由于二进制编码的表示形式比较通用,在此不做详细的介绍。
2.1.2 &格雷编码
格雷码在相邻状态的转换中,每次只有1位发生变化,虽然减少了产生毛刺和一些暂态的可能,但不适用于有很多状态跳转的情况。表2-1给出了十进制数字0~9的格雷码表示形式。
格雷码数据列表
十进制数字
十进制数字
由于在有限状态机中,输出信号经常是通过状态的组合逻辑电路来驱动,因此有可能由于输入信号的不同时到达而产生毛刺。如果状态机的所有状态是一个顺序序列,则可通过格雷码来消除毛刺,但对于时序逻辑状态机中的复杂分支,格雷编码也不能达到消除毛刺的目的,所以此编码方式用得也不是太多。
2.1.3 &独热码
独热码是指对任意给定的状态,状态向量中只有1位为1,其余位都为0。n状态的状态机就需要n个触发器。这种状态机的速度与状态的数量无关,仅取决于到某特定状态的转移数量,速度很快。当状态机的状态增加时,如果使用二进制编码,那么状态机速度会明显下降。而采用独热码,虽然多用了触发器,但由于状态译码简单,节省和简化了组合逻辑电路。独热码还具有设计简单、修改灵活、易于综合和调试等优点。表2-2给出了十进制数字0~9的独热码的表示形式。
独热码数据列表
十进制数字
十进制数字
000_0000_00
000_0100_00
000_0000_01
000_1000_00
000_0000_10
001_0000_00
000_0001_00
010_0000_00
000_0010_00
100_0000_00
对于寄存器数量多而门逻辑相对缺乏的FPGA器件,采用独热码可以有效提高电路的速度和可靠性,也有利于提高器件资源的利用率。独热码有很多无效状态,应该确保状态机一旦进入无效状态时,可以立即跳转到确定的已知状态。
状态机的Verilog实现
基于Verilog
HDL语言的状态机设计方法非常灵活,按代码描述方法的不同,可分为一段式描述、两段式描述和三段式描述等。不同的描述所对应的电路是不同的,因此最终的性能也是不同的。由于一段式的描述方式存在很多缺点,比如说可维护性差,代码复杂,不易修改和调试等,所以在此不做介绍。为了保证代码的规范性、可靠性和可维护性,下面分别介绍两段式和三段式的描述方法。
2.2.1 &两段式描述法
在这种描述方法中,一个时序逻辑的always块用于给当前状态向量赋值,即完成改变状态的工作;另一个组合逻辑的always块用于计算下一状态和输出逻辑,通常用于描述组合输出的Moore状态机或异步Mealy状态机。
【例1】用两段式描述法描述状态机,二进制编码
module FSM_Two_Sec(clk, rst_n, sig1, sig2, a,
input clk, rst_n;
input sig1, sig2;
output reg a,
& //定义三个状态参数,二进制编码
parameter S0 = 2'b00, S1 = 2'b01, S2 =
reg [1:0] state, next_
//时序逻辑的always块用于改变状态
always @ (posedge clk or negedge
state &= S0;
&&state &=
//组合逻辑的always块用于计算输出和下一状态&&&&&
always @ (state or sig1 or sig2
//将输入和当前状态加入到敏感列表中
case (state)
&&if (sig1 ||
&&&&&&&&&&&
&&a = 1'b1;
&&&&&&&&&&&
&&a = 1'b0;
&&if(sig1 == 1'b1)
&&&&&&&&&&&
&&next_state = S1;
&&&&&&&&&&&
&&next_state = S0;
&&S1: begin
&&a = 1'b0;
&&if(sig2 == 1'b1)
&&&&&&&&&&&
&&next_state = S2;
&&&&&&&&&&&
&&next_state = S0;
&&S2: begin
&&b = 1'b0;
&&a = 1'b0;
&&next_state = S0;
&&default: begin
&&next_state = S0;
2.2.2 &三段式描述法
三段式描述法包含三个always块,其中有一个组合逻辑的always块,用于计算下一状态;有一个时序逻辑的always块,用于进行状态切换,即改变当前状态;还有另外一个always块,可以为时序逻辑,也可以为组合逻辑,用于计算状态机的输出,但需要注意的是,这样综合后的结果是不一样的。
【例2】用三段式描述法描述状态机,二进制编码
module FSM_Three_Sec1(clk, rst_n, sig1, sig2, a,
input clk, rst_n;
input sig1, sig2;
output reg a,
& //定义状态参数,二进制编码
parameter[1:0] S0 = 2'b00, S1 = 2'b01, S2 =
reg [1:0] state, next_
//时序逻辑,用于进行改变状态
always @(posedge clk or negedge
& if (!rst_n)
&&&&&&&&&&&&&
& state &= S0;
&&&&&&&&&&&&&
& state &= next_
& //时序逻辑,用于计算输出
always @(posedge clk or negedge
& if (!rst_n)
&&&&&&&&&&&&&
&&&&&&&&&&&&&
&&&&&&&&&&&&&
& case(state)
&&&&&&&&&&&&&&&&&&&&
& S0: begin
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& if (sig1 || sig2)
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
& S1: begin
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
& default: begin
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&
& //组合逻辑,用于计算下一状态
always @(state or sig1 or
& case (state)
&&&&&&&&&&&&&
& S0: begin
&&&&&&&&&&&&&&&&&&&&
& if(sig1)
&&&&&&&&&&&&&&&&&&&&
&&next_state = S1;
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
&&&&&&&&&&&&&
& S1: begin
&&&&&&&&&&&&&&&&&&&&
& if(sig2)
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& next_state = S2;
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
& S2: begin
&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
&&&&&&&&&&&&&
& default: begin
&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
【例3】用三段式描述法描述状态机,二进制编码
module FSM_Three_Sec2(clk, rst_n, sig1, sig2, a,
input clk, rst_n;
input sig1, sig2;
output reg a,
//定义状态参数,二进制编码
parameter[1:0] S0 = 2'b00, S1 = 2'b01, S2 =
reg [1:0] state, next_
//组合逻辑,用于计算输出
always @(state or sig1 or
& a = (state == S0) && (sig1 ||
& b = (state == S1);
& //时序逻辑,用于改变状态
always @(posedge clk or negedge
& if (!rst_n)
&&&&&&&&&&&&&
& state &= S0;
&&&&&&&&&&&&&
& state &= next_
& //组合逻辑,用于计算下一状态
always @(state or sig1 or
& case (state)
&&&&&&&&&&&&&
& S0: begin
&&&&&&&&&&&&&&&&&&&&
& if(sig1)
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& next_state = S1;
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
&&&&&&&&&&&&&
& S1: begin
&&&&&&&&&&&&&&&&&&&&
& if(sig2)
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& next_state = S2;
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
&&&&&&&&&&&&&
& S2: begin
&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
&&&&&&&&&&&&&
& default: begin
&&&&&&&&&&&&&&&&&&&&
& next_state = S0;
&&&&&&&&&&&&&
【例4】用三段式描述法描述状态机,独热编码
module FSM_Three_Sec3(clk, rst_n, sig1, sig2, a,
input clk, rst_n;
input sig1, sig2;
output reg a,
//定义状态参数,独热编码
parameter S0 = 3'b001, S1 = 3'b010, S2 =
reg [2:0] state, next_
//组合逻辑,用于计算输出
always @(state or sig1 or
&& &a = (state
== S0) && (sig1 || sig2);
& &&b = (state
//时序逻辑,用于改变状态
always @ (posedge clk or negedge
&&if (!rst_n)
&&state &= S0;
&&state &=
//组合逻辑,用于计算下一状态
always @ (state or sig1 or
&&next_state = S0;
&&case (state)
&&S0: begin
&&&&&&&&&&&
&&if(sig1)
&&&&&&&&&&&&&&
&&&next_state =
&&&&&&&&&&&
&&&&&&&&&&&&&&&
&&next_state = S0;
&&S1 : begin
&&&&&&&&&&&
&&if(sig2)
&&&&&&&&&&&&&&
&&&next_state =
&&&&&&&&&&&
&&&&&&&&&&&&&&&
&&next_state = S0;
&&S2 : begin
&&&&&&&&&&
&&&next_state =
&&default: begin
&&&&&&&&&&&
&&next_state = S0;
【例5】用三段式描述法描述状态机,独热编码的另一种形式
module FSM_Three_Sec4(clk, rst_n, sig1, sig2, a,
input clk, rst_n;
input sig1, sig2;
output reg a,
//定义状态参数,独热编码
parameter S0 = 0, S1 = 1, S2 =
reg [2:0] state, next_
//组合逻辑,用于计算输出
always @(state or sig1 or
& a = (state == S0) && (sig1 ||
& b = (state == S1);
//时序逻辑,用于改变状态
always @ (posedge clk or negedge
state &= 3'b001;
state &= next_
//组合逻辑,用于计算下一状态
always @ (state or sig1 or
next_state = 3'b000;
state [S0]: begin
&&&&&&&&&&&
&&&&&&&&&&&&&&&
next_state [S1] = 1'b1;
&&&&&&&&&&&
&&&&&&&&&&&&&&&
next_state [S0] = 1'b1;
state [S1]: begin
&&&&&&&&&&&
&&&&&&&&&&&&&&&
next_state [S2] = 1'b1;
&&&&&&&&&&&
&&&&&&&&&&&&&&&
next_state [S0] = 1'b1;
state [S2]: begin
&&&&&&&&&&&
next_state [S0] = 1'b1;
default: begin
&&&&&&&&&&&
next_state [S0] = 1'b1;
三、设计可综合的状态机的指导原则
因为大多数FPGA内部的触发器数目相当多,又加上独热码状态机的译码逻辑最为简单,所以在设计采用FPGA实现的状态机时,往往采用独热码状态机(即每个状态只有一个寄存器置位的状态机)。
建议采用case语句来建立状态机的模型,因为这些语句表达清晰明了,可以方便地从当前状态分支转向下一个状态并设置输出。不要忘记写上case语句的最后一个分支default,并将状态变量设为'bx或初始化状态,这就等于告知编译器:case语句已经指定了所有的状态。这样综合器就可以删除不需要的译码电路,使生成的电路简洁,并与设计要求一致。
状态机应该有一个异步或同步复位端,以便在通电时将硬件电路复位到有效状态,也可以在操作中将硬件电路复位。
目前大多数综合器往往不支持在一个always块中由多个事件触发的状态机,为了能综合出有效的电路,用Verilog
HDL描述的状态机应明确地由唯一时钟触发。如果设计要求必须有不同的时钟触发的状态机,可以采用以下办法:编写另一个模块,在那个模块中使用另外一个时钟;然后用实例引用的方法在另外一个模块中把它们连接起来。为了使设计比较简单,调试比较容易,应该尽量使这两个状态机的时钟有一定的关系。例如甲模块的时钟是乙模块时钟的同步计数器的输出。
千万不要使用综合工具来设计异步状态。因为目前大多数综合工具在对异步状态机进行逻辑优化时会胡乱地简化逻辑,使综合后的异步状态机不能正常工作。如果一定要设计异步状态机,建议采用电路图输入的方式,而不要直接用Verilog
RTL级别的描述方法通过综合来产生。
HDL中,状态必须明确赋值。通常使用参数(parameter)或宏定义(define)语句加上赋值语句来实现。
四、状态机设计总结
状态机设计的一般步骤为:
(1)逻辑抽象,得出状态转换图。就是把给出的一个实际逻辑关系表示为时序逻辑函数,可以用状态转换表来描述,也可以用状态转换图来描述。
(2)状态化简。如果在状态转换图中出现这样两个状态,它们在相同的输入下转换到同一状态去,并得到一样的输出,则成为等价状态。显然等价状态是重复的,可以合并为一个。电路的状态数越少,存储电路也就越简单。状态化简的目的就在于将等价状态尽可能的合并,以得到最简的状态转换图。
(3)状态分配。状态分配又称为状态编码。通常有很多种编码方式,编码方法选择得当,设计的电路可以简单,反之,选得不好,则设计的电路就会复杂许多。在实际设计时,须综合考虑电路复杂度与电路性能之间的折衷。在触发器资源丰富的FPGA或ASIC设计中,采用独热编码既可以使电路性能得到保证又可充分利用其触发器数量多的优势,也可以采取输出编码的状态指定来简化电路结构,并提高状态机的运行速度。
(4)选定触发器的类型并求出状态方程、驱动方程和输出方程。
(5)按照方程得出逻辑图。用Verilog
HDL来描述有限状态机,可以充分发挥硬件描述语言的抽象建模能力,使用always块语句和case语句及赋值语句即可方便实现。具体的逻辑化简、逻辑电路到触发器映射均可由计算机自动完成。上述步骤中的第(2)步及第(4)、(5)步不再需要很多的人为干预,使电路设计工作得到简化,效率也有很大的提高。
文章说明:本文是笔者学习Verilog时的笔记整理,参考自周景润
姜攀编著的《基于Quartus
II的数字系统Verilog
HDL设计实例详解》(第2版)第238页至第251页和夏宇闻编著的《Verilog数字系统设计教程》(第3版)第166页至第178页,笔者对书中的内容进行了整理和重新编排,并引用了书中的一些理论和观点,特此说明。
作者邮箱:
博客地址:
全文PDF版下载地址:
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 实验四 状态机图模型 的文章

 

随机推荐