仓库源文

.. Kenneth Lee 版权所有 2020

:Authors: Kenneth Lee :Version: 1.0

“硬件状态机”


状态机以前介绍过::doc:状态机方法 。今天和几个芯片的同事讨论他们的状态机设计 ,他们非要说“我们硬件的状态机”和“你们软件的状态机”不一样。

我气死了,状态机他么还分软件的和硬件的?我要针对这个问题建一个逻辑,顺便深入探 讨一下“状态机”的本质是什么。

我们做芯片的同事经常画这样的时序图:

    .. figure:: _static/时序图1.jpg

你觉得这个东西很特别,是因为你觉得你整个行为是时钟驱动的,C在一个cycle发了一个 消息给D,下个cycle必然可以发d,所以这个图里面的信号发送的序列就是唯一的。

但这个根本算不上什么特别的,比如我们认为这些A,B,C,D就是4台服务器,互相之间建 立可靠连接,消息没有传到会重传,我同样可以认为D收到c后,肯定能收到d。这个在逻辑 上不是一样的?

状态机是架构设计,它根本不管你是什么鬼电信号,光信号,消息包还是函数调用。它关 心的是模块之间的“承诺”。就上面这幅图,B收到了一个f,如果当初他没有收到过b,你这 个B还能正常工作吗?还是会乱发其他消息,或者什么消息都不收?

你这些东西都没有推演过,我怎么觉得这个B怼在我的系统中是靠谱的呢?

这才是状态机要面对的问题。上面这个B,我们在逻辑上认为,它只会收到a,f,h。它在这 幅时序图中的呈现的状态机应该是这样的:

    .. figure:: _static/状态机1.jpg

B预期你先发个a给它,它才能那个收f,然后才能收h,不是这样还行不行,你时序图里没 说。

所以状态机推演是什么意思呢?当然不是只画上面这幅图。状态机推演是我想要告诉你, 如果不在你设想的这种顺序的时候,你的行为是不是都可以维持在可以控制的状态下,也 就是说,你的B在任何一种状态下,如果遇到可能面对的一种情形,是不是都可以表现正常 。如果考虑这些要素,这个状态机可能应该是这样的:

    .. figure:: _static/状态机2.jpg

你看,这才是完整的状态机推演。我们是完全把你看作是个黑盒,也不管其他沟通对象怎 么走,只保证你这个黑盒呈现出来是靠谱的,这个角度来看状态机推演的。状态机是个可 能性的“全集”。

只要你的通讯协议需要“一步步”完成,我们基本都会有状态机分析的需要,因为我们要处 理异常。除非你没有这样的一步步,任何一个东西进来,都和前面做了什么没有关系,直 接就可以响应,否则你不可能不需要状态机分析的。

这甚至和你硬件里面有多少个状态寄存器没有关系,你的寄存器如果不影响这个对外反映 的行为,我都可以当作看不见。我只关心你的“对外反应”(所反映出来的状态),其他内 部的“状态”和我没关系。决定你有状态机的是你的对外行为,不是你里面有没有状态寄存 器。

对同一个硬件,状态机的实际维护可以是多份的,比如前面这个B的状态机,可能你有个 session/transaction的概念,每个session都有自己的步骤。这个状态机就属于这个 session。但这个一点不影响我们基于每个独立的session进行状态机推演。

状态机也不考虑“如果”的,这也是时序图不能取代的地方,一种时序只是一种可能的序列 ,状态机是系统中某个对象的全部可能性,没有“如果这样,如果那样”这种说法的。比如 在上面这个S1的状态上,收到f的时候,有两种可能,一种是f包含“成功”的消息,一种是f 包含“失败”的消息。在状态机上这是两个不同的“激发”,它是这样建模的:

    .. figure:: _static/状态机3.jpg

所以,别老来给我强调你的硬件有什么特别的地方,越是硬件对状态机的要求就越高。因 为如果ABCD是台服务器,它挂死了,我还能登录上去,人工修改它的状态,你硬件在总线 上挂个Master,它自己堵死了没有响应,你从哪里reset它的状态啊?

特别是,如果某个硬件已经推演过了,接口上进行过这样的状态机推演了,确定每种情况 都可以正常工作了,你再开一个口子,可以给它插入新的事件,那原来的推演是可以被破 坏的。比如还是上面这个状态机。我认为到得了S1,send_b这个动作可以保证某个端口肯 定是打开了的,这时收到f可以放心直接给某个端口发消息,结果你丫做了一个消息i,也 可以切换到S1,但就是端口没有开,这个系统就可能出问题了。

时序图是无限的,你根本画不完,你画多少我都不敢信任你的模块。所以你要做状态机建 模。我其他和你配合的模块才知道我的异常流程怎么设计。