See also: Lemmings1, Lemmings2, and Lemmings3.
Although Lemmings can walk, fall, and dig, Lemmings aren't invulnerable. If a Lemming falls for too long then hits the ground, it can splatter. In particular, if a Lemming falls for more than 20 clock cycles then hits the ground, it will splatter and cease walking, falling, or digging (all 4 outputs become 0), forever (Or until the FSM gets reset). There is no upper limit on how far a Lemming can fall before hitting the ground. Lemmings only splatter when hitting the ground; they do not splatter in mid-air.
Extend your finite state machine to model this behaviour.
笔记:用了两个方法,主要区别在于统计掉落时间的计数器部分以及设计的状态数,上述两个不同的设计导致会导致判定落地延迟的不同。
方法一:设计八个状态,当下落时间足够时进入“落地必寄”的状态,落地后进入死亡状态,由于从下落状态至落地必寄状态再至死亡状态会有延迟,因此落地时长的判定设置为19 (个人总觉得这种方法会有问题,但说不上来)
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 );
reg [2:0]state, next_state; //注意状态数和对应位宽是否足够
reg [4:0]F_Time; //记录下落时间
wire Ready_SP; //标记下落时间已足够splater
parameter W_L=3'b000, W_R=3'b001, F_L=3'b010, F_R=3'b011, D_L=3'b100, D_R=3'b101, B_SP=3'b110 ,SP=3'b111 ,ON=1'b1, OFF=1'b0 ;
//下落时间计数器
always @(posedge clk or posedge areset)
begin
if (areset)
F_Time <= 5'd0; //重置时计数器清零
else if(state==F_L|state==F_R)
F_Time <= (F_Time==5'd19 ? 5'd19 : F_Time + 1'd1);
else F_Time <= 5'd0; //中断下落状态计数器清零
end
assign Ready_SP=(F_Time==5'd19 ? 1'b1 : 1'b0); //下落时间足够后触发R_SP信号
always @(*) //8个状态 6个常规状态 W_L W_R F_L F_R D_L D_R 记录落地死亡状态 B_SP 死亡状态 SP
begin
case(state)
W_L : next_state = (ground ? (dig ? D_L : (bump_left ? W_R : W_L)): F_L); //walk状态优先通过ground是否为0信号判定fall
W_R : next_state = (ground ? (dig ? D_R : (bump_right ? W_L : W_R)): F_R); //ground为1则判断dig,最后判断bump
F_L : next_state = (ground ? W_L : (Ready_SP ? B_SP : F_L)); //不考虑落地直接转向,则下落状态要么维持,要么落地转为行走
F_R : next_state = (ground ? W_R : (Ready_SP ? B_SP : F_R)); //下落过程时间若过长,进入B_SP状态
D_L : next_state = (ground ? D_L : F_L); //一旦开挖就挖到挖穿下落为止
D_R : next_state = (ground ? D_R : F_R);
B_SP: next_state = (ground ? SP : B_SP); //下落过程中B_SP保持状态,落地即splater
SP : next_state = SP; //状态锁定,直到reset
endcase
end
always @(posedge clk or posedge areset)
begin
if (areset)
state <= W_L;
else
state <= next_state;
end
assign walk_left = (state==W_L ? ON : OFF);
assign walk_right = (state==W_R ? ON : OFF);
assign aaah = (state==F_L)|(state==F_R)|(state==B_SP); //B_SP状态也要ahhh
assign digging = (state==D_L)|(state==D_R);
endmodule
方法二:去掉方法一中的Ready_Splater状态,改为条件达成的情况下,在时钟沿到来时直接由下落状态进入死亡状态,此时由于少了一个状态转换的周期,所以计数器计数改为20,相比之下个人认为这种方法更符合逻辑。
//lemmings4 改
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 );
reg [2:0]state, next_state; //注意状态数和对应位宽是否足够
reg [4:0]F_Time; //记录下落时间
wire Ready_SP; //代表已经下落了至少20周期
parameter W_L=3'b000, W_R=3'b001, F_L=3'b010, F_R=3'b011, D_L=3'b100, D_R=3'b101, SP=3'b111 ,ON=1'b1, OFF=1'b0 ;
//下落时间计数器 注意:计数器总是慢于state一个周期,即下落时长满了n个周期后,计数器才计到n,而不是在第n个下落周期时段内时,计数器为n
always @(posedge clk or posedge areset)
begin
if (areset)
F_Time <= 5'd0; //重置时计数器清零
else if(state==F_L|state==F_R)
F_Time <= (F_Time==5'd20 ? 5'd20 : F_Time + 1'd1);
else F_Time <= 5'd0; //中断下落状态计数器清零
end
assign Ready_SP=(F_Time==5'd20 ? 1'b1 : 1'b0); //下落时间足够后触发R_SP信号
always @(*) //7个状态 6个常规状态 W_L W_R F_L F_R D_L D_R 死亡状态 SP
begin
case(state)
W_L : next_state = (ground ? (dig ? D_L : (bump_left ? W_R : W_L)): F_L); //walk状态优先通过ground是否为0信号判定fall
W_R : next_state = (ground ? (dig ? D_R : (bump_right ? W_L : W_R)): F_R); //ground为1则判断dig,最后判断bump
F_L : next_state = (ground ? (Ready_SP ? SP : W_L): F_L); //不考虑落地直接转向,则下落状态要么维持,要么落地转为行走
F_R : next_state = (ground ? (Ready_SP ? SP : W_R): F_R); //Ready_SP代表已经下落了至少20个周期,此时ground=0代表此刻下落时长超过了20周期,进入splater状态
D_L : next_state = (ground ? D_L : F_L); //一旦开挖就挖到挖穿下落为止
D_R : next_state = (ground ? D_R : F_R);
SP : next_state = SP;
endcase
end
always @(posedge clk or posedge areset)
begin
if (areset)
state <= W_L;
else
state <= next_state;
end
assign walk_left = (state==W_L ? ON : OFF);
assign walk_right = (state==W_R ? ON : OFF);
assign aaah = (state==F_L)|(state==F_R)|(state==B_SP); //B_SP状态也要ahhh
assign digging = (state==D_L)|(state==D_R);
endmodule