3.2.5.13 Lemmings 4
问题描述
虽然旅鼠可以行走、摔倒和挖掘,但旅鼠并非刀枪不入。如果旅鼠摔倒的时间过长,然后撞到地面,就会飞溅。特别是,如果旅鼠跌落超过 20 个时钟周期后撞到地面,它就会飞溅,并永远停止行走、跌落或挖掘(所有 4 个输出都变为 0)(或直到 FSM 被重置)。旅鼠在落地前的下落距离没有上限。旅鼠只有在落地时才会飞溅,在半空中不会飞溅。
扩展你的有限状态机来模拟这种行为。
分析:相比于lemmings1-lemmings3,本题多出了以下情况
- 需要设置一个计数器count来记录下落周期数
- 在state=fall_l或state=fall_r时,加入count判断条件
- 多出两种状态,splatter表示下落超过20周期但还未碰地,dead表示下落超过20周期且碰地
关于计数器如下(解释代码中为什么将count的初值设为1)
代码:
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=3'd0,right=3'd1,dig_l=3'd2,dig_r=3'd3,fall_l=3'd4,fall_r=3'd5,splatter=3'd6,dead=3'd7;
reg [3:0] state,next_state;
reg [4:0] count; //计数器
// 这里把count的初值设为了1,原因可以看画的图
always @(posedge clk,posedge areset) begin
if(areset)
count<=1;
else if(next_state==fall_l || next_state==fall_r)
count<=count+1;
else
count<=1;
end
always @(*) begin
case(state)
left:begin
if(!ground)
next_state=fall_l; //判断是否落下
else if(dig)
next_state=dig_l; //不落下,判断是否挖掘
else if(bump_left)
next_state=right; //不挖掘,判断是否碰壁
else
next_state=left;
end
right:begin
if(!ground)
next_state=fall_r;
else if(dig)
next_state=dig_r;
else if(bump_right)
next_state=left;
else
next_state=right;
end
dig_l:begin
if(!ground)
next_state=fall_l;
else
next_state=dig_l;
end
dig_r:begin
if(!ground)
next_state=fall_r;
else
next_state=dig_r;
end
fall_l:begin
if(!ground && count<=20)
next_state<=fall_l; //不超过20周期
else if(!ground && count>20)
next_state<=splatter;
else
next_state<=left;
end
fall_r:begin
if(!ground && count<=20)
next_state<=fall_r; //不超过20周期
else if(!ground && count>20)
next_state<=splatter;
else
next_state<=right;
end
splatter:begin
if(ground)
next_state<=dead;
else
next_state<=splatter;
end
dead:begin
next_state<=dead;
end
endcase
end
always @(posedge clk,posedge areset) begin
if(areset)
state<=left;
else
state<=next_state;
end
assign walk_left = (state == left);
assign walk_right = (state == right);
assign aaah = ((state == fall_l)||(state == fall_r)||(state == splatter));
assign digging = ((state == dig_l)||(state == dig_r));
endmodule
3.28补充:计数器的always模块和时序转移部分的always模块是并行的,所以能在count计数改变的同时更新state的状态