错题笔记:
这道题是关于串行通信协议,接收数据流的的一种状态机。包括前面几道状态机的题在内,出错了很多次,主要原因有两点:
(1)时序理解不到位
(2)题目理解不到位
题目:
在许多(较旧的)串行通信协议中,每个数据字节都与起始位和停止位一起发送,以帮助接收者从位流中划分字节。一种常见的方案是使用一个起始位 (0)、8 个数据位和 1 个停止位 (1)。当没有传输任何内容(空闲)时,该行也位于逻辑 1 处。
设计一个有限的状态机,当给定位流时,它将识别何时正确接收字节。它需要识别起始位,等待所有8个数据位,然后验证停止位是否正确。如果停止位未按预期出现,则 FSM 必须等到找到停止位后再尝试接收下一个字节。
做题过程:
1.一开始写读取接收数据流的这种状态机时,对时序理解不到位,以为是先有现状态(时刻1),再有输入(时刻2),在输入的同时,产生次状态(时刻2);但是这种理解是错误的,因为次状态,是通过结合现状态和输入两者,判断而出的,所以输入和现状态一定是同步的,否则就无法同时操作他俩来进行判断(这个错误对我来说,很典型)。
2.一开始的思路(思路一)有问题,还是和对时序的理解有关,我下意识认为到了S8,就已经流过了8位data,所以,我认为在S8时,输入若为1,则到S9状态,就可以输出done=1了。
但是实际上,在S8时,输入信号并不是代表的stop信号,而是代表的bit[8]。
3.在意识到上述错误以后,我增加了一个状态(思路二),在这个状态图的理解下,我卡了很久。从Done状态,输入为1时,下一状态为ELSE,用来代表,上述时序图中,最右侧红框的变化,但后来我发现这一个ELSE状态是多余的,因为如果在DONE下输入为1,可以直接令其,回到S0状态,于是我又修改了状态图(思路三)。
4.修改之后,还是输出不对,done信号始终为0,这让我很疑惑。对比别人的答案后,我发现我漏掉了时序图中下侧红框中所表示的变化,所以就增加了ERROR的状态。在ERROR状态下,如果输入为0,保持ERROR;如果输入为1,则跳转到S0状态。而我原来的写法是,如果在S9下,输入为0,就直接跳转到S0, 这和题目的要求是不符合的,题目的S0指的是输入要为1(如时序图中左侧红框所示)。所以正确的状态转换图如下:
但还是很疑惑,为什么done信号在思路三的代码下,会始终为0,感觉上,S9到Done的跳转应该是正常的才对,那done信号就应该在Done状态下输出1,但仿真结果却和我设想的不一样。
正确答案:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
reg [3:0] state,next_state;
parameter S0=0,S1=1,S2=2,S3=3,S4=4,S5=5,S6=6,S7=7,S8=8,S9=9,DONE=10,ERROR=11;
always@(*)begin
case(state)
S0: next_state = in?S0:S1;
S1: next_state = S2;
S2: next_state = S3;
S3: next_state = S4;
S4: next_state = S5;
S5: next_state = S6;
S6: next_state = S7;
S7: next_state = S8;
S8: next_state = S9;
S9: next_state = in?DONE:ERROR;//一开始写的S0,理解有误
DONE: next_state = in?S0:S1;
ERROR: next_state = in?S0:ERROR;//一开始理解的是ELSE
endcase
end
always@(posedge clk)begin
if(reset)
state <= S0;
else
state <= next_state;
end
assign done = (state==DONE);
endmodule
卡了很久的错误答案:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output done
);
reg [3:0] state,next_state;
parameter S0=0,S1=1,S2=2,S3=3,S4=4,S5=5,S6=6,S7=7,S8=8,S9=9,DONE=10;
always@(*)begin
case(state)
S0: next_state = in?S0:S1;
S1: next_state = S2;
S2: next_state = S3;
S3: next_state = S4;
S4: next_state = S5;
S5: next_state = S6;
S6: next_state = S7;
S7: next_state = S8;
S8: next_state = S9;
S9: next_state = in?DONE:S0;//问题就出在如果in为0,并不是跳转到S0;
DONE: next_state = in?S0:S1;
endcase
end
always@(posedge clk)begin
if(reset)
state <= S0;
else
state <= next_state;
end
assign done = (state==DONE);
endmodule