前言
今天刷完状态机的2/3,以下是书写的代码。
题库
1:Lemmings2:
除了向左和向右走之外,如果下面的地面消失,旅鼠还会摔倒(大概会“啊啊!”)。
除了左右行走和撞到时改变方向外,当地面=0时,旅鼠还会摔倒并说“啊!当地面重新出现(地面=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 = 4'b0001,
RIGHT = 4'b0010,
FALL_L = 4'b0100,
FALL_R = 4'b1000;
reg [3:0] state, next_state;
wire [1:0] bump;
assign bump = {bump_left,bump_right};
always @(posedge clk, posedge areset) begin
if(areset)
state <= LEFT;
else
state <= next_state;
end
always @(*) begin
case(state)
LEFT:begin
if(ground == 1'b0) begin
next_state = FALL_L;
end
else if((bump == 2'b10)||(bump == 2'b11))begin
next_state = RIGHT ;
end
else
next_state = LEFT ;
end
RIGHT:begin
if(ground == 1'b0) begin
next_state = FALL_R;
end
else if((bump == 2'b01)||(bump == 2'b11))begin
next_state = LEFT ;
end
else begin
next_state = RIGHT ;
end
end
FALL_L:begin
if(ground == 1'b0)
next_state = FALL_L;
else
next_state = LEFT;
end
FALL_R:begin
if(ground == 1'b0)
next_state = FALL_R;
else
next_state = RIGHT;
end
endcase
end
always @(posedge clk, posedge areset) begin
if(areset)
aaah <= 1'b0;
else
aaah <= ~ground;
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
endmodule
2:Lemmings3:
除了走路和跌倒之外,旅鼠有时还可以被告知做一些有用的事情,比如挖掘(当 dig=1 时它开始挖掘)。如果旅鼠目前在地面上行走(地面=1且没有坠落),则可以挖掘,并将继续挖掘,直到到达另一侧(地面=0)。在这一点上,由于没有地面,它会掉下来(啊!),然后在它再次落地后继续向原来的方向行走。与跌倒一样,在挖掘时被撞到是没有效果的,在跌倒或没有地面时被告知挖掘是被忽略的。
(换句话说,行走的旅鼠可以跌倒、挖掘或改变方向。如果满足这些条件中的多个条件,则 fall 的优先级高于 dig,而 dig 的优先级高于切换方向的优先级。
扩展有限状态机以对此行为进行建模。
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 = 6'b000001,
RIGHT = 6'b000010,
FALL_L = 6'b000100,
FALL_R = 6'b001000,
DIG_L = 6'b010000,
DIG_R = 6'b100000;
reg [5:0] state, next_state;
wire [1:0] bump;
assign bump = {bump_left,bump_right};
always @(posedge clk, posedge areset) begin
if(areset)
state <= LEFT;
else
state <= next_state;
end
always @(*) begin
case(state)
LEFT:begin
if(ground == 1'b0) begin
next_state = FALL_L;
end
else if(dig == 1'b1)begin
next_state = DIG_L;
end
else if((bump == 2'b10)||(bump == 2'b11))begin
next_state = RIGHT ;
end
else
next_state = LEFT ;
end
RIGHT:begin
if(ground == 1'b0) begin
next_state = FALL_R;
end
else if(dig == 1'b1)begin
next_state = DIG_R;
end
else if((bump == 2'b01)||(bump == 2'b11))begin
next_state = LEFT ;
end
else begin
next_state = RIGHT ;
end
end
FALL_L:begin
if(ground == 1'b0)
next_state = FALL_L;
else
next_state = LEFT;
end
FALL_R:begin
if(ground == 1'b0)
next_state = FALL_R;
else
next_state = RIGHT;
end
DIG_L:begin
if(ground == 1'b0)
next_state = FALL_L;
else
next_state = DIG_L;
end
DIG_R:begin
if(ground == 1'b0)
next_state = FALL_R;
else
next_state = DIG_R;
end
endcase
end
always @(posedge clk, posedge areset) begin
if(areset)
aaah <= 1'b0;
else
aaah <= ~ground;
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
assign digging = (state == DIG_R)||(state == DIG_L);
endmodule
3:Lemmings4:
虽然旅鼠可以走路、跌倒和挖掘,但旅鼠并不是刀枪不入的。如果旅鼠跌倒时间过长然后撞到地面,它可能会飞溅。特别是,如果旅鼠跌倒超过 20 个时钟周期然后撞到地面,它会飞溅并停止行走、跌落或挖掘(所有 4 个输出变为 0),永远(或直到 FSM 被重置)。旅鼠在落地之前可以跌落多远没有上限。旅鼠只有在落地时才会飞溅;它们不会在半空中飞溅。
扩展有限状态机以对此行为进行建模。
跌倒 20 个周期是可以生存的:
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 = 7'b0000001,
RIGHT = 7'b0000010,
FALL_L = 7'b0000100,
FALL_R = 7'b0001000,
DIG_L = 7'b0010000,
DIG_R = 7'b0100000,
DEAD = 7'b1000000,
DEAD_MAX = 32'd20;
reg [5:0] state, next_state;
reg [31:0] cnt;
wire [1:0] bump;
assign bump = {bump_left,bump_right};
always @(posedge clk, posedge areset) begin
if(areset)
state <= LEFT;
else
state <= next_state;
end
always @(*) begin
case(state)
LEFT:begin
if(ground == 1'b0) begin
next_state = FALL_L;
end
else if(dig == 1'b1)begin
next_state = DIG_L;
end
else if((bump == 2'b10)||(bump == 2'b11))begin
next_state = RIGHT ;
end
else
next_state = LEFT ;
end
RIGHT:begin
if(ground == 1'b0) begin
next_state = FALL_R;
end
else if(dig == 1'b1)begin
next_state = DIG_R;
end
else if((bump == 2'b01)||(bump == 2'b11))begin
next_state = LEFT ;
end
else begin
next_state = RIGHT ;
end
end
FALL_L:begin
if(ground == 1'b0)
next_state = FALL_L;
else if(cnt >= DEAD_MAX)
next_state = DEAD;
else
next_state = LEFT;
end
FALL_R:begin
if(ground == 1'b0)
next_state = FALL_R;
else if(cnt >= DEAD_MAX)
next_state = DEAD;
else
next_state = RIGHT;
end
DIG_L:begin
if(ground == 1'b0)
next_state = FALL_L;
else if(cnt >= DEAD_MAX)
next_state = DEAD;
else
next_state = DIG_L;
end
DIG_R:begin
if(ground == 1'b0)
next_state = FALL_R;
else
next_state = DIG_R;
end
DEAD:begin
next_state <= DEAD;
end
endcase
end
//计时器计跌倒的时间
always @(posedge clk, posedge areset) begin
if(areset)
cnt <= 5'b0;
else if((state == FALL_R) || (state == FALL_L))
cnt <= cnt + 1'b1;
else
cnt <= 5'b0;
end
// Output logic
assign walk_left = (state == LEFT)&&(state!=DEAD);
assign walk_right = (state == RIGHT)&&(state!=DEAD);
assign digging = ((state == DIG_R)||(state == DIG_L))&&(state!=DEAD);
assign aaah = ((state == FALL_L)||(state == FALL_R))&&(state!=DEAD);
endmodule
注意:本题调试过程中遇到了一个非常严重的问题,计数器一开始我只设置为[4:0] cnt,一共只有5位,后来一直报错。修改成32位之后,就没有报错了。
4:Fsm onehot:
给定以下具有 1 个输入和 2 个输出的状态机:
假设这个状态机使用单次编码,其中状态[0]到状态[9]分别对应状态 S0 到 S9。除非另有说明,否则输出均为零。
实现状态机的状态转换逻辑和输出逻辑部分(但不包括状态触发器)。在 state[9:0] 中给出当前状态,必须产生 next_state[9:0]和两个输出。假设采用单次热编码,通过检查得出逻辑方程。(测试平台将使用非单次热输入进行测试,以确保您没有试图做更复杂的事情)。
Solution:
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2);
assign next_state[0] = (state[9:7]|state[4:0])&&(~in);
assign next_state[1] = (state[9:8]|state[0])&∈
assign next_state[2] = state[1]&∈
assign next_state[3] = state[2]&∈
assign next_state[4] = state[3]&∈
assign next_state[5] = state[4]&∈
assign next_state[6] = state[5]&∈
assign next_state[7] = state[7:6]&∈
assign next_state[8] = state[5]&&(~in);
assign next_state[9] = state[6]&&(~in);
assign out1 = (state[9]|state[8]);
assign out2 = (state[9]|state[7]);
endmodule
5:Fsm ps2:
PS/2 鼠标协议发送的信息长度为三个字节。然而,在连续的字节流中,信息的起点和终点并不明显。唯一的提示是,每个三字节报文的第一个字节总是位[3]=1(但其他两个字节的位[3]可能是 1 或 0,这取决于数据)。
我们需要一个有限状态机,在给定输入字节流时搜索报文边界。我们将使用的算法是丢弃字节,直到我们看到一个 bit[3]=1 的字节。然后,我们假设这是信息的第 1 个字节,并在收到全部 3 个字节后发出收到信息的信号(完成)。
FSM 应在成功接收到每条信息的第三个字节后立即发出完成信号。
Solution:
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
parameter B1 = 4'b0001,//等待1个周期(即byte1)
B2 = 4'b0010,//等待1个周期(即byte2)
B3 = 4'b0100,//检查byte3(in[3])是否为1
WAIT = 4'b1000;
reg [3:0] state,next_state;
// State transition logic (combinational)
always @(*) begin
case(state)
WAIT:begin
if(in[3])
next_state =B1;
else
next_state =WAIT;
end
B1:
next_state =B2;
B2:
next_state =B3;
B3: begin
if(in[3])
next_state =B1;
else
next_state =WAIT;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk or posedge reset) begin
if(reset)
state <= WAIT;
else
state <= next_state;
end
// Output logic
assign done = (state == B3);
endmodule
6:Fsm ps2data:
现在有了一个可以识别 PS/2 字节流中 3 字节信息的状态机,再添加一个数据通路,每当接收到一个数据包时,它也会输出 24 位(3 字节)信息(out_bytes[23:16] 是第一个字节,out_bytes[15:8] 是第二个字节,等等)。
每当 done 信号断言时,out_bytes 必须有效。在其他时间,您可以输出任何内容(即 "无所谓")。
Solution:
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
parameter B1 = 4'b0001,//等待1个周期(即byte1)
B2 = 4'b0010,//等待1个周期(即byte2)
B3 = 4'b0100,//检查byte3(in[3])是否为1
WAIT = 4'b1000;
reg [3:0] state,next_state;
// State transition logic (combinational)
always @(*) begin
case(state)
WAIT:begin
if(in[3])
next_state =B1;
else
next_state =WAIT;
end
B1:
next_state =B2;
B2:
next_state =B3;
B3: begin
if(in[3])
next_state =B1;
else
next_state =WAIT;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk or posedge reset) begin
if(reset)
state <= WAIT;
else
state <= next_state;
end
// Output logic
assign done = (state == B3);
always @(posedge clk) begin
if(reset)
out_bytes <= 24'b0;
else
out_bytes <= {out_bytes[23:0],in};//只是添加了一个移位寄存器器
end
endmodule
7:Fsm serial:
在许多(较早的)串行通信协议中,每个数据字节都与一个起始位和一个停止位一起发送,以帮助接收器从比特流中划分字节。一种常见的方案是使用 1 个起始位(0)、8 个数据位和 1 个停止位(1)。当没有任何传输时(空闲),线路也处于逻辑 1。
设计一个有限状态机,当给定一个比特流时,它能识别字节何时被正确接收。它需要识别起始位,等待所有 8 个数据位,然后验证停止位是否正确。如果停止位没有按预期出现,有限状态机必须等待,直到找到停止位后再尝试接收下一个字节。
Solution:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
parameter IDLE = 4'b0001,
START = 4'b0010,
STOP = 4'b0100,
WAIT = 4'b1000,
cnt_max = 4'd8 ;
reg [3:0] state,next_state;
reg [3:0] cnt;
//先赋值
always @(posedge clk) begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
//计数器在起始状态开始计时+1,一直从0记到8结束.
//在等待状态不变,停止和初始状态(IDLE)为0。
always @(posedge clk) begin
if(reset)
cnt <= 4'd0;
else if(state == START)
cnt <= cnt + 1'b1;
else if(state == WAIT)
cnt <= cnt;
else
cnt <= 4'd0;
end
//根据状态转移图写代码
always @(*) begin
case(state)
IDLE:begin
if(!in)
next_state = START;
else
next_state = state;
end
START:begin
if(cnt == cnt_max) begin
if(in)
next_state = STOP;
else
next_state = WAIT;
end
else
next_state = START;
end
STOP:begin
if(!in)
next_state = START;
else
next_state = IDLE;
end
WAIT:begin
if(in)
next_state = IDLE;
else
next_state = WAIT;
end
endcase
end
assign done = (state == STOP);
endmodule
8:Fsm serialdata:
现在您有了一个有限状态机,可以识别串行比特流中的字节何时被正确接收,然后添加一个数据通路,输出正确接收到的数据字节。
请注意,串行协议会先发送最小有效位。
Solution:
与上面的题目基本相同,只是多了一个out_byte的移位寄存器赋值语句。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
parameter IDLE = 4'b0001,
START = 4'b0010,
STOP = 4'b0100,
WAIT = 4'b1000,
cnt_max = 4'd8 ;
reg [3:0] state,next_state;
reg [3:0] cnt;
//先赋值
always @(posedge clk) begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
//计数器在起始状态开始计时+1,一直从0记到8结束.
//在等待状态不变,停止和初始状态(IDLE)为0。
always @(posedge clk) begin
if(reset)
cnt <= 4'd0;
else if(state == START)
cnt <= cnt + 1'b1;
else if(state == WAIT)
cnt <= cnt;
else
cnt <= 4'd0;
end
//根据状态转移图写代码
always @(*) begin
case(state)
IDLE:begin
if(!in)
next_state = START;
else
next_state = state;
end
START:begin
if(cnt == cnt_max) begin
if(in)
next_state = STOP;
else
next_state = WAIT;
end
else
next_state = START;
end
STOP:begin
if(!in)
next_state = START;
else
next_state = IDLE;
end
WAIT:begin
if(in)
next_state = IDLE;
else
next_state = WAIT;
end
endcase
end
assign done = (state == STOP);
always @(posedge clk) begin
if(reset)
out_byte <= 4'd0;
else if((state == START)&&(cnt < cnt_max)) //处于起始状态且计数器在0~7的时候,给寄存器分别进行赋值。
out_byte[cnt] <= in;
else
out_byte <= out_byte;
end
endmodule
9:Fsm serialdp:
我们希望在串行接收器中加入奇偶校验。奇偶校验在每个数据字节后增加一个额外位。我们将使用奇偶校验,即接收到的 9 个比特中 1 的个数必须是奇数。例如,101001011 满足奇偶校验(有 5 个 1),但 001001011 不满足奇偶校验。
更改您的 FSM 和数据路径,以执行奇奇偶校验检查。只有在正确接收到字节且奇偶校验通过时,才赋值完成信号。与串行接收器 FSM 一样,该 FSM 需要识别起始位,等待所有 9 位(数据和奇偶校验位),然后验证停止位是否正确。如果停止位没有按预期出现,FSM 必须等待找到停止位后再尝试接收下一个字节。
以下模块可用于计算输入流的奇偶校验(这是一个带复位的 TFF)。它的预期用途是给定输入比特流,并在适当的时候复位,以便计算每个字节中 1 位的数量。
Solution:
这道题和上道题(第八题)几乎一样,只是多一个奇偶校验位。要改的地方有三处:1:cnt_max由8改为9,因为多出来一位给奇偶校验位。2:调用parity模块,生成奇偶校验位odd。3:done信号在奇偶校验位正确之后,才能输出done信号(即odd为0)。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
parameter IDLE = 4'b0001,
START = 4'b0010,
STOP = 4'b0100,
WAIT = 4'b1000,
cnt_max = 4'd9 ;
reg [3:0] state,next_state;
reg [3:0] cnt;
wire odd;
//先赋值
always @(posedge clk) begin
if(reset)
state <= IDLE;
else
state <= next_state;
end
//计数器在起始状态开始计时+1,一直从0记到8结束.
//在等待状态不变,停止和初始状态(IDLE)为0。
always @(posedge clk) begin
if(reset)
cnt <= 4'd0;
else if(state == START)
cnt <= cnt + 1'b1;
else if(state == WAIT)
cnt <= cnt;
else
cnt <= 4'd0;
end
//根据状态转移图写代码
always @(*) begin
case(state)
IDLE:begin
if(!in)
next_state = START;
else
next_state = state;
end
START:begin
if(cnt == cnt_max) begin
if(in)
next_state = STOP;
else
next_state = WAIT;
end
else
next_state = START;
end
STOP:begin
if(!in)
next_state = START;
else
next_state = IDLE;
end
WAIT:begin
if(in)
next_state = IDLE;
else
next_state = WAIT;
end
endcase
end
assign done = ((state == STOP)&&(odd == 1'b0));//奇偶校验为odd为0,才可以进入done状态。
always @(posedge clk) begin
if(reset)
out_byte <= 4'd0;
else if((state == START)&&(cnt < cnt_max)) //处于起始状态且计数器在0~7的时候,给寄存器分别进行赋值。
out_byte[cnt] <= in;
else
out_byte <= out_byte;
end
parity u_parity(.clk(clk) ,
.in(in) ,
.reset(state != START) ,
.odd(odd)
);
endmodule
10:Fsm hdlc:
同步 HDLC 成帧包括解码连续比特数据流,以寻找表示帧(数据包)开始和结束的比特模式。正好看到 6 个连续的 1(即 01111110)就是表示帧边界的 "标志"。为避免数据流中意外包含 "标志",发送方在每 5 个连续 1 后插入一个 0,接收方必须检测并丢弃该 0。如果出现 7 个或更多连续的 1,我们还需要发出错误信号。
创建一个有限状态机来识别这三个序列:
0111110:发出需要丢弃一个比特的信号(丢弃)。
01111110:标志帧的开始/结束(标志)。
01111111...: 错误(7 个或更多 1)(err)。
当 FSM 复位时,它应处于前一个输入为 0 的状态。
下面是一些说明所需操作的示例序列。
Solution:
module top_module(
input clk,
input reset, // Synchronous reset
input in,
output disc,
output flag,
output err);
parameter NONE = 4'd0,ONE = 4'd1,TWO = 4'd2;
parameter THREE = 4'd3,FOUR = 4'd4,FIVE = 4'd5;
parameter SIX = 4'd6,ERROR = 4'd7;
parameter DISC = 4'd8,FLAG = 4'd9;
reg [3:0] current_state,next_state;
always @(*) begin
case(current_state)
NONE:begin
next_state = in ? ONE : NONE;
end
ONE:begin
next_state = in ? TWO : NONE;
end
TWO:begin
next_state = in ? THREE : NONE;
end
THREE:begin
next_state = in ? FOUR : NONE;
end
FOUR:begin
next_state = in ? FIVE : NONE;
end
FIVE:begin
next_state = in ? SIX : DISC;
end
SIX:begin
next_state = in ? ERROR : FLAG;
end
DISC:begin
next_state = in ? ONE : NONE;
end
FLAG:begin
next_state = in ? ONE : NONE;
end
ERROR:begin
next_state = in ? ERROR : NONE;
end
endcase
end
always @(posedge clk) begin
if(reset)begin
current_state <= NONE;
end
else begin
current_state <= next_state;
end
end
always @(posedge clk) begin
if(reset)begin
disc <= 1'd0;
flag <= 1'd0;
err <= 1'd0;
end
else begin
case(next_state)
DISC:begin
disc <= 1'd1;
flag <= 1'd0;
err <= 1'd0;
end
FLAG:begin
disc <= 1'd0;
flag <= 1'd1;
err <= 1'd0;
end
ERROR:begin
disc <= 1'd0;
flag <= 1'd0;
err <= 1'd1;
end
default:begin
disc <= 1'd0;
flag <= 1'd0;
err <= 1'd0;
end
endcase
end
end
endmodule
参考内容
HDLBits刷题网站:HDLBits (01xz.net)
标签:begin,字节,HDLBits,next,状态机,state,答案,output,input From: https://blog.csdn.net/weixin_58164636/article/details/140600906