HDLBits答案记录【FSM-水库供水实践题】(仅用于自己答案记录)
这里虽然是三段式状态机,但是和二段式状态机(输出判断的是state)更像。三段式状态机的输出更偏向以时序(输出判断的是next_state)。(个人理解)
Desin a Moore FSM
题目:一个大型水库为多个用户供水。为了保持足够高的水位,每隔5英寸垂直放置三个传感器。
当水位高于最高传感器(S3)时,输入流速应为零。
当水位低于最低传感器(S1)时,流速应为最大值(标称流量阀和补充流量阀均打开)。
水位位于上部和下部传感器之间时的流速由两个因素决定:
水位和最后一个传感器变化之前的水位。每个水位都有一个与其相关的标称流速,如下表所示。
如果传感器变化表明之前的液位【低于】当前液位,则应出现【标称流量】。
如果之前的水位(state)高于当前水位(next_state),则应通过打开【补充流量阀】(由△FR控制)来增加流速。
绘制水库控制器的摩尔模型状态图。清楚地指示每个状态的所有状态转换和输出。FSM的输入为S1,S2和S3;输出为FR1, FR2,FR3和△FR。
还包括主动高同步重置,将状态机重置为相当于水位长时间处于低位时的状态(未断言传感器,且所有四个输出均已断言)。
module top_module (
input clk,
input reset,
input [3:1] s,
output fr3,
output fr2,
output fr1,
output dfr
);
parameter L1=4'b0001,//below s1
S1_2=4'b0010,//between s1~s2
S2_3=4'b0100,//between s2~s3
H3=4'b1000;//above s3
reg [3:0]state,next_state;
reg [2:0]fr;
assign {fr3,fr2,fr1}=fr;
always@(posedge clk)begin
if(reset)begin
state<=L1;
end
else begin
state<=next_state;
end
end
always@(*)begin
case(s)
3'b000:next_state=L1;
3'b001:next_state=S1_2;
3'b011:next_state=S2_3;
3'b111:next_state=H3;
default:next_state=L1;
endcase
end
always@(posedge clk)begin
if(reset)begin
fr<=3'b111;
end else begin
case(next_state)
L1:fr<=3'b111;
S1_2:fr<=3'b011;
S2_3:fr<=3'b001;
H3:fr<=3'b000;
default:fr<=3'b111;
endcase
end
end
always@(posedge clk)begin
if(reset)begin
dfr<=1'b1;
end else begin
if(state>next_state)begin
dfr<=1'b1;
end
else if(state<next_state)begin
dfr<=1'b0;
end
else
dfr<=dfr;
end
end
endmodule
Lemming1
旅鼠游戏涉及大脑相当简单的小动物。非常简单,我们将使用有限状态机对其进行建模。
在旅鼠的2D世界中,旅鼠可以处于两种状态之一:向左行走或向右行走。如果遇到障碍物,它会切换方向。特别是,如果一只旅鼠在左边被撞,它会向右行走。如果它在右边颠簸,它会向左走。如果同时在两侧碰撞,它仍然会切换方向。
实现一个具有两个状态、两个输入和一个输出的摩尔状态机来模拟这种行为。
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
output walk_left,
output walk_right); //
parameter LEFT=1'b0, RIGHT=1'b1;
reg state, next_state;
always@(posedge clk or posedge areset)begin
if(areset)begin
state <= LEFT;
end
else begin
state <= next_state;
end
end
always @(*) begin
case(state)
LEFT:begin
if(bump_left)begin
next_state = RIGHT;
end
else begin
next_state = LEFT;
end
end
RIGHT:begin
if(bump_right)begin
next_state = LEFT;
end
else begin
next_state = RIGHT;
end
end
endcase
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
endmodule
Lemming2
除了左右行走外,旅鼠还会摔倒(大概还会“啊!”)
如果地面消失在他们下面。除了在颠簸时左右行走和改变方向外,
当地面=0时,旅鼠还会摔倒并说“啊!”。
当地面再次出现(地面=1)时,旅鼠将继续沿着与坠落前相同的方向行走。坠落时被撞击不会影响行走方向,
在地面消失(但尚未坠落)的同一周期内被撞击,或在地面仍在坠落时重新出现时,也不会影响步行方向。
建立一个有限状态机来模拟这种行为。
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
output walk_left,
output walk_right,
output aaah );
parameter LEFT=4'b0001,RIGHT=4'b0010,DOWN_LEFT=4'b0100,DOWN_RIGHT=4'b1000;
reg [3:0]state,next_state;
always@(posedge clk,posedge areset)begin
if(areset)
state<=LEFT;
else
state<=next_state;
end
always@(*)begin
case(state)
LEFT:next_state=ground?(bump_left?RIGHT:LEFT):DOWN_LEFT;
RIGHT:next_state=ground?(bump_right?LEFT:RIGHT):DOWN_RIGHT;
DOWN_LEFT:next_state=ground?LEFT:DOWN_LEFT;
DOWN_RIGHT:next_state=ground?RIGHT:DOWN_RIGHT;
default:next_state=LEFT;
endcase
end
assign walk_left=(state==LEFT);
assign walk_right=(state==RIGHT);
assign aaah=(state==DOWN_LEFT||state==DOWN_RIGHT
endmodule
Lemmings 3
除了行走和摔倒之外,有时还可以告诉旅鼠做一些有用的事情,比如挖掘(当挖掘=1时开始挖掘)。如果旅鼠当前正在地面上行走(地面=1且未坠落),【它可以挖掘,并将继续挖掘,直到到达另一侧(地面=0)】。到那时,因为没有地面,它就会坠落(啊!),然后,一旦它再次触地,继续沿着原来的方向行走。与摔倒一样,在挖掘时被撞倒没有任何影响,当摔倒或没有地面时被告知要挖掘则被忽略。
(换句话说,行走的旅鼠可以下降、挖掘或切换方向。如果满足其中一个以上的条件,下降的优先级高于挖掘,而挖掘的优先级高于切换方向。)
扩展有限状态机来模拟这种行为。
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter LEFT=6'b000001,//左走状态
RIGHT=6'b000010,//右走状态
DOWN_LEFT=6'b000100,//坠落后左状态
DOWN_RIGHT=6'b001000,//坠落后右状态
TODIG_LEFT=6'b010000,//挖掘后左状态
TODIG_RIGHT=6'b100000;//挖掘后右状态
reg [5:0]state,next_state;
//第一进程(状态转移)
always@(posedge clk,posedge areset)begin
if(areset)
state<=LEFT;
else
state<=next_state;
end
//第二进程(状态转移条件的判断)
always@(*)begin
case(state)
LEFT:next_state=ground?(dig?TODIG_LEFT:(bump_left?RIGHT:LEFT)):DOWN_LEFT;
RIGHT:next_state=ground?(dig?TODIG_RIGHT:(bump_right?LEFT:RIGHT)):DOWN_RIGHT;
//当ground==1时候,此刻不需要对挖掘进行判断了,因为挖掘条件是(地面=1且未坠落)
DOWN_LEFT:next_state=ground?(LEFT):DOWN_LEFT;
DOWN_RIGHT:next_state=ground?(RIGHT):DOWN_RIGHT;
//开始挖掘后会一直挖掘,直到ground=0
TODIG_LEFT:next_state=ground?TODIG_LEFT:DOWN_LEFT;
TODIG_RIGHT:next_state=ground?TODIG_RIGHT:DOWN_RIGHT;
default:next_state=LEFT;
endcase
end
//第三
assign walk_left=(state==LEFT);
assign walk_right=(state==RIGHT);
assign aaah=(state==DOWN_LEFT|state==DOWN_RIGHT);
assign digging=(state==TODIG_LEFT|state==TODIG_RIGHT);
endmodule
Lemmings
虽然旅鼠可以行走、摔倒和挖掘,但旅鼠并非无懈可击。如果旅鼠摔倒太久,然后撞到地面,它可能会飞溅。特别是,如果一只旅鼠坠落超过20个时钟周期,然后撞到地面,它将飞溅并停止行走、坠落或挖掘(所有4个输出都变为0),直到永远(或直到FSM重置)。旅鼠在落地前能落多远没有上限。旅鼠只有在触地时才会飞溅;它们不会在半空中飞溅。
扩展有限状态机来模拟这种行为。
坠落20个周期可存活:
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter LEFT=7'b0000001,
RIGHT=7'b0000010,
DOWM_LEFT=7'b0000100,
DOWM_RIGHT=7'b0001000,
DIG_LEFT=7'b0010000,
DIG_RIGHT=7'b0100000,
SPLAT=7'b1000000;
reg [6:0]state,next_state;
reg [6:0]count;
always@(posedge clk,posedge areset)begin
if(areset)
count<=7'd0;
else if((next_state==DOWM_LEFT)||(next_state==DOWM_RIGHT))
count<=count+1'b1;
else
count<=7'd0;
end
always@(posedge clk,posedge areset)begin
if(areset)
state<=LEFT;
else
state<=next_state;
end
always@(*)begin
case(state)
LEFT:next_state=ground?(dig?DIG_LEFT:(bump_left?RIGHT:LEFT)):DOWM_LEFT;
RIGHT:next_state=ground?(dig?DIG_RIGHT:(bump_right?LEFT:RIGHT)):DOWM_RIGHT;
DOWM_LEFT:next_state=ground?((count>7'd20)?SPLAT:LEFT):DOWM_LEFT;
DOWM_RIGHT:next_state=ground?((count>7'd20)?SPLAT:RIGHT):DOWM_RIGHT;
DIG_LEFT:next_state=ground?DIG_LEFT:DOWM_LEFT;
DIG_RIGHT:next_state=ground?DIG_RIGHT:DOWM_RIGHT;
SPLAT:next_state=SPLAT;
default:next_state=LEFT;
endcase
end
assign walk_left=(state==LEFT);
assign walk_right=(state==RIGHT);
assign aaah=(state==DOWM_RIGHT||state==DOWM_LEFT);
assign digging=(state==DIG_RIGHT||state==DIG_LEFT);
endmodule