本题是HDLBits进入FSM之后第一道以实际问题为背景的题,我称之为“蓄水池有限状态机”,这道题有两个特点:一是此FSM为多输入多输出,二是对于这个Moore状态机(题目要求是Moore型),题目给出的描述中输出似乎不仅由状态本身决定,还与状态之间的转换顺序有关。
出于对特点的关注,在此将题目中的关键要素与解题思路记录如下,欢迎大家批评指正!
1. 状态机三要素:输入、输出与状态
本题描述的背景是一座由三个水位传感器监测的蓄水池,蓄水池内壁纵向等间距嵌入着3个水位传感器(S3、S2、S1),另有2个注水口,其中一个注水口闸门由3个信号控制(FR1、FR2、FR3),另一个闸门则由1个信号单独控制(ΔFR)。可从题目所给背景信息中抽取出实现状态机所需要素,分别是:
- 输入:每当水位上升没过某一传感器时,该传感器遇水激活(Sensors Asserted),向FSM输入信号1’b1,而当水位下降到该传感器所在水平面之下时,传感器离水失活,向FSM输入信号1’b0。这样的传感器有三个。(注意,激活信号电平题目未作要求,也可以使用1’b0作为激活信号)
- 输出:3个传感器信号进入FSM后,经过一系列状态变化决定4个注水速率控制信号的输出(Flow Rate Inputs to Be Asserted),控制注水口闸门向蓄水池注水,其中三个输出信号称为“常规注水信号”,其与水位、传感器输入的关系在图表中指出,另一个输出信号称为“补充注水信号”,其输出规则是这样定义的——若先前水位高于当前水位(说明水量是降到当前水位的),则开启补充注水;若先前水位低于当前水位(说明水量是涨到当前水位的),则关闭补充注水,只需常规注水即可。(这里可从综合后时序图得知输出信号为高电平则表示注水信号有效)
- 状态:从输入输出可以看出,这些信号都在影响或者受影响于一个事物,那就是蓄水池的水位。输入信号反映当前水位状态,当水位处于S3传感器之上则3个传感器对FSM输入都为1’b1,水位处于S1传感器之下则3个传感器输入都为1’b0;输出信号影响当前水位状态,当水位处于S1传感器之下则四个输出信号都为1’b1(全力注水),当水位处于S3传感器之上则四个输出信号都为1’b0(停止注水)。
2. 输入输出关系:状态是如何变化的
虽然在上文中我们已经搞清楚了状态机的三要素,但是此时还未对状态做具体的界定。我们不妨从初始状态(也就是题目中最后所给的reset复位状态)开始模拟注水,借此捋一下三者的关系,更方便我们构建三段式状态机(这里采用三段式,逻辑更加清晰)中的两段——当前输入决定次态以及当前状态决定输出。
- 初始时,蓄水池默认水位在S1传感器之下,此时三个传感器均未遇水,所以FSM输入{s3, s2, s1} = 3’b000,而依据题目描述,此时四个注水速率控制信号的输出全开,即FSM输出{fr3, fr2, fr1, dfr} = 4’b1111。
- 随着水越注越多,逐渐淹没S1传感器,S1传感器遇水激活,此时FSM输入{s3, s2, s1} = 3’b001,反映水位位于S2与S1传感器之间,基于此,注水速率控制信号也发生相应变化(本节除输出全开和输出全关外暂时不考虑补充注水信号),依照题目图表说明,此时FSM输出{fr3, fr2, fr1} = 4’b011。当然,由于用水需求,水位可能从S2与S1传感器之间下降到S1传感器之下,此时S1传感器离水失活,输入信号变为3’b000,输出信号也变为4’b1111。
还有一种情况是:用水更加厉害,水位一直保持在S1传感器之下没有上来,此时S1传感器未被淹没,输入信号保持3’b000不变,输出信号也就保持4’b1111不变,相当于保持在初始状态,下面状态中的相似情况不再说明。
- 假设由于没有用水需求或者用水速度比不上注水速度,水位上升到了S3与S2传感器之间。此时S2传感器遇水激活,FSM输入变为{s3, s2, s1} = 3’b011,相应地,FSM输出变为{fr3, fr2, fr1} = 4’b001;若是用水量增大,水位又下降到S2传感器与S1传感器之间,S2传感器离水失活,FSM输入变为{s3, s2, s1} = 3’b001,相应地,FSM输出变为{fr3, fr2, fr1} = 4’b011。
- 假设由于没有用水需求或者用水速度比不上注水速度,水位上升到了S3传感器之上。此时S3传感器遇水激活,FSM输入变为3’b111,相应地,输出变为4’b0000,也就是四个注水速率控制信号的输出全关。
基于上述四段状态描述,我们可以大致分出四个状态,即:
- 水位处于S1传感器之下(BelowS1)
- 水位处于S2传感器与S1传感器之间(BetwS21)
- 水位处于S3传感器与S2传感器之间(BetwS32)
- 水位处于S3传感器之上(AboveS3)
3. 另类输出要求:化次序为状态本身
对于dfr这个输出信号需要特殊考虑。对于Moore型状态机,输出应当只取决于当前状态,但是依据题目描述,输出dfr似乎取决于状态出现的次序:如果当前水位是由高水位下降得到的(即由高位状态转换到低位状态),则dfr输出1’b1(说明需要开启补充注水口);如果当前水位是由低水位上涨得到的(即由低位状态转换到高位状态),则dfr输出1’b0(说明需要关闭补充注水口)。
-
有一种方法是通过添加“上一状态”,用于在状态机的输出描述中单独判断dfr的输出情况,可以参见博主“国静德远”的这一篇博文hdlbits之Exams/ece241 2013 q4的FSM问题(如果大家理解了前面的小节,就会发现这位博主所描述的状态机中组合逻辑判断中一些条件是不会发生的)。
-
另一种方法则是将次序转化为状态,即将原本的状态进行细分,给状态加上次序的赘述(如将A状态细分为:A状态<由B状态所得>,A状态<由C状态所得>),将原本的一个状态变为带有次序属性的多个状态,这样,每个输出就由对应的带有次序属性的状态来描述,从而不脱离Moore状态机的定义。这也是本题采用的方法。
由此,上一小节大致划分的4个状态就可以最终细分为如下6个状态:
- 水位处于S1传感器之下(BelowS1)
- 水位处于S2传感器与S1传感器之间<上升到这个水位>(BetwS21_u)
- 水位处于S2传感器与S1传感器之间<下降到这个水位>(BetwS21_d)
- 水位处于S3传感器与S2传感器之间<上升到这个水位>(BetwS32_u)
- 水位处于S3传感器与S2传感器之间<下降到这个水位>(BetwS32_d)
- 水位处于S3传感器之上(AboveS3)
此时,对于每个状态,补充注水信号dfr都有相应的输出情况与之对应,无需专门增加现态与次态之外的“前一状态”对其进行描述。
4. HDL语言描述:经典三段式状态机
经过上述关键要素与解题思路的分析,可以用Verilog HDL将蓄水池有限状态机描述如下:
module top_module (
input clk,
input reset,
input [3:1] s,
output fr3,
output fr2,
output fr1,
output dfr
);
// 状态描述
localparam BelowS1 = 6'b000001, // 采用独热码,以寄存器用量换组合电路用量
BetwS21_u = 6'b000010, // u:表示是升到这个水位的
BetwS21_d = 6'b000100, // d:表示是降到这个水位的
BetwS32_u = 6'b001000,
BetwS32_d = 6'b010000,
AboveS3 = 6'b100000;
// 现态、次态寄存器声明
reg [5:0] state;
reg [5:0] next_state;
// 三段式状态机1:时序逻辑描述状态转换
always @(posedge clk) begin
if(reset)
state <= BelowS1;
else
state <= next_state;
end
// 三段式状态机2:组合逻辑描述判断逻辑
always @(*) begin
case(state)
BelowS1 : next_state = s[1] ? BetwS21_u : BelowS1;
BetwS21_u : next_state = s[2] ? BetwS32_u : (s[1] ? BetwS21_u : BelowS1);
BetwS21_d : next_state = s[2] ? BetwS32_u : (s[1] ? BetwS21_d : BelowS1);
BetwS32_u : next_state = s[3] ? AboveS3 : (s[2] ? BetwS32_u : BetwS21_d);
BetwS32_d : next_state = s[3] ? AboveS3 : (s[2] ? BetwS32_d : BetwS21_d);
AboveS3 : next_state = s[3] ? AboveS3 : BetwS32_d;
endcase
end
// 三段式状态机3:组合逻辑描述输出(时序允许的情况下,使用时序逻辑可降低毛刺影响)
always @(*) begin
case(state)
BelowS1 : {fr3, fr2, fr1, dfr} = 4'b1111;
BetwS21_u : {fr3, fr2, fr1, dfr} = 4'b0110;
BetwS21_d : {fr3, fr2, fr1, dfr} = 4'b0111;
BetwS32_u : {fr3, fr2, fr1, dfr} = 4'b0010;
BetwS32_d : {fr3, fr2, fr1, dfr} = 4'b0011;
AboveS3 : {fr3, fr2, fr1, dfr} = 4'b0000;
default : {fr3, fr2, fr1, dfr} = 4'b1111;
endcase
end
endmodule
5. 总结
这道FSM设计题的亮点在于状态本身——状态的界定以及状态之间的转换。
- 博主“国静德远”所提出的增加“前一状态”的方法更直观、更贴合问题描述,也是一个非常不错的思路,值得学习与记录。
- 我对此题虽然力求描述清楚干练,可言语之间仍显啰嗦……不如直接上代码来得有逻辑且精简。不过希望这不厌其烦的描述能帮助大家最大限度地理解并挖掘这道题的精髓,方便日后一查即懂。