PS/2鼠标协议发送三字节长的消息。然而,在连续字节流中,消息的开始和结束位置并不明显。唯一的迹象是,每个三字节消息的第一个字节始终具有bit[3]=1(但其他两个字节的bit[3]可能为1或0,具体取决于数据)。
我们需要一个有限状态机,当给定输入字节流时,它将搜索消息边界。我们将使用的算法是丢弃字节,直到我们看到bit[3]=1的字节。然后,我们假设这是消息的字节1,并在收到所有3个字节后发出消息接收信号(完成)。
FSM应在成功接收每个消息的第三个字节后立即在循环中发出信号。
尽管in[7:0]中是一个字节,但FSM只有一个输入:in[3]中。
你需要~4个状态。三种状态可能不起作用,因为其中一种状态需要断言done,并且每个接收到的消息只在一个周期内断言done。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
parameter BYTE1=4'b0001,BYTE2=4'b0010,BYTE3=4'b0100,DONE=4'b1000;
reg [4:0]state,next_state;
// State transition logic (combinational)
always@(*)begin
case(state)
BYTE1:begin
if(in[3]==1'b1)
next_state= BYTE2;
else
next_state=BYTE1;
end
BYTE2:next_state=BYTE3;
BYTE3:next_state=DONE;
DONE:begin
if(in[3]==1'b1)
next_state= BYTE2;
else
next_state=BYTE1;
end
default:next_state=BYTE1;
endcase
end
// State flip-flops (sequential)
always@(posedge clk)begin
if(reset)
state<=BYTE1;
else
state<=next_state;
end
// Output logic
assign done=(state==DONE);
endmodule
现在有了一个状态机,它将识别PS/2字节流中的三字节消息,添加一个数据路径,该数据路径也将在收到数据包时输出24位(3字节)消息(out_bytes[23:16]是第一个字节,out_bytes[15:8] 是第二个字节,等等)。
每当断言done信号时,out_bytes都需要有效。您可以在其他时间输出任何内容(i.e., don’t-care).。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
parameter Byte1=4'b0001,Byte2=4'b0010,Byte3=4'b0100,Done=4'b1000;
reg [3:0]state,next_state;
// FSM from fsm_ps2
always@(posedge clk)begin
if(reset)
state<=Byte1;
else
state<=next_state;
end
always@(*)begin
case(state)
Byte1:next_state=in[3]?Byte2:Byte1;
Byte2:next_state=Byte3;
Byte3:next_state=Done;
Done:next_state=in[3]?Byte2:Byte1;
default:next_state=Byte1;
endcase
end
assign done=(state==Done);
// New: Datapath to store incoming bytes.
always@(posedge clk)begin
if(next_state==Byte2)begin
if(state==Byte1)
out_bytes[23:16]<=in;
else if(state==Done)
out_bytes[23:16]<=in;
end else if(next_state==Byte3)begin
out_bytes[15:8]<= in;
end else if(next_state==Done||next_state==Byte1)begin
out_bytes[7:0]<=in;
end
end
endmodule
在许多(较旧的)串行通信协议中,每个数据字节与开始位和停止位一起发送,以帮助接收器从比特流中划分字节。一种常见方案是使用一个起始位(0)、8个数据位和1个停止位(1)。当无任何传输(空闲)时,线路也处于逻辑1。
设计一个有限状态机,当给定比特流时,该状态机将识别何时正确接收字节。它需要识别起始位,等待所有8个数据位,然后验证停止位是否正确。如果停止位未按预期出现,则FSM必须等到找到停止位后,再尝试接收下一个字节。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
parameter IDLE=4'd0,START=4'd1,
DATE1=4'd2,DATE2=4'd3,DATE3=4'd4,DATE4=4'd5,DATE5=4'd6,DATE6=4'd7,DATE7=4'd8,DATE8=4'd9,
STOP=4'd10,WAIT=4'd11;
reg [3:0]state,next_state;
always@(posedge clk)begin
if(reset)
state<=IDLE;
else
state<=next_state;
end
always@(*)begin
case(state)
IDLE:next_state=in?IDLE:START;
START:next_state=DATE1;
DATE1:next_state=DATE2;
DATE2:next_state=DATE3;
DATE3:next_state=DATE4;
DATE4:next_state=DATE5;
DATE5:next_state=DATE6;
DATE6:next_state=DATE7;
DATE7:next_state=DATE8;
DATE8:next_state=in?STOP:WAIT;
WAIT:next_state=in?IDLE:WAIT;
STOP:next_state=in?IDLE:START;
default:next_state=IDLE;
endcase
end
assign done=(state==STOP);
endmodule