FSM onehot
题目要求采用独热码的方式进行编写,其中state[0]和state[9]分别对应于S0和S9。除非另有指定,否则输出为零。并实现状态机的状态转换逻辑和输出逻辑部分,在状态[9:0]中,您将获得当前状态,并且必须产生next_state[9:0]和两个输出。
方法一:
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2
);
parameter S0 = 4'd0;
parameter S1 = 4'd1;
parameter S2 = 4'd2;
parameter S3 = 4'd3;
parameter S4 = 4'd4;
parameter S5 = 4'd5;
parameter S6 = 4'd6;
parameter S7 = 4'd7;
parameter S8 = 4'd8;
parameter S9 = 4'd9;
assign next_state[0] = ~in & (state[S0] | state[S1] | state[S2] | state[S3] | state[S4] | state[S7] | state[S8] | state[S9]);
assign next_state[1] = in & (state[S0] | state[S8] | state[S9]);
assign next_state[2] = in & state[S1];
assign next_state[3] = in & state[S2];
assign next_state[4] = in & state[S3];
assign next_state[5] = in & state[S4];
assign next_state[6] = in & state[S5];
assign next_state[7] = in & (state[S6] | state[S7]);
assign next_state[8] = ~in & state[S5];
assign next_state[9] = ~in & state[S6];
assign out1 = (state[S8] | state[S9]);
assign out2 = (state[S7] | state[S9]);
endmodule
方法二:该方法逻辑正确,但时间上的仿真不能通过。因为题目给出采用 state[0] - state[9]分别对应于S0-S9的方式,无需比对每一位,仅对十位中的某一位进行状态分析,从而简化了表达,可节约时间。
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2
);
//独热码
parameter S0 = 10'b0000000001;
parameter S1 = 10'b0000000010;
parameter S2 = 10'b0000000100;
parameter S3 = 10'b0000001000;
parameter S4 = 10'b0000010000;
parameter S5 = 10'b0000100000;
parameter S6 = 10'b0001000000;
parameter S7 = 10'b0010000000;
parameter S8 = 10'b0100000000;
parameter S9 = 10'b1000000000;
//第二段 组合逻辑进行状态跳转
always @ (*)begin
case(state)
S0:begin
if(in == 1'b0)
next_state = S0;
else
next_state = S1;
end
S1:begin
if(in == 1'b0)
next_state = S0;
else
next_state = S2;
end
S2:begin
if(in == 1'b0)
next_state = S0;
else
next_state = S3;
end
S3:begin
if(in == 1'b0)
next_state = S0;
else
next_state = S4;
end
S4:begin
if(in == 1'b0)
next_state = S0;
else
next_state = S5;
end
S5:begin
if(in == 1'b0)
next_state = S8;
else
next_state = S6;
end
S6:begin
if(in == 1'b0)
next_state = S9;
else
next_state = S7;
end
S7:begin
if(in == 1'b0)
next_state = S0;
else
next_state = S7;
end
S8:begin
if(in == 1'b0)
next_state = S0;
else
next_state = S1;
end
S9: begin
if(in == 1'b0)
next_state = S0;
else
next_state = S1;
end
default:next_state = 10'b0;
endcase
end
//第三段 描述输出
assign out1 = (state == S8 | state == S9) ? 1:0;
assign out2 = (state == S7 |state == S9) ? 1:0;
Fsm ps2
PS/2 鼠标协议发送长度为 3 个字节的消息。但是,在连续字节流中,消息的开始和结束位置并不明显。唯一的指示是,每个三字节消息的第一个字节始终具有 bit[3]=1(但其他两个字节的位 [3] 可能是 1 或 0,具体取决于数据)。
我们想要一个有限的状态机,当给定输入字节流时,它将搜索消息边界。我们将使用的算法是丢弃字节,直到我们看到一个位[3]=1的字节。然后,我们假设这是消息的字节 1,并在收到所有 3 个字节(完成)后发出接收消息的信号。
FSM 应在成功接收到每条消息的第三个字节后立即在周期内发出信号。
题目分析:
该题是对接收的每三个字节产生一个完成信号。字节流是连续的,因此只需要检测边界,即可判断出三个字节的接收,题目中第一个字节更好判断始终为1,而另外两个字节可能为1也可能为0,因此我们就以检测第一个字节作为边界。设置一个等待状态,只要检测到1,那么即可跳转到第一个字节,紧接着依次接收,直到第三个字节完成,否则就一直等待。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done
);
reg [3:0] state;
reg [3:0] next_state;
parameter BYTE_FIRST = 4'b0001; //第1-3个字节
parameter BYTE_SECOND = 4'b0010;
parameter BYTE_THIRD = 4'b0100;
parameter WAIT = 4'b1000; //等待状态
//第一段 用时序逻辑描述状态寄存器
always @ (posedge clk or posedge reset)begin
if(reset)
state <= WAIT;
else
state <= next_state;
end
//第二段 用组合逻辑描述状态转换
always @ (*)begin
case(state)
BYTE_FIRST:begin
next_state = BYTE_SECOND;
end
BYTE_SECOND:begin
next_state = BYTE_THIRD;
end
BYTE_THIRD:begin
if(in[3]==1'b1)
next_state = BYTE_FIRST;
else
next_state = WAIT;
end
WAIT: begin
if(in[3]==1'b1)
next_state = BYTE_FIRST;
else
next_state = WAIT;
end
default:next_state = WAIT;
endcase
end
//第三段 用组合逻辑描述输出
assign done = (state == BYTE_THIRD);
endmodule
Fsm ps2data
根据上题,现在,您已经有了一个状态机,它将识别 PS/2 字节流中的三字节消息,请添加一个数据路径,该数据路径还将在收到数据包时输出 24 位(3 字节)消息(out_bytes[23:16] 是第一个字节,out_bytes[15:8] 是第二个字节,依此类推)。
done信号时,out_bytes都需要有效。您可以在其他时间输出任何内容。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done
);
reg [3:0] state;
reg [3:0] next_state;
reg [23:0] out_bytes_reg;
parameter BYTE_FIRST = 4'b0001; //第1-3个字节
parameter BYTE_SECOND = 4'b0010;
parameter BYTE_THIRD = 4'b0100;
parameter DONE = 4'b1000; //完成状态
//第一段 用时序逻辑描述状态寄存器
always @ (posedge clk or posedge reset)begin
if(reset)
state <= BYTE_FIRST;
else
state <= next_state;
end
//第二段 用组合逻辑描述状态转换
always @ (*)begin
case(state)
BYTE_FIRST:begin
if(in[3]==1'b1)
next_state = BYTE_SECOND;
else
next_state = BYTE_FIRST;
end
BYTE_SECOND:begin
next_state = BYTE_THIRD;
end
BYTE_THIRD:begin
next_state = DONE;
end
DONE: begin
if(in[3]==1'b1)
next_state = BYTE_SECOND;
else
next_state = BYTE_FIRST;
end
default:next_state = BYTE_FIRST;
endcase
end
//第三段 用组合逻辑描述输出
assign done = (state == DONE);
//输出24位数据
always @ (posedge clk)begin
if(next_state == BYTE_SECOND)
out_bytes_reg[23:16] <= in;
else if(next_state == BYTE_THIRD)
out_bytes_reg[15:8] <= in;
else if (next_state == DONE)
out_bytes_reg[7:0] <= in;
else
out_bytes_reg <= 24'd0;
end
assign out_bytes = out_bytes_reg;
endmodule
Fsm serial(不需要将数据输出)
在许多(较旧的)串行通信协议中,每个数据字节都与一个起始位和一个停止位一起发送,以帮助接收方将字节与位流分隔开来。一种常见的方案是使用一个起始位 (0)、8 个数据位和 1 个停止位 (1)。当没有任何内容被传输(空闲)时,该行也位于逻辑 1 处。
设计一个有限的状态机,该状态机将在给定位流时识别何时正确接收字节。它需要识别起始位,等待所有8个数据位,然后验证停止位是否正确。**如果停止位未按预期出现,**则 FSM 必须等到找到停止位后再尝试接收下一个字节。
题目分析:该题有五个状态,空闲状态、开始状态、数据状态、停止状态和等待状态。其中空闲状态的时候根据输入in信号来判断,如果in=0,说明进入开始状态,否则仍然是空闲状态,从开始状态到数据状态,数据状态中需要特别注意,这里其实包含0-7 八位数据的接收,采用计数的方式来进行8个数据位的依次接收,当接收完成后仍然根据in信号,判断是否进入停止状态。如果数据位接收完成,但是输入停止位信号一直没过来,那就进去等待状态。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
parameter IDLE = 5'd00001;
parameter START= 5'd00010;
parameter DATA = 5'd00100;
parameter STOP = 5'd01000;
parameter WAIT = 5'd10000;
reg [4:0] state;
reg [4:0] next_state;
reg [3:0] count;
// 第一段 状态寄存器
always @(posedge clk)begin
if(reset)begin
state <= IDLE;
end
else begin
state <= next_state;
end
end
//第二段 组合逻辑描述状态转移
always @(*)begin
case(state)
IDLE :begin
if(in == 1'b0)
next_state = START;
else
next_state = IDLE;
end
START:begin
next_state = DATA;
end
DATA :begin
if(count == 4'd7)begin //计数8次,说明8个数据接收完成
if(in == 1'b1) //出现停止位
next_state = STOP;
else
next_state = WAIT;
end
else
next_state = DATA;
end
STOP :begin
if(in == 1'b0)
next_state = START;
else
next_state = IDLE;
end
WAIT :begin
if(in == 1'b0)
next_state = WAIT;
else
next_state = IDLE;
end
default:begin
next_state = IDLE;
end
endcase
end
//第三段 组合逻辑描述输出
always @(*)begin
if(reset)
done = 1'b0;
else if(state == STOP)
done = 1'b1;
else
done = 1'b0;
end
//计数器设计
always @(posedge clk)begin
if(reset)
count <= 4'b0;
else if(state == DATA)begin
count <= count + 1'b1;
end
else
count <= 4'b0;
end
endmodule
由此可看到在数据状态比较复杂,需要设计计数器,进行八次的计数,来确定八个数据位的接收,
Fsm serialdata 状态机串行数据
该题是在上题的基础上,将数据进行输出。也就是说该题的数据状态更复杂,不仅需要设计计数器,进行八次的计数,来确定八个数据位的接收,另外数据状态还要进行数据的输出,每一次计数,将一位的输入给数据输出缓存的对应位, par_in[count] <= in; 最后还要将将缓存的数据的八位给到输出。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
);
parameter IDLE = 5'd00001;
parameter START= 5'd00010;
parameter DATA = 5'd00100;
parameter STOP = 5'd01000;
parameter WAIT = 5'd10000;
reg [4:0] state;
reg [4:0] next_state;
reg [3:0] count;
reg [7:0] par_in; //数据位是一位一位给的 共八位
// 第一段 状态寄存器
always @(posedge clk)begin
if(reset)begin
state <= IDLE;
end
else begin
state <= next_state;
end
end
//第二段 组合逻辑描述状态转移
always @(*)begin
case(state)
IDLE :begin
if(in == 1'b0)
next_state = START;
else
next_state = IDLE;
end
START:begin
next_state = DATA;
end
DATA :begin
if(count == 4'd8)begin //计数8次,说明8个数据接收完成
if(in == 1'b1) //出现停止位
next_state = STOP;
else
next_state = WAIT;
end
else
next_state = DATA;
end
STOP :begin
if(in == 1'b0)
next_state = START;
else
next_state = IDLE;
end
WAIT :begin
if(in == 1'b0)
next_state = WAIT;
else
next_state = IDLE;
end
default:begin
next_state = IDLE;
end
endcase
end
//第三段描述输出,可以采用一个always块来包含不同状态下所有的输出情况,这里为了
//对每个输出信号都清楚理解,分成不同三个多个always块来写。
//输出数据接收寄存
always @(posedge clk)begin
if(reset)
par_in[count] <= 1'd0;
else if(next_state == DATA)
par_in[count] <= in;
else
par_in[count] <= 1'd0;
end
//输出数据
always @(posedge clk)begin
if(reset)
out_byte <= 8'd0;
else if(next_state == STOP)
out_byte <= par_in;
else
out_byte <= 8'd0;
end
//done信号
always @(posedge clk)begin
if(reset)begin
done <= 1'd0;
end
else if(next_state == STOP)
done <= 1'd1;
else
done <= 1'd0;
end
//设计计数器
always @(posedge clk)begin
if(reset)begin
count <= 4'd0;
end
else if (next_state == DATA)
count <= count + 1'd1;
else
count <= 4'd0;
end
endmodule
Fsm serialdp(具有奇偶校验的串行接收器)
我们希望向串行接收器添加奇偶校验。奇偶校验在每个数据字节后增加一个额外的位。我们将使用奇数奇偶校验,其中收到的9位中的1的数量必须是奇数。例如,101001011满足奇数奇偶校验(有 5 个 1),但001001011不满足。
更改 FSM 和数据路径以执行奇数奇偶校验。仅当正确接收字节并且其奇偶校验通过时,才可确定done完成信号。另外此 FSM 需要标识起始位,等待所有 9 个(数据和奇偶校验)位,然后验证停止位是否正确。如果停止位未按预期出现,则 FSM 必须等到找到停止位后再尝试接收下一个字节。
为您提供了以下模块,可用于计算输入流的奇偶校验(这是一个具有重置功能的TFF)。预期的用途是,它应该被赋予输入位流,并在适当的时间复位,以便它计算每个字节中的1位数。
module parity (
input clk,
input reset,
input in,
output reg odd
);
always @(posedge clk)
if (reset) odd <= 0;
else if (in) odd <= ~odd;
endmodule
请注意,串行协议首先发送最低有效位,奇偶校验位在 8 个数据位之后发送。(最高位表示奇偶校验位)
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
);
parameter IDLE = 5'd00001;
parameter START= 5'd00010;
parameter DATA = 5'd00100;
parameter STOP = 5'd01000;
parameter WAIT = 5'd10000;
reg [4:0] state;
reg [4:0] next_state;
reg [3:0] count;
reg [7:0] par_in; //数据位是一位一位给的 共八位
wire Isdone;
reg odd_temp;
// 第一段 状态寄存器
always @(posedge clk)begin
if(reset)begin
state <= IDLE;
end
else begin
state <= next_state;
end
end
//第二段 组合逻辑描述状态转移
always @(*)begin
case(state)
IDLE :begin
if(in == 1'b0)
next_state = START;
else
next_state = IDLE;
end
START:begin
next_state = DATA;
end
DATA :begin
if(count == 4'd9)begin //计数8次,说明8个数据接收完成
if(in == 1'b1) //出现停止位
next_state = STOP;
else
next_state = WAIT;
end
else
next_state = DATA;
end
STOP :begin
if(in == 1'b0)
next_state = START;
else
next_state = IDLE;
end
WAIT :begin
if(in == 1'b0)
next_state = WAIT;
else
next_state = IDLE;
end
default:begin
next_state = IDLE;
end
endcase
end
//第三段描述输出,可以采用一个always块来包含不同状态下所有的输出情况,这里为了
//对每个输出信号都清楚理解,分成不同三个多个always块来写。
//输出数据接收寄存
always @(posedge clk)begin
if(reset)
par_in[count] <= 1'd0;
else if(next_state == DATA)
par_in[count] <= in;
else
par_in[count] <= 1'd0;
end
//输出数据
always @(posedge clk)begin
if(reset)
out_byte <= 8'd0;
else if(next_state == STOP)begin
if(odd_temp) //满足奇偶校验将接收的数据给输出
out_byte <= par_in;
else
out_byte <= 8'd0;
end
else
out_byte <= 8'd0;
end
//done信号
always @(posedge clk)begin
if(reset)begin
done <= 1'd0;
end
else if(next_state == STOP)begin //STOP仅能说明接收了九位数据,但是还要进行检测看是否为奇数校验
if(odd_temp)
done <= 1'd1;
else
done <= 1'd0;
end
else
done <= 1'd0;
end
assign Isdone = (next_state == START);
parity u0(clk,Isdone,in,odd_temp);
//设计计数器
always @(posedge clk)begin
if(reset)begin
count <= 4'd0;
end
else if (next_state == DATA)
count <= count + 1'd1;
else
count <= 4'd0;
end
endmodule