关于有限状态机(FSM)编码的技巧和注意事项
- 格式:doc
- 大小:24.50 KB
- 文档页数:3
1.1概述有限状态机是指输出取决于过去输入部分和当前输入部分的时序逻辑电路。
有限状态机又可以认为是组合逻辑和寄存器逻辑的一种组合。
状态机特别适合描述那些发生有先后顺序或者有逻辑规律的事情,其实这就是状态机的本质。
状态机就是对具有逻辑顺序或时序规律的事件进行描述的一种方法在实际的应用中根据状态机的输出是否与输入条件相关,可将状态机分为两大类,即摩尔(Moore) 型状态机和米勒(Mealy) 型状态机。
Mealy型状态转移图1.2状态机的描述方法状态机的描述方法多种多样,将整个状态机写到1个always 模块里,在该模块中既描述状态转移,又描述状态的输入和输出,这种写法一般被称为一段式FSM 描述方法;还有一种写法是使用两个always 模块,其中一个always 模块采用同步时序的方式描述状态转移,而另一个模块采用组合逻辑的方式判断状态转移条件,描述状态转移规律,这种写法被称为两段式FSM 描述方法;还有一种写法是在两段式描述方法的基础上发展而来的,这种写法使用3 个always模块,一个always 模块采用同步时序的方式描述状态转移,一个采用组合逻辑的方式判断状态转移条件,描述状态转移规律,第三个always 模块使用同步时序电路描述每个状态的输出,这种写法称为三段式写法。
1.3 FSM的状态编码二进制码(Binary)和格雷码(Gray)属于压缩状态编码,这种编码的优点是使用的状态向量最少,但是需要较多的逻辑资源用来状态译码。
二进制码从一个状态转换到相邻状态时,可能有多个比特位发生变化,易产生中间状态转移问题,状态机的速度也要比采用其它编码方式慢。
格雷码两个相邻的码值仅有一位就可区分,这将会减少电路中相邻物理信号线同时变化的情况,因而可以减少电路中的电噪声。
Johnson码也有同样的特点,但是要用较多的位数。
独热码(One-hot)指对任意给定的状态,状态寄存器中只有l位为1,其余位都为0。
matlab有限状态机编程有限状态机(Finite State Machine, FSM)是一种数学模型,用于描述对象在特定状态下对输入的响应。
在实际编程中,有限状态机常常被用来设计和实现程序的控制逻辑,简化复杂系统的行为。
在Matlab中,有限状态机编程可以通过编写状态转换矩阵或状态转换表来实现。
首先,需要定义系统可能的状态以及状态之间的转换条件。
然后,根据输入条件和当前状态,在程序中实现状态的切换和相应的操作。
在编写有限状态机程序时,有几个关键的概念需要了解。
首先是状态(State),即系统可能处于的不同情况或条件。
其次是事件(Event),即触发状态转换的输入条件。
最后是转换(Transition),描述状态之间的变化规则。
举一个简单的例子来说明有限状态机的编程过程。
假设有一个自动售货机系统,有三个状态:待机状态、选择商品状态和出货状态。
当用户投入硬币时,系统从待机状态转换为选择商品状态;当用户选择商品后,系统从选择商品状态转换为出货状态;最后,商品出货后系统回到待机状态。
在Matlab中,可以使用switch-case语句来实现有限状态机的逻辑。
根据当前状态和输入事件,通过switch-case语句确定下一个状态,并执行相应的操作。
除了使用switch-case语句,Matlab还提供了其他工具和函数来简化有限状态机的编程,如Stateflow工具箱。
Stateflow提供了图形化界面,可以直观地设计状态机,并生成对应的Matlab代码。
总的来说,Matlab有限状态机编程是一种简洁而有效的方法,用于实现复杂系统的控制逻辑。
通过合理设计状态、事件和转换规则,可以提高程序的可读性和可维护性。
同时,Matlab提供的工具和函数也能帮助开发人员更快速地实现有限状态机功能。
希望本文能帮助读者更好地理解和应用有限状态机在Matlab中的编程方法。
状态机注意事项
一、确定状态
在创建状态机时,首先需要明确系统或对象的状态。
确定状态的定义和范围,以便于后续的状态编码和转换条件确定。
二、确定事件
事件是导致状态转换的原因。
确定事件是状态机设计的重要环节。
需要明确哪些事件会触发状态转换,以及事件对状态转换的影响。
三、确定转换条件
转换条件是指状态在特定事件触发下从一种状态转换到另一种状态的条件。
确定转换条件需要考虑到所有可能的状态转换情况,并确保条件的正确性和完整性。
四、状态编码
状态编码是将状态机中的状态和事件用编程语言进行表示的方法。
在确定状态编码时,需要考虑编程语言的特性和数据类型,以便于后续的状态转换和事件处理。
五、初始状态
初始状态是状态机的起始点。
在确定初始状态时,需要明确初始状态的设定和进入条件,并确保初始状态的正确性和合理性。
六、状态转换图
状态转换图是描述状态机中状态和事件之间关系的图形表示。
在确定状态转换图时,需要明确各个状态之间的转换关系和转换条件,以便于后续的状态机和程序实现。
七、异常处理
异常处理是指在状态机运行过程中出现异常情况时的处理方法。
在确定异常处理时,需要考虑可能出现的异常情况,并制定相应的处理策略,以便于及时发现和处理异常。
八、测试和验证
测试和验证是确保状态机正确性和稳定性的重要环节。
在测试和验证时,需要选择合适的测试用例和测试方法,并确保测试的全面性和有效性。
同时,需要对测试结果进行分析和评估,以便于发现和修复潜在的问题和错误。
有限状态机FSM(FiniteStateMachine)及实现⽅式介绍⼀、为什么引⼊有限状态机? 最近做⼀个项⽬,项⽬中很多实体(Entity),每个实体都有很多状态(State),各状态会经过不同事件(Event)触发后转换到另⼀个状态。
这些事件包括但不限于:⽤户页⾯点击触发,⽣效时间或失效时间到达,其他依赖实体状态变更等。
在状态变更后还会有⼀系列动作(Action)处理。
⼀旦相互依赖实体或实体本⾝状态增多,状态转换变多,处理这些状态的业务代码也会分散在各处,代码处理很容易漏掉,维护成本很⾼。
所以考虑引⼊有限状态机。
⼆、什么是有限状态机? 有限状态机,也称为FSM(Finite State Machine),其在任意时刻都处于有限状态集合中的某⼀状态。
当其获得⼀个输⼊字符时,将从当前状态转换到另⼀个状态,或者仍然保持在当前状态。
任何⼀个FSM都可以⽤状态转换图来描述,图中的节点表⽰FSM中的⼀个状态,有向(⽅向表⽰从⼀个初态转换到次态)加权(权表⽰事件)边表⽰输⼊字符时状态的变化。
如果图中不存在与当前状态与输⼊字符对应的有向边,则FSM将进⼊“消亡状态(Doom State)”,此后FSM将⼀直保持“消亡状态”。
状态转换图中还有两个特殊状态:状态1称为“起始状态”,表⽰FSM的初始状态。
状态6称为“结束状态”。
在启动⼀个FSM时,⾸先必须将FSM置于“起始状态”,然后触发⼀系列时间,最终,FSM会到达“结束状态”或者“消亡状态”。
图1:状态转换图说明:在通常的FSM模型中,⼀般还存在⼀个“接受状态”,并且FSM可以从“接受状态”转换到另⼀个状态,只有在识别最后⼀个字符后,才会根据最终状态来决定是否接受所输⼊的字符串。
此外,也可以将“其实状态”也作为接受状态,因此空的输⼊序列也是可以接受的。
1. 状态机要素状态机可归纳为4个要素,即现态、条件、动作、次态。
“现态”和“条件”是因,“动作”和“次态”是果。
模糊状态机(FuSM)FSM (有限状态机):涉及到不同状态之间的转换,且系统一次只处于一个当前状态。
FuSM(模糊状态机):有限状态机的一个变种,建立在模糊逻辑的概念之上,一般定义为“被扩展来处理部分真相概念的传统逻辑(bool 逻辑)的超集”。
应该注意,虽然FuSM建立在模糊逻辑概念之上,但不代表是实实在在的模糊系统。
部分真值是一个非常强大的概念。
与常规的FSM不同,FuSM在范围上不具有一般性。
与FSM一样,FuSM跟踪一系列可能的游戏状态。
但不同的是,FSM具有一个单一的当前状态,然后通过转换到一个不同的状态来响应输入事件,而FuSM 可能同时具有多个状态,因此不存在转换。
模糊系统中的每个状态都计算一个"激活水平",该激活水平决定了系统处于任意给定状态的程度,因此,系统的整体行为由当前被激活状态的贡献组合来决定。
FuSM仅仅对那些能够同时处于多个状态并且具有超越简单数字值(如开或关,关闭或打开,生存或死亡)的系统有用,模糊数值用于描述部分开,几乎关闭和未完全死亡等。
另一种对此类数值类型进行量化的方法是使用一个归一系数(0.0 与 1.0之间的数)来表示条件对各个端状态的隶属度(例如:0.0表示完全关闭,1.0表示完全开启),尽管对于FuSM来说归一化并不是必须的。
这是不必记住集合隶属度的所有权限制的一种简单方式,同时也确保了集合隶属度值之间比较的简单性。
关于什么是真正的FuSM,在游戏AI领域还存在一些混淆的看法,因为在同一类别中存在好几个FSM 变种被当作是FuSM。
这些变种包括:1::具有转换优先级的FSM. 在该模型中,必须对每个可用状态的激活水平进行计算(该模型仍然是一个FSM,因此每个状态都有一系列可能的转换);然后那个具有最高激活水平的状态获胜,成为新的当前状态。
这是许多程序员使用模糊度概念来增加其决策状态机的方式,但该系统仍然是一个FSM,并且类似系统输出行的可预测性仅仅比常规FSM稍微小一点。
贴1 状态机的编码
a.状态机的编码。
Biary、gray-code编码使用最少的触发器,较多的组合
逻辑。
而one-hot编码反之。
由于CPLD更多的提供组合逻辑资源,而FPGA更多的提供触发器资源,所以CPLD多使用gray-code,而FPGA多使用one-hot编码。
另一方面,对于小型设计使用gray-code和binary编码更有效,而大型状态机使用one-hot更高效。
b.在代码中添加综合器的综合约束属性或者在图形界面下设置综合约束属性可以比较方便的改变状态的编码。
如VHDL的示例:
Synplicity:
attribute syn_encoding : string;
attribute syn_encoding of <signal_name> : type is "value ";
-- The syn_encoding attribute has 4 values : sequential, onehot, gray and safe.
Exemplar:
-- Declare TYPE_ENCODING_style attribute
-- Not needed if the exemplar_1164 package is used
type encoding_style is (BINARY, ONEHOT, GRAY, RANDOM, AUTO);
attribute TYPE_ENCODING_style : encoding_style;
...
attribute TYPE_ENCODING_style of <typename> : type is ONEHOT; Verilog示例:
Synplicity:
Reg[2:0] state; /* synthesis syn_encoding = "value" */;
// The syn_encoding attribute has 4 values : sequential, onehot, gray and safe.
Exemplar:
Parameter /* exemplar enum <type_name> */ s0 = 0, s1 = 1, s2 = 2, s3 = 3, S4 = 4;
Reg [2:0] /* exemplar enum <type_name> */ present_state, next_state
贴2:状态机的编码风格
a.关于FSM的编码方法。
FSM分两大类:米勒型和摩尔型。
组成要素有输入(包括复位),状态(包括当前状态的操作),状态转移条件,状态的输出条件。
设计FSM的方法和技巧多种多样,但是总结起来有两大类:第一种,将状态转移和状态的操作和判断等写到一个模块(process、block)中。
另一种是将状态转移单独写成一个模块,将状态的操作和判断等写到另一个模块中(在
Verilog代码中,相当于使用两个“always” block)。
其中较好的方式是后者。
其原因如下。
首先FSM和其他设计一样,最好使用同步时序方式设计,好处不再累述。
而状态机实现后,状态转移是用寄存器实现的,是同步时序部分。
状态的转移条件的判断是通过组合逻辑判断实现的,之所以第二种比第一种编码方式合理,就在
于第二种编码将同步时序和组合逻辑分别放到不同的程序块(process,block)中实现。
这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。
b.初始化状态和默认状态。
一个完备的状态机(健壮性强)应该具备初始化状态和默认状态。
当芯片加电或者复位后,状态机应该能够自动将所有判断条件复位,并进入初始化状态。
需要注明的一点是,大多数FPGA有GSR(Global Set/Reset)信号,当FPGA加电后,GSR信号拉高,对所有的寄存器,RAM等单元复位/置位,这是配置于FPGA 的逻辑并未生效,所以不能保证正确的进入初始化状态。
所以使用GSR企图进入FPGA的初始化状态,常常会产生种种不必要的麻烦。
一般的方法是采用异步复位信号,当然也可以使用同步复位,但是要注意同步复位的逻辑设计。
解决这个问题的另一种方法是将默认的初始状态的编码设为全零,这样GSR复位后,状态机自动进入初始状态。
令一方面状态机也应该有一个默认(default)状态,当转移条件不满足,或者状态发生了突变时,要能保证逻辑不会陷入“死循环”。
这是对状态机健壮性的一个重要要求,也就是常说的要具备“自恢复”功能。
对应于编码就是对case,if-else语句要特别注意,要写完备的条件判断语句。
VHDL中,当使用CASE语句的时候,要使用“When Others”建立默认状态。
使用“IF...THEN...ELSE”语句的时候,要用在“ELSE”指定默认状态。
Verilog中,使用“case”语句的时候要用“default”建立默认状态,使用“if...else”语句的注意事项相似。
另外提一个技巧:大多数综合器都支持Verilog编码状态机的完备状态属性--“full case”。
这个属性用于指定将状态机综合成完备的状态,如Synplicity 的综合工具(Synplify/Synplify Pro,Amplify,etc)支持的命令格式如下: case (current_state) // synthesis full_case
2’b00 : next_state <= 2’b01;
2’b01 : next_state <= 2’b11;
2’b11 : next_state <= 2’b00;
//这两段代码等效
case (current_state)
2’b00 : next_state <= 2’b01;
2’b01 : next_state <= 2’b11;
2’b11 : next_state <= 2’b00;
default : next_state <= 2bx;
Synplicity还有一个关于状态机的综合属性,叫“// synthesis
parallel_case”其功能是检查所有的状态是“并行的”(parallel),也就是说在同一时间只有一个状态能够成立。
c.使用完备的“if...else”还有一个重要的好处,就是可以避免生成非目的性的“锁存器”(Latch)。
详见westor的一篇文章“为什么XST与Synplify的综合结果不一样?”
d.状态机的定义可以用parameter定义,但是不推荐使用`define宏定义的方式,因为‘define宏定义在编译时自动替换整个设计中所定义的宏,而parameter 仅仅定义模块内部的参数,定义的参数不会与模块外的其他状态机混淆。