目录
前言
3.2.5 Finite State Machines
3.2.5.10 Lemmings 1(Lemmings1)
3.2.5.11 Lemmings 2(Lemmings2)
3.2.5.12 Lemmings 3(Lemmings3)
3.2.5.13 Lemmings 4(Lemmings4)
结语
HDLbits网站链接
今天更新几道题目,这几道题目是旅鼠游戏,这个游戏层层递进,状态机的思想体现地淋漓尽致,希望大家可以做一做,很有趣。
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
这道题目比较容易,旅鼠只有两种状态,向左走或者向右走,如果碰到障碍物,它将切换方向,也就是如果在左侧撞到,它将会朝右走,如果在右侧撞到,将会向左走。题目要求moore型状态机实现,应该没什么难度。
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 = 2'd0, RIGHT = 2'd1, GROUND_LEFT = 2'd2, GROUND_RIGHT = 2'd3;
reg [1:0] current_state;
reg [1:0] next_state;
always@(posedge clk or posedge areset)begin
if(areset)begin
current_state <= LEFT;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
LEFT:begin
next_state = ground ? (bump_left ? RIGHT : LEFT) : GROUND_LEFT;
end
RIGHT:begin
next_state = ground ? (bump_right ? LEFT : RIGHT) : GROUND_RIGHT;
end
GROUND_LEFT:begin
next_state = ground ? LEFT : GROUND_LEFT;
end
GROUND_RIGHT:begin
next_state = ground ? RIGHT : GROUND_RIGHT;
end
default:begin
next_state = LEFT;
end
endcase
end
assign walk_left = (current_state == LEFT);
assign walk_right = (current_state == RIGHT);
assign aaah = (current_state == GROUND_LEFT || current_state == GROUND_RIGHT);
/*
//second way
always@(posedge clk or posedge areset)begin
if(areset)begin
aaah <= 1'b0;
end
else begin
aaah <= ~ground;
end
end
*/
endmodule
这道题目相比第一道题,多加了一个掉落状态,如果ground为1,旅鼠将会发出大叫并且跌落。这里的旅鼠大叫信号(aaah)有两种实现方式,一种就是用状态机输出,另一种是直接将ground取反,但是不建议第二种方式,从作者的题意来看,要根据状态决定输出。
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 = 4'd0, RIGHT = 4'd1, GROUND_LEFT = 4'd2, GROUND_RIGHT = 4'd3;
parameter DIGGING_LEFT = 4'd4, DIGGING_RIGHT = 4'd5;
reg [3:0] current_state;
reg [3:0] next_state;
always@(posedge clk or posedge areset)begin
if(areset)begin
current_state <= LEFT;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
LEFT:begin
next_state = ground ? (dig ? DIGGING_LEFT : (bump_left ? RIGHT : LEFT)) : GROUND_LEFT;
end
RIGHT:begin
next_state = ground ? (dig ? DIGGING_RIGHT : (bump_right ? LEFT : RIGHT)) : GROUND_RIGHT;
end
GROUND_LEFT:begin
next_state = ground ? LEFT : GROUND_LEFT;
end
GROUND_RIGHT:begin
next_state = ground ? RIGHT : GROUND_RIGHT;
end
DIGGING_LEFT:begin
next_state = ground ? DIGGING_LEFT : GROUND_LEFT;
end
DIGGING_RIGHT:begin
next_state = ground ? DIGGING_RIGHT : GROUND_RIGHT;
end
default:begin
next_state = LEFT;
end
endcase
end
assign walk_left = (current_state == LEFT);
assign walk_right = (current_state == RIGHT);
assign digging = (current_state == DIGGING_LEFT || current_state == DIGGING_RIGHT);
assign aaah = (current_state == GROUND_LEFT || current_state == GROUND_RIGHT);
/*
//second way
always@(posedge clk or posedge areset)begin
if(areset)begin
aaah <= 1'b0;
end
else begin
aaah <= ~ground;
end
end
*/
endmodule
这道题目花了我不少时间,主要在于状态的增加我没有理清楚。题目中作者说如果旅鼠在地面上(ground = 1)并且挖掘信号为1,则它可以开始挖洞,一直挖,直到把地都挖穿了(ground = 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 = 4'd0, RIGHT = 4'd1, GROUND_LEFT = 4'd2, GROUND_RIGHT = 4'd3;
parameter DIGGING_LEFT = 4'd4, DIGGING_RIGHT = 4'd5, SPLATTER = 4'd6, AAAH_END = 4'd7;
reg [3:0] current_state;
reg [3:0] next_state;
reg [4:0] counter;
always@(posedge clk or posedge areset)begin
if(areset)begin
counter <= 5'd0;
end
else if(next_state == GROUND_LEFT || next_state == GROUND_RIGHT)begin
counter <= counter + 1'b1;
end
else begin
counter <= 5'd0;
end
end
always@(posedge clk or posedge areset)begin
if(areset)begin
current_state <= LEFT;
end
else begin
current_state <= next_state;
end
end
always@(*)begin
case(current_state)
LEFT:begin
next_state = ground ? (dig ? DIGGING_LEFT : (bump_left ? RIGHT : LEFT)) : GROUND_LEFT;
end
RIGHT:begin
next_state = ground ? (dig ? DIGGING_RIGHT : (bump_right ? LEFT : RIGHT)) : GROUND_RIGHT;
end
GROUND_LEFT:begin
next_state = ground ? LEFT : (counter == 5'd20 ? SPLATTER : GROUND_LEFT);
end
GROUND_RIGHT:begin
next_state = ground ? RIGHT : (counter == 5'd20 ? SPLATTER : GROUND_RIGHT);
end
DIGGING_LEFT:begin
next_state = ground ? DIGGING_LEFT : GROUND_LEFT;
end
DIGGING_RIGHT:begin
next_state = ground ? DIGGING_RIGHT : GROUND_RIGHT;
end
SPLATTER:begin
next_state = ground ? AAAH_END : SPLATTER;
end
AAAH_END:begin
next_state = AAAH_END;
end
default:begin
next_state = LEFT;
end
endcase
end
assign walk_left = (current_state == LEFT);
assign walk_right = (current_state == RIGHT);
assign digging = (current_state == DIGGING_LEFT || current_state == DIGGING_RIGHT);
assign aaah = (current_state == GROUND_LEFT || current_state == GROUND_RIGHT || current_state == SPLATTER);
endmodule
这道题目真是作者又加了一个输出,如果旅鼠跌落的时间太久(大于20个周期),旅鼠就挂了,所以这里需要一个计数器,来计算旅鼠跌落的时间,大家注意,这里的计数器和平常的计数器不太一样,这里计数器的加1条件是当旅鼠开始跌落起计时,如果计数到20个周期,旅鼠就完蛋了...这里的大叫信号只能采用博主答案中的这种方式,没有第二种方式了。建议大家先不要看答案,先自己做一做,这几道题目真是非常有意思。
今天更新这几道旅鼠的题目吧,不知道为啥,每次都把旅鼠打成竹鼠......我也很无奈.....好啦,还是那句老话,如果代码有错误的地方,欢迎大家指出来,我一定尽快改正。
https://hdlbits.01xz.net/wiki/Main_Page