15、PS/2数据包解析器
PS/2 鼠标协议发送三个字节长的消息。但是,在连续的字节流中,消息的开始和结束位置并不明显。唯一的指示是每个三字节消息的第一个字节总是有bit[3]=1(但其他两个字节的 bit[3] 可能是 1 或 0,具体取决于数据)。
我们需要一个有限状态机,当给定输入字节流时,它会搜索消息边界。我们将使用的算法是丢弃字节,直到我们看到bit[3]=1 的字节。然后我们假设这是消息的第 1 个字节,并在接收到所有 3 个字节后(完成)发出消息接收信号。
FSM 应该在每个消息的第三个字节被成功接收后立即在周期内发出完成信号。
注:in的第3位为1时,状态机启动,其他两位可能为1或0。此外,这里不允许重叠检测。
代码实现:
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
// State transition logic (combinational)
parameter [1:0] First_state=2'b00, Second_state=2'b01, Third_state=2'b10, Wait_state=2'b11;
reg [1:0] state, next_state;
always @(*) begin
case(state) // State transition logic
First_state:
next_state <= Second_state;
Second_state:
next_state <= Third_state;
Third_state:begin
if(in[3] == 1'b1)
next_state <= First_state;
else
next_state <= Wait_state;
end
Wait_state:begin
if(in[3] == 1'b1)
next_state <= First_state;
else
next_state <= Wait_state;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(reset)
state <= Wait_state;
else
state <= next_state;
end
// Output logic
assign done = (state == Third_state);
endmodule
验证结果:
16、PS/2数据包解析器和数据路径
现在您有一个状态机可以识别 PS/2 字节流中的三字节消息,添加一个数据路径,该数据路径也将在收到数据包时输出 24 位(3 字节)消息 ( out_bytes[23:16]是第一个字节,out_bytes[15:8]是第二个字节,以此类推)。
当done信号为1时,输出24bit的数据,这24bit的数据高8位,中8位,低8位分别从in[3]为1开始计起,依次输出。done信号为0的时候,不关心数据信号。高8位输出仅当下一状态为Second_state才开始,此处可以简化判断逻辑。
代码实现:
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
// State transition logic (combinational)
parameter [1:0] First_state=2'b00, Second_state=2'b01, Third_state=2'b10, Wait_state=2'b11;
reg [1:0] state, next_state;
// FSM from fsm_ps2
always @(*) begin
case(state) // State transition logic
First_state:begin
if(in[3] == 1'b1)
next_state <= Second_state;
else
next_state <= First_state;
end
Second_state:
next_state <= Third_state;
Third_state:
next_state <= Wait_state;
Wait_state:begin
if(in[3] == 1'b1)
next_state <= Second_state;
else
next_state <= First_state;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(reset)
state <= First_state;
else
state <= next_state;
end
// New: Datapath to store incoming bytes.
always @(posedge clk)begin
if(next_state == Second_state)begin
out_bytes[23:16] <= in;
end
else if(next_state == Third_state)begin
out_bytes[15:8] <= in;
end
else if(next_state == Wait_state)begin
out_bytes[7:0] <= in;
end
else begin
out_bytes <= 24'd0;
end
end
// Output logic
assign done = (state == Wait_state);
endmodule
验证结果:
17、串行接收器
在许多(较旧的)串行通信协议中,每个数据字节都与一个起始位和一个停止位一起发送,以帮助接收器从位流中分隔字节。一种常见的方案是使用 1 个起始位 (0)、8 个数据位和 1 个停止位 (1)。当没有传输任何内容(空闲)时,该线路也处于逻辑 1。
设计一个有限状态机,当给定比特流时,它将识别何时正确接收字节。它需要识别起始位,等待所有 8 个数据位,然后验证停止位是否正确。如果停止位没有按预期出现,FSM 必须等待直到找到停止位,然后才能尝试接收下一个字节。
提示:
in信号包含了一个起始位(0),8个数据位和一个停止位(1),开始in为1,也就是idle状态,当in为0时,进入Start状态,然后经过8个周期,如果in为1,则进入Stop状态,接着如果in为0,进入第二轮Start状态,否则进入idle状态。
代码实现:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
// State transition logic (combinational)
parameter [3:0] Start=4'd0,One=4'd1,Two=4'd2,Three=4'd3,Four=4'd4,Five=4'd5;
parameter [3:0] Six=4'd6,Seven=4'd7,Eight=4'd8,Stop=4'd9,idle=4'd10,Wait=4'd11;
reg [3:0] state, next_state;
always @(*) begin
case(state) // State transition logic
Start:
next_state <= One;
One:
next_state <= Two;
Two:
next_state <= Three;
Three:
next_state <= Four;
Four:
next_state <= Five;
Five:
next_state <= Six;
Six:
next_state <= Seven;
Seven:
next_state <= Eight;
Eight:begin
if(in ==1'b1)
next_state <= Stop;
else
next_state <= Wait;
end
Stop:begin
if(in ==1'b1)
next_state <= idle;
else
next_state <= Start;
end
idle:begin
if(in ==1'b1)
next_state <= idle;
else
next_state <= Start;
end
Wait:begin
if(in ==1'b1)
next_state <= idle;
else
next_state <= Wait;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(reset)
state <= idle;
else
state <= next_state;
end
// Output logic
assign done = (state == Stop);
endmodule
验证结果:
18、串行接收器和数据通路
既然您有一个有限状态机,可以识别在串行比特流中正确接收字节的时间,请添加一个数据路径,以输出正确接收的数据字节。out_byte需要在done为1时有效,否则无关紧要。
请注意,串行协议首先发送最低有效位。
提示:本题是上一道题的扩展,不仅需要输出done信号,还需要输出数据。
代码实现:
(1)方法1
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
// State transition logic (combinational)
parameter [3:0] Start=4'd0,One=4'd1,Two=4'd2,Three=4'd3,Four=4'd4,Five=4'd5;
parameter [3:0] Six=4'd6,Seven=4'd7,Eight=4'd8,Stop=4'd9,idle=4'd10,Wait=4'd11;
reg [3:0] state, next_state;
reg [7:0] out_reg;
// Use FSM from Fsm_serial
always @(*) begin
case(state) // State transition logic
Start:begin
next_state <= One;
out_reg[0] <= in;
end
One:begin
next_state <= Two;
out_reg[1] <= in;
end
Two:begin
next_state <= Three;
out_reg[2] <= in;
end
Three:begin
next_state <= Four;
out_reg[3] <= in;
end
Four:begin
next_state <= Five;
out_reg[4] <= in;
end
Five:begin
next_state <= Six;
out_reg[5] <= in;
end
Six:begin
next_state <= Seven;
out_reg[6] <= in;
end
Seven:begin
next_state <= Eight;
out_reg[7] <= in;
end
Eight:begin
if(in ==1'b1)
next_state <= Stop;
else
next_state <= Wait;
end
Stop:begin
if(in ==1'b1)
next_state <= idle;
else
next_state <= Start;
end
idle:begin
if(in ==1'b1)
next_state <= idle;
else
next_state <= Start;
end
Wait:begin
if(in ==1'b1)
next_state <= idle;
else
next_state <= Wait;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(reset)
state <= idle;
else
state <= next_state;
end
// Output logic
assign done = (state == Stop);
assign out_byte = (state == Stop) ? out_reg : 8'd0;
endmodule
(2)方法2
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output done
); //
parameter [2:0] IDLE = 3'd0, START = 3'd1, DATA = 3'd2, STOP = 3'd3, WAIT = 3'd4;
reg [2:0] current_state;
reg [2:0] next_state;
reg [3:0] counter;
reg [7:0] par_in;
// Use FSM from Fsm_serial
always @(*)begin
case(current_state)
IDLE:begin
if(~in)
next_state = START;
else
next_state = IDLE;
end
START:
next_state = DATA;
DATA:begin
if(counter == 4'd8)
next_state = in? STOP:WAIT;
else
next_state = DATA;
end
STOP:
next_state = in? IDLE:START;
WAIT:
next_state = in? IDLE:WAIT;
default:
next_state = IDLE;
endcase
end
always @(posedge clk)begin
if(reset)
current_state <= IDLE;
else
current_state <= next_state;
end
always @(posedge clk)begin
if(reset)begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
else begin
case(next_state)
IDLE:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
START:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
DATA:begin
done <= 1'd0;
out_byte <= 8'd0;
par_in[counter] <= in;
counter <= counter + 1'd1;
end
STOP:begin
done <= 1'd1;
out_byte <= par_in;
counter <= 4'd0;
end
WAIT:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
endcase
end
end
endmodule
验证结果:
19、带奇偶校验的串行接收器
我们想为串行接收器添加奇偶校验。奇偶校验在每个数据字节后增加一位。我们将使用奇校验,其中接收到的 9 位中1的数量必须是奇数。例如,101001011满足奇校验(有 5 个1 s),但001001011不满足。
更改 FSM 和数据路径以执行奇校验。仅当正确接收到一个字节并且其奇偶校验通过时才断言完成信号。像串行接收器 FSM,这个 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
); //
// Modify FSM and datapath from Fsm_serialdata
parameter [2:0] IDLE = 3'd0, START = 3'd1, DATA = 3'd2, STOP = 3'd3, WAIT = 3'd4;
reg [2:0] current_state;
reg [2:0] next_state;
reg [3:0] counter;
reg [8:0] data_in;
reg odd_temp;
wire Isdone;
// Use FSM from Fsm_serial
always @(*)begin
case(current_state)
IDLE:begin
if(~in)
next_state = START;
else
next_state = IDLE;
end
START:
next_state = DATA;
DATA:begin
if(counter == 4'd9)
next_state = in? STOP:WAIT;
else
next_state = DATA;
end
STOP:
next_state = in? IDLE:START;
WAIT:
next_state = in? IDLE:WAIT;
default:
next_state = IDLE;
endcase
end
always @(posedge clk)begin
if(reset)
current_state <= IDLE;
else
current_state <= next_state;
end
always @(posedge clk)begin
if(reset)begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
else begin
case(next_state)
IDLE:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
START:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
DATA:begin
done <= 1'd0;
out_byte <= 8'd0;
data_in[counter] <= in;
counter <= counter + 1'd1;
end
STOP:begin
done <= odd_temp ? 1'd1 : 1'd0;
out_byte <= odd_temp ? data_in[7:0] : 8'd0;
counter <= 4'd0;
end
WAIT:begin
done <= 1'd0;
out_byte <= 8'd0;
counter <= 4'd0;
end
endcase
end
end
// New: Add parity checking.
assign Isdone = (next_state == START);
parity u0(clk,Isdone,in,odd_temp);
endmodule
验证结果:
20、序列识别
Fsm hdlc
同步帧检测涉及对数据的连续位流进行解码,以寻找指示帧(数据包)开始和结束的位模式。 6个连续的1(即01111110)是表示帧边界的“标志”。 为了避免数据流意外包含“标志”,发送方必须在接收方必须检测并丢弃的每5个连续的1秒后插入一个零。 如果连续7个或更多1,我们还需要发出错误信号。
可以通过状态机来识别下面三种序列:
0111110:表示5个1后面的0bit需被忽略;
01111110:表示一帧的开始或结束;
01111111…:错误
当状态机被复位时,它应当表现为之前的输入为0;
下面是三种波形示例:
提示:
代码实现:
module top_module(
input clk,
input reset, // Synchronous reset
input in,
output disc,
output flag,
output err);
parameter [3:0] NONE=4'd0, ONE=4'd1, TWO=4'd2, THREE=4'd3, FOUR=4'd4;
parameter [3:0] FIVE=4'd5, SIX=4'd6, ERROR=4'd7, DISCARD=4'd8, FLAG=4'd9;
reg [3:0] state, next_state;
always @(*) begin
case(state) // State transition logic
NONE:begin
if( in == 1'b1 )
next_state <= ONE;
else
next_state <= NONE;
end
ONE:begin
if( in == 1'b1 )
next_state <= TWO;
else
next_state <= NONE;
end
TWO:begin
if( in == 1'b1 )
next_state <= THREE;
else
next_state <= NONE;
end
THREE:begin
if( in == 1'b1 )
next_state <= FOUR;
else
next_state <= NONE;
end
FOUR:begin
if( in == 1'b1 )
next_state <= FIVE;
else
next_state <= NONE;
end
FIVE:begin
if( in == 1'b1 )
next_state <= SIX;
else
next_state <= DISCARD;
end
SIX:begin
if( in == 1'b1 )
next_state <= ERROR;
else
next_state <= FLAG;
end
ERROR:begin
if( in == 1'b1 )
next_state <= ERROR;
else
next_state <= NONE;
end
DISCARD:begin
if( in == 1'b1 )
next_state <= ONE;
else
next_state <= NONE;
end
FLAG:begin
if( in == 1'b1 )
next_state <= ONE;
else
next_state <= NONE;
end
endcase
end
always @(posedge clk) begin
if(reset)
state <= NONE;
else
state <= next_state;// State flip-flops with asynchronous reset
end
// Output logic
assign disc = (state == DISCARD);
assign flag = (state == FLAG);
assign err = (state == ERROR);
endmodule
验证结果: