目录
1 旅鼠游戏
Lemmings游戏涉及具有简单大脑的生物。 如此简单以至于我们将使用有限状态机对其进行建模。
在Lemmings的2D世界中,Lemmings可以处于以下两种状态之一:向左行走或向右行走。 如果碰到障碍物,它将切换方向。特别是,如果Lemmings在左侧发生碰撞,它将向右行走。 如果它撞到右边,它将向左走。 如果同时在两侧碰撞,它将仍然会切换方向。
1.1 Lemmings1
用两个状态,两个输入和一个输出对此行为进行建模,以实现Moore型状态机。
提示:
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;
always @(*) begin
// State transition logic
case (state)
LEFT: next_state = (bump_left) ? RIGHT : LEFT;
RIGHT:next_state = (bump_right) ?LEFT : RIGHT;
endcase
end
always @(posedge clk, posedge areset) begin
// State flip-flops with asynchronous reset
if(areset)
state <= LEFT;
else
state <= next_state;
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
endmodule
1.2 Lemmings2
除了左右走动之外,如果地面在它们下面消失,它们将掉落(可能会喊“aaah!”)。
除了在碰撞时左右走动和改变方向外,当ground= 0时,旅鼠也会掉下来并说“ aaah!”。 当地面重新出现时(ground= 1),旅鼠将恢复与跌倒之前相同的方向行走。 跌倒时被撞击不会影响步行方向,并且与地面消失(但尚未坠落)的周期相同,或者当地面重新出现时仍在坠落,也不会影响步行方向。
构建对此行为进行建模的有限状态机。
solution:
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=0,RIGHT=1,FALL_L=2,FALL_R=3;
reg [1:0] state,next;
always @(*) begin
case (state)
//先判断ground是否为1,再看方向bump
LEFT :next = ground ? (bump_left ? RIGHT : LEFT) : FALL_L;
RIGHT :next = ground ? (bump_right ? LEFT : RIGHT) : FALL_R;
FALL_L:next = ground ? LEFT : FALL_L;
FALL_R:next = ground ? RIGHT: FALL_R;
endcase
end
always @(posedge clk or posedge areset) begin
if (areset)
state <= LEFT;
else
state <= next;
end
assign walk_left = (state==LEFT);
assign walk_right= (state==RIGHT);
assign aaah = (state==FALL_L | state==FALL_R);
endmodule
1.3 Lemmings3
除了走路和摔倒之外,有时还可以要求Lemmings做一些有用的事情,例如挖掘(当dig = 1时就开始挖掘)。
如果一只Lemming目前正在地面上行走(ground= 1且没有掉落),它可以进行挖掘,并将继续挖掘直到到达另一侧(ground= 0)。
此时,由于没有地面,它将坠落(aaah!),然后一旦再次撞击地面,便继续沿其原始方向行走。 与掉落一样,在挖掘过程中发生碰撞无效,而在掉落或没有地面时被告知挖掘则被忽略。
(换句话说,行走的旅鼠会掉落,挖掘或切换方向。如果满足以上条件之一,则下降优先级高于挖掘,挖掘优先级高于切换方向。)
提示:
solution:
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=0,RIGHT=1,FALL_L=2,FALL_R=3,DIG_L=4,DIG_R=5;
reg [2:0] state,next;
always @(*) begin
case (state)
LEFT : next = ground ? (dig ? DIG_L : (bump_left ? RIGHT : LEFT)): FALL_L;
RIGHT: next = ground ? (dig ? DIG_R : (bump_right ? LEFT : RIGHT)): FALL_R;
FALL_L:next = ground ? LEFT : FALL_L;
FALL_R:next = ground ? RIGHT: FALL_R;
DIG_L: next = ground ? DIG_L : FALL_L;
DIG_R: next = ground ? DIG_R : FALL_R;
endcase
end
always @(posedge clk or posedge areset) begin
if (areset)
state <= LEFT;
else
state <= next;
end
assign walk_left = (state==LEFT);
assign walk_right= (state==RIGHT);
assign aaah = (state==FALL_L | state==FALL_R);
assign digging = (state==DIG_L | state==DIG_R);
endmodule
1.4 Lemmings4
尽管Lemmings可以行走,掉落和挖土,但Lemmings并不是无敌的。 如果Lemmings掉落的时间过长,然后撞到地面,它可能会飞溅。 特别是,如果Lemming掉落超过20个时钟周期然后撞到地面,它将永久飞溅(并且直到4个输出变为0)(或直到FSM复位),然后停止行走,掉落或挖掘(全部4个输出变为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=0,RIGHT=1,FALL_L=2,FALL_R=3,DIG_L=4,DIG_R=5,SPLAT=6;
reg [2:0] state,next;
reg [31:0] cnt; //一定要加长度
always @(posedge clk or posedge areset) begin
if (areset) begin
state <= LEFT;
cnt <= 0;
end
else if(state == FALL_L || state == FALL_R) begin
state <= next;
cnt <= cnt + 1;
end
else begin
state <= next;
cnt <= 0;
end
end
always @(*) begin
case (state)
LEFT : next = ground ? (dig ? DIG_L : (bump_left ? RIGHT : LEFT)): FALL_L;
RIGHT: next = ground ? (dig ? DIG_R : (bump_right ? LEFT : RIGHT)): FALL_R;
FALL_L:next = ground ? ((cnt>19) ? SPLAT : LEFT) : FALL_L;
FALL_R:next = ground ? ((cnt>19) ? SPLAT : RIGHT) : FALL_R;
DIG_L: next = ground ? DIG_L : FALL_L;
DIG_R: next = ground ? DIG_R : FALL_R;
SPLAT: next = SPLAT;
endcase
end
assign walk_left = (state==LEFT);
assign walk_right= (state==RIGHT);
assign aaah = (state==FALL_L || state==FALL_R);
assign digging = (state==DIG_L || state==DIG_R);
endmodule
2 onehot FSM
给定以下具有1个输入和2个输出的状态机:
假设此状态机使用独热编码,其中state[0]至state[9]分别对应于状态S0至S9。 除非另有说明,否则输出为零。
实现状态机的状态转换逻辑和输出逻辑部分(但不实现状态触发器)。
你将给定state[9:0]中的当前状态,并且必须产生next_state [9:0]和两个输出。通过假设独热编码,通过检验推导出逻辑方程 。(测试台将使用非独热码输入进行测试,以确保你没有尝试做更复杂的事情)。
提示:可以通过查看状态转换图的边缘来导出单热状态转换逻辑的逻辑方程式。
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2);
assign next_state[0] = ~in & (state[0]|state[1]|state[2]|state[3]|state[4]|state[7]|state[8]|state[9]);
assign next_state[1] = in & (state[0]|state[8]|state[9]);
assign next_state[2] = in & state[1];
assign next_state[3] = in & state[2];
assign next_state[4] = in & state[3];
assign next_state[5] = in & state[4];
assign next_state[6] = in & state[5];
assign next_state[7] = in & (state[6]|state[7]);
assign next_state[8] = ~in & state[5];
assign next_state[9] = ~in & state[6];
assign out1 = state[8]|state[9];
assign out2 = state[7]|state[9];
endmodule
3 PS/2 packet parser
3.1 PS/2 packet parser
PS / 2鼠标协议发送三字节长的消息。 但是,在连续的字节流中,消息的开始和结束位置并不明显。 唯一的指示是,每个三字节消息的第一个字节始终具有bit[3] = 1。
(但其他两个字节的bit [3]取决于数据,可能是1或0)
我们需要一个有限状态机,当给定输入字节流时它将搜索消息边界。 我们将使用的算法是丢弃字节,直到看到bit [3] = 1的字节为止。 然后,我们假定这是消息的字节1,并且一旦接收到所有3个字节(完成),就发出接收消息的信号。
在成功接收到每个消息的第三个字节之后,FSM应该立即在周期中发出完成信号。
在无错误条件下,每三个字节形成一条消息:
出现错误时,搜索字节1:
请注意,这与1xx序列识别器不同。 此处不允许重叠序列:
提示:
尽管in [7:0]是一个字节,但FSM只有一个输入:in [3]。
这里需要〜4个状态。三种状态可能不起作用,因为其中一种状态需要断言完成,并且对于每个收到的消息,仅在一个周期内断言完成。
断言(assertion)是编程中的一种常用手段,在通常情况下,断言就是将一个返回值总是真(或者我们需要是真)的判别式放在语句中,用以排除在设计逻辑上不应该出现的情况。
举个例子:我们都知道除数不能为0,那么就可以对除数使用断言,以使程序在除数为0的情况下产生异常退出。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
parameter DONE=0,BYTE1=1,BYTE2=2,BYTE3=3;
reg [1:0] state,next;
// State transition logic (combinational)
always @(*) begin
case (state)
DONE : next = in[3] ? BYTE2 : BYTE1;
BYTE1: next = in[3] ? BYTE2 : BYTE1;
BYTE2: next = BYTE3;
BYTE3: next = DONE;
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if (reset) begin
state <= BYTE1;
end
else begin
state <= next;
end
end
// Output logic
assign done = (state==DONE);
endmodule
3.2 PS/2 packet parser and datapath
现在已经有了一个状态机,该状态机将标识PS / 2字节流中的三字节消息,添加一个数据路径,该数据路径将在接收到数据包时也输出24位(3字节)消息(out_bytes [23:16] 是第一个字节,out_bytes [15:8]是第二个字节,依此类推)。
断言完成信号时,out_bytes必须有效。 你可能会在其他时间输出任何内容(即,don’t-care)。
solution
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
// FSM from fsm_ps2
parameter DONE=0,BYTE1=1,BYTE2=2,BYTE3=3;
reg [1:0] state,next;
// State transition logic (combinational)
always @(*) begin
case (state)
DONE : next = in[3] ? BYTE2 : BYTE1;
BYTE1: next = in[3] ? BYTE2 : BYTE1;
BYTE2: next = BYTE3;
BYTE3: next = DONE;
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if (reset) begin
state <= BYTE1;
end
else begin
state <= next;
end
end
// Output logic
assign done = (state==DONE);
// New: Datapath to store incoming bytes.
/*always @(posedge clk) begin
if (reset)
out_bytes = 0;
else begin
case (state)
DONE : out_bytes = {3{in[7:0]}};
BYTE1: out_bytes[23:16] = in[3] ? in[7:0] : out_bytes[23:16];
BYTE2: out_bytes[15:8] = in[7:0];
BYTE3: out_bytes[7:0] = in[7:0];
default out_bytes = {3{in[7:0]}};
endcase
end
end*/
reg [23:0] data;
always @(posedge clk) begin
if (reset) begin
data <= 24'd0;
end
else begin
data <= {data[15:0],in};
end
end
assign out_bytes = (done) ? data : 24'd0;
endmodule