1、PS/2鼠标协议发送三字节长的消息。然而,在一个连续的字节流中,消息的开始和结束位置并不明显。唯一的指示是,每个三字节消息的第一个字节的bit[3]=1(但其他两个字节的bit[3]可能是1或0,具体取决于数据)。
我们需要一个有限状态机,当给定一个输入字节流时,它将搜索消息边界。我们将使用的算法是丢弃字节,直到我们看到bit[3]=1的字节。然后我们假设这是一条消息的字节1,并在所有3个字节都被接收(完成)后发出消息接收信号。
FSM应在成功接收到每条消息的第三个字节后立即发送信号完成循环。
状态图一开始想了好一会儿,这里是将byte1作为常态,直到in[3]=1时才跳到次态。而将三个状态变换之后到done,此时如果in[3]=0,则回到byte1,如果in[3]=1,则直接跳到byte2,因为byte3结束若in[3]=1则会直接到下个三字节,是连续的,如果跳到byte1会有一个间隔。
状态图正确太重要了!
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
parameter byte1=0,byte2=1,byte3=2,done0=3;
reg [1:0] state,next_state;
// State transition logic (combinational)
always @(*)
begin
case(state)
byte1: next_state<=(in[3])?byte2:byte1;
byte2: next_state<=byte3;
byte3: next_state<=done0;
done0: next_state<=(in[3])?byte2:byte1;
//出现一个done就输出一个done的高电平,这里一开始我把done设置成常态,in[3]=1时才变化,这样会导致输出不匹配。
endcase
end
// State flip-flops (sequential)
always @(posedge clk)
begin
if(reset) state<=0;
else state<=next_state;
end
// Output logic
assign done = (state==done0)? 1:0;
endmodule
2、现在有了一个状态机,它可以识别PS/2字节流中的三字节消息,添加一个数据路径,每当接收到数据包时,它也会输出24位(3字节)消息(out_bytes[23:16]是第一个字节,out_bytes[15:8]是第二个字节等)。
无论何时断言done信号,out_字节都必须有效。您可以在其他时间输出任何内容(即不关心)。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
parameter byte1=0,byte2=1,byte3=2,done0=3;
reg [1:0] state,next_state;
always @(*) //组合逻辑
begin
case(state)
byte1: next_state<=(in[3])?byte2:byte1;
byte2: next_state<=byte3;
byte3: next_state<=done0;
done0: next_state<=(in[3])?byte2:byte1;
endcase
end
always @(posedge clk)
begin
if(reset) state<=0;
else state<=next_state;
//唯一不同于上一题的部分:
//易错:只有当in[3]=1时才读入in的值,如果没有这个判断,在任意时刻in都会载入out_bytes[23:16]中。
//同时,done状态时也需要考虑下一状态的变化时out_bytes[23:16]的输出。
//三字节的首位输出很重要
case(state)
byte1:out_bytes[23:16] <=(in[3])?in:0;
byte2:out_bytes[15:8] <=in;
byte3:out_bytes[7:0] <=in;
done0:out_bytes[23:16] <=(in[3])?in:0;
endcase
end
assign done = (state==done0)? 1:0;
endmodule