为直观易于理解,状态机采用三段式写法,每个转移条件单独给出。输出需使用逻辑电路, 使用时序电路会比参考波形晚一个时钟周期。
注意:在设计状态机时需要充分考虑转换条件和优先级问题。
链接:https://hdlbits.01xz.net/wiki/Lemmings1
当前进方向发生碰撞时调转方向
Lemmings1 状态转换图
此题较为简单直接根据状态及转化写代码。
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=0, RIGHT=1, ...
reg state, next_state;
parameter S0 = 1, S1 = 0;
wire S02S1;
wire S12S0;
assign S02S1 = bump_left == 1;
assign S12S0 = bump_right == 1;
always @(*) begin
// State transition logic
case(state)
S0:begin
if(S02S1)
next_state = S1;
else
next_state = state;
end
S1:begin
if(S12S0)
next_state = S0;
else
next_state = state;
end
endcase
end
always @(posedge clk, posedge areset) begin
// State flip-flops with asynchronous reset
if(areset)
state <= S0;
else
state <= next_state;
end
assign walk_left = (state == S0);
assign walk_right = (state == S1);
endmodule
增加ground输入和aaah输出,当ground=0(没有地面)时,坠落aaah=1(结束游戏);当地面恢复时,回到坠落前的前进方向。
注意:左右方向转换的条件中ground=1是必要的,即只有在有地面时才可能有方向变换
Lemmings2 状态转换图
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 );
reg [3:0] state_c, state_n;
parameter left = 0, right = 1, leftgr = 2, rightgr = 3;
wire left2right, right2left, leftgr2left, left2leftgr, right2rightgr, rightgr2right;
always@(posedge clk or posedge areset) begin
if(areset)
state_c <= left;
else
state_c <= state_n;
end
always@(*) begin
case (state_c)
left:begin
if(left2right)
state_n = right;
else if(left2leftgr)
state_n = leftgr;
else
state_n = state_c;
end
right:begin
if(right2left)
state_n = left;
else if(right2rightgr)
state_n = rightgr;
else
state_n = state_c;
end
leftgr:begin
if(leftgr2left)
state_n = left;
else
state_n = state_c;
end
rightgr:begin
if(rightgr2right)
state_n = right;
else
state_n = state_c;
end
endcase
end
assign left2right = bump_left && ground && state_c == left;
assign left2leftgr = ground == 0 && state_c == left;
assign right2left = bump_right && ground && state_c == right;
assign right2rightgr = ground == 0 && state_c == right;
assign leftgr2left = ground && state_c == leftgr;
assign rightgr2right = ground && state_c == rightgr;
assign walk_left = state_c == left;
assign walk_right = state_c == right;
assign aaah = (state_c == leftgr) || (state_c == rightgr);
endmodule
增加dig(挖掘)输入和digging(正在挖掘)输出。在行进过程中若出现挖掘条件(dig=1),则进行挖掘,直至没有地面(ground=0)坠落为止;当地面恢复(ground=1)时,回到坠落前的前进方向。
注意:优先级:fall>dig>switch direction,因此在转换时需要按优先级排列。
Lemmings3状态转换图
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_c, state_n;
parameter left=0, right=1, dig_left=2, dig_right=3, fall_left=4, fall_right=5;
wire left2right, left2dig_left, left2fall_left, dig_left2fall_left, fall_left2left;
wire right2left, right2dig_right, right2fall_right, dig_right2fall_right, fall_right2right;
always@(posedge clk or posedge areset) begin
if(areset)
state_c <= left;
else
state_c <= state_n;
end
always@(*) begin
case (state_c)
left:begin
if(left2fall_left) //考虑优先级
state_n = fall_left;
else if(left2dig_left)
state_n = dig_left;
else if(left2right)
state_n = right;
else
state_n = state_c;
end
right:begin
if(right2fall_right)
state_n = fall_right;
else if(right2dig_right)
state_n = dig_right;
else if(right2left)
state_n = left;
else
state_n = state_c;
end
dig_left:begin
if(dig_left2fall_left)
state_n = fall_left;
else
state_n = state_c;
end
dig_right:begin
if(dig_right2fall_right)
state_n = fall_right;
else
state_n = state_c;
end
fall_left:begin
if(fall_left2left)
state_n = left;
else
state_n = state_c;
end
fall_right:begin
if(fall_right2right)
state_n = right;
else
state_n = state_c;
end
default:state_n = left;
endcase
end
assign left2right = bump_left && ground && state_c==left;
assign left2dig_left = dig && ground && state_c==left;
assign left2fall_left = ground==0 && state_c==left;
assign dig_left2fall_left = ground==0 && state_c==dig_left;
assign fall_left2left = ground && state_c==fall_left;
assign right2left = bump_right && ground && state_c==right;
assign right2dig_right = dig && ground && state_c==right;
assign right2fall_right = ground==0 && state_c==right;
assign dig_right2fall_right = ground==0 && state_c==dig_right;
assign fall_right2right = ground && state_c==fall_right;
assign walk_left = state_c==left;
assign walk_right = state_c==right;
assign aaah = (state_c==fall_left) || (state_c==fall_right);
assign digging = (state_c==dig_left) || (state_c==dig_right);
endmodule
增加坠落计时条件,当坠落时开始计时,超过20个周期则游戏结束(所有输出变为0,只有复位时才重新开始游戏)
注意:每个状态转移条件需要较为严格的限制;根据实际参考波形,超过20个周期且重新回到地面(ground=1)时才更新状态
Lemmings4状态转换图
为方便理解,状态转移寄存器和计数寄存器分开写。其中计数cnt根据实际参考波形需要充分的位数,若范围过小可能不符合参考波形。
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_c, state_n;
parameter Left=0, Right=1, Dig_l=2, Dig_r=3, Fall_l=4, Fall_r=5, Overtime=6;
wire Left2Right, Left2Dig_l, Left2Fall_l, Dig_l2Fall_l, Fall_l2Overtime, Fall_l2Left;
wire Right2Left, Right2Dig_r, Right2Fall_r, Dig_r2Fall_r, Fall_r2Overtime, Fall_r2Right;
wire over;
int cnt; //为使cnt位数充分大,定义为int型
wire cnt_add;
always@(posedge clk or posedge areset) begin
if(areset)
state_c <= Left;
else
state_c <= state_n;
end
always@(*) begin
case (state_c)
Left:begin
if(Left2Fall_l)
state_n = Fall_l;
else if(Left2Dig_l)
state_n = Dig_l;
else if(Left2Right)
state_n = Right;
else
state_n = state_c;
end
Right:begin
if(Right2Fall_r)
state_n = Fall_r;
else if(Right2Dig_r)
state_n = Dig_r;
else if(Right2Left)
state_n = Left;
else
state_n = state_c;
end
Dig_l:begin
if(Dig_l2Fall_l)
state_n = Fall_l;
else
state_n = state_c;
end
Dig_r:begin
if(Dig_r2Fall_r)
state_n = Fall_r;
else
state_n = state_c;
end
Fall_l:begin
if(Fall_l2Left)
state_n = Left;
else if(Fall_l2Overtime)
state_n = Overtime;
else
state_n = state_c;
end
Fall_r:begin
if(Fall_r2Right)
state_n = Right;
else if(Fall_r2Overtime)
state_n = Overtime;
else
state_n = state_c;
end
Overtime:begin
state_n = state_c;
end
endcase
end
assign Left2Right = bump_left && ground && state_c==Left;
assign Left2Dig_l = dig && state_c==Left;
assign Left2Fall_l = ground==0 && state_c==Left;
assign Dig_l2Fall_l = ground==0 && state_c==Dig_l;
assign Fall_l2Overtime = over && ground && state_c==Fall_l; //在坠落状态下,地面恢复且超时游戏结束
assign Fall_l2Left = ground && over==0 && state_c==Fall_l; //在坠落状态下,地面恢复且计时未到时才转换到行进方向
assign Right2Left = bump_right && ground && state_c==Right;
assign Right2Dig_r = dig && state_c==Right;
assign Right2Fall_r = ground==0 && state_c==Right;
assign Dig_r2Fall_r = ground==0 && state_c==Dig_r;
assign Fall_r2Overtime = over && ground && state_c==Fall_r;
assign Fall_r2Right = ground && over==0 && state_c==Fall_r;
assign walk_left = state_c==Left;
assign walk_right = state_c==Right;
assign aaah = (state_c==Fall_l) || (state_c==Fall_r);
assign digging = (state_c==Dig_l) || (state_c==Dig_r);
always@(posedge clk or posedge areset) begin
if(areset)
cnt <= 0;
else if(cnt_add)
cnt <= cnt+1;
else
cnt <= 0;
end
assign cnt_add = state_c==Fall_l || state_c==Fall_r; //坠落时开始计时
assign over = (cnt > 20-1)?1:0; //计时超过20个周期
endmodule