1. 状态机是什么
状态机(有限状态自动机,FSM)是实现电路功能的主要思路之一,也是一种建模手段。状态机既可以用于实际的电路实现,也是拆解设计目标、对宏观目标进行拆解的数学模型。 说人话的话,状态机表现为电路设计、软件设计等等不同的形象,但实际上它是一套分析事情的方法学,适用于电路设计、软件设计甚至现实生活中的任务安排等等。 状态机的构成 广义的状态机由四部分组成: 第一个是 State ,状态。一个状态机至少要包含两个状态。例如自动门的例子,有 open 和 closed 两个状态。 第二个是 Event ,事件。事件就是执行某个操作的触发条件或者口令。对于自动门,“按下开门按钮”就是一个事件。 第三个是 Action ,动作。事件发生以后要执行动作。例如事件是“按开门按钮”,动作是“开门”。编程的时候,一个 Action 一般就对应一个函数。 第四个是 Transition ,变换。也就是从一个状态变化为另一个状态。例如“开门过程”就是一个变换。 对于电路设计而言,状态机一般由状态、转移条件(对应事件)和输出(对应动作)构成,“变换”就是当前状态和下一状态的切换,由于形式基本是一致的,不会单独去提。 电路设计不是必须使用状态机,但状态机是一种简洁、通用的解决方案。有时候之所以需要使用状态机,往往是电路中遇到了组合逻辑或一个时钟周期内难以解决的问题,比如:
- 输出信号仅需要在一种情况下,在某种输入出现时有效,而不是在任何情况下都因为某输入而有效
- 输出所需的数据需要在电路运行时才能根据输入确定下来,或因为访存等存在延迟
- 希望电路重复有限次,需要计数
- 同一模块内实现了几个相关功能,这些功能复用了部分电路,同时又有自己独立的部分,需要进行选择
- 电路除主要功能外,还存在一些较少触发的特殊功能
2. 如何快速理解电路中的状态机
状态机是为了实现电路功能而生的,要快速理解状态机,就要熟悉常见功能的常见电路实现,常见电路实现对应的常见状态机设计。
2.1 一种最常见的电路功能
独家秘笈:“握手电路” 握手电路是各类模块、各种功能、各类通信协议乃至更复杂功能的基础。可以这么说,在基础功能(比如加减乘除、比较、查询等一个clk可以实现的功能)之上,几乎所有涉及控制、交互的复杂功能的实现都离不开握手的思想。握手的概念可以某种状态机结构显式的出现,也可能是通过某些使能信号等隐式存在。 为什么需要握手电路?我们在设计一个较为复杂的电路时,往往是将功能拆成不同的模块,一个模块实现一个功能,这样做“拆分”,利于分步、分层解决问题(反过来说,即使复杂如CPU,你也可以想办法用一个超大模块去实现,但是各个功能点之间的耦合会异常复杂,以至于根本无从下手),也利于团队分工合作。 握手的基本组成是这样的: 图中虚线箭头是信号,实线箭头是状态转移。 一个基本的“握手”是这样的:小红想给小明说话,必须得保证两件事:小明此刻是有空的,同时小红自己想好要说啥了。当且仅当这两个条件同时达成时,小红和小明才有可能开始聊天。在图中,小明的ready可以发生在小红valid之前,也可以在valid之后。。 为啥说这个模型重要呢?看起来这就只是一个最简单的通信模型啊。其实,这里暗含了状态机最典型的特征:在这个例子里,小红的valid可以视为一个状态,即“我要发送的数据已经准备好了”,数据不是立刻需要发出去,而是需要等待小明的ready信号,小红等到这个信号后,才能从准备好数据的状态,转移到发送数据的状态。而对于小明呢?小明从ready进入work也必须等待小红的valid信号。 这一设计有趣的一点是,在小红看来,小明的ready是一个输入信号,但在小明看来,自己的ready是一个状态,自己要做的只是在ready状态下,持续的输出一个ready=1,并在接受到valid=1时进行状态转移到work即可;小红也是在自己的valid状态持续输出valid=1,并等待ready=1时进行状态转移。小红和小明的行为在这种框架下被解耦了,他们可以在自己适当的时候进入自己的ready/valid状态,并在条件成立的情况下从容的进行下一步动作。对于小红和小明两个需要交互模块本身,他们的状态机因此变得简洁、确定。 从小红的时序图上来看,仿佛是输出valid和输入ready同时为1的下一个clk,小红就转移到了下一个状态(小明也是一样的道理)。 这个例子非常形象的说明了状态机的特色:具备等待能力(小红的valid)、每一状态下的输出能力(小明在ready状态持续输出ready=1)以及条件转移能力。 同时,这个模型为所有此类需要等待、根据条件进行转移的模块间交流乃至模块内功能设计奠定了基础。 一个功能模块内部的核心功能往往并不复杂,许多情况下使用一组组合逻辑即可实现。那为什么稍微复杂一点的模块就让人看不懂了呢?首先,套用小红小明的例子,一个模块设计时经常需要使用另一个模块的输出作为输入条件,以实现模块间的功能配合;其次,在一个模块内部,其状态转移的条件往往也需要等待另一个信号,或者例如访存等功能,其所需信息的到来时间由外部决定,不能提前确定。这种功能之间的同步问题提高了模块功能的复杂性。 小红和小明沟通的问题,就给这一类问题提出了良好的解决模板:两个模块之间要协同,那么就需要每一方都至少有两个状态:ready和work。如果有一个模块内部的某个功能的某一步需要等待另一个信号,那么这一个功能点也有可能需要被拆分为两步状态机。
2.2 状态机中几种常见的基本状态
- Idle态:
几乎所有状态机的起点都是idle。电路为啥需要idle态?首先,电路总是需要复位,复位后所有寄存器回到一个默认的状态,状态机也需要一个这样的状态,一般直接以idle作为该默认态;其次,idle态意味着,该电路目前没有正在执行的功能,没有异常,已经就绪并等待任务开始。电路总是应该能够循环执行的,状态机在一次功能执行结束后,要准备执行下一次功能,就必须回到idle。 - Prepare态:
拿小红和小明的问题举例,小红给小明说话作为一个电路功能,在从idle态到valid之间,往往需要特定的功能去准备好自己要说的东西,有时需引入一个“PREP”状态,这一clk的输入激励往往就是使能en和一组配置信号,该状态负责处理指令 - RESP/END态:
一次任务结束后,可能存在不同的执行结果,比如需要重新返回某一步进行循环、需要向其他模块发送结束信号,或者单纯的清理复位一下寄存器,此时往往设计一个END状态或者RESP(响应)状态
2.3 如何分析状态机设计
为了说明这个问题,我们现在假定有一个模块A,已知其功能是接收模块B发送的地址,将某些数据发送给模块C。 假定在不理解设计者意图的情况下,读电路总结模块A的状态机是这样的: 尽管图中没有涉及转移信号,我们依然可以做出以下猜测:
- 存在idle到prep态,那么应该有一组来自模块B的启动信号,使模块A进入工作状态。这个启动过程没有显式的ready握手,那么可能在idle状态下就在向模块B输出ready类型的信号了,可以重点关注idle时有没有给模块B的输出。
- 存在prep态到data态,推测模块A需要根据prep中给出的信息,到其他部分(比如存储器中)提取数据。值得注意的是,在此图中状态从prep直接转移到了data,而没有经过类似于握手的过程,那么perp到data的转移条件可能来自相关存储器的有效信号,或者data状态存在用于获取数据的子状态机(即用两三个状态实现和外部存储的通信,data状态下获得了数据)。
- Data后状态机出现了分支,此时应该考虑是在prep或者data状态时,根据某些信号或者数据,判断了工作模式是stream还是single,应该重点分析这个分支条件的来源。
- 两个send状态相对独立,可以单独分析。Send_stream和packet_done之间存在循环,应该分析一下循环和退出的条件,由此就能猜出send_packet到底在执行什么功能了。还需要关注模块A和要接受数据的模块C之间是怎么互动握手,来确定数据是否发送成功、是否接收成功,涉及到了哪些信号。
在看到状态图后,我们有了以上对于功能的猜想,再去读电路,就是回答这些问题,以及验证我们对于电路运作的猜测。
|