本题完成对同步HDLC组帧的数据流bit进行解码,需要判断数据流的起始,终止,还有错误以及丢弃0的状态,并且给出相应的标志,具体如下:
- 0111110: Signal a bit needs to be discarded (disc).
- 01111110: Flag the beginning/end of a frame (flag).
- 01111111...: Error (7 or more 1s) (err).
当状态机rst的时候,状态机必须回到之前输入为0的状态。
下面给了几个例子示意图
笔者的思路是采用移位寄存器加状态机的方法,移位寄存器作为序列检测器使用,同时检测到对应的序列之后,状态机跳转到相应的状态。只采用了三个状态,分别是IDLE,SYN,ERROR,是足够对三个输出信号进行判断的。
提一下主要思路和需要注意的点
主要思路:
- 初始处于IDLE状态,当序列检测器检测到开始标志的时候跳转SYN,如果检测到错误标志则跳转ERROR;
- SYN状态检测到结束标志跳转IDLE,如果检测到错误则跳转ERROR;
- ERROR状态进入之后一直保持,直到输入为低电平才返回IDLE;
- 根据各个状态之间的跳转判断输出;
注意的点:
- 同步复位
- 不管在什么状态都可能会遇到连续7个高电平,因此都需要判断ERROR
- ERROR跳出逻辑不是in == 1'b0,而是seq_reg8[0] == 1'b1,是因为时序需要多打一拍
- 当状态机rst的时候,状态机必须回到之前输入为0的状态。对于这个要求只需要将移位寄存器清0即可。
下面直接贴代码
module top_module(
input clk,
input reset, // Synchronous reset
input in,
output disc,
output flag,
output err);
parameter IDLE = 3'd0;
// parameter START = 3'd2;
parameter SYN = 3'd1;
parameter ERROR = 3'd2;
// parameter
reg [2:0] curr_state;
reg [2:0] next_state;
reg [7:0] seq_reg8;
always @(posedge clk) begin
if(reset) begin
curr_state <= IDLE;
end
else begin
curr_state <= next_state;
end
end
always @(*) begin
case(curr_state)
IDLE:begin
if(seq_reg8 == 8'b01111110) begin
next_state <= SYN;
end
else if(seq_reg8 == 8'b01111111) begin
next_state <= ERROR;
end
else begin
next_state <= IDLE;
end
end
SYN:begin
if(seq_reg8 == 8'b01111110) begin
next_state <= IDLE;
end
else if(seq_reg8 == 8'b01111111) begin
next_state <= ERROR;
end
else begin
next_state <= SYN;
end
end
ERROR: begin
if( seq_reg8[0] == 1'b0) begin
next_state <= IDLE;
end
else begin
next_state <= ERROR;
end
end
default:next_state <= IDLE;
endcase
end
always@(posedge clk) begin
if(reset) begin
seq_reg8 <= 8'd0;
end
else begin
seq_reg8 <={seq_reg8[6:0],in};
end
end
// assign disc = (curr_state == SYN)&&(seq_reg8[6:0] == 7'b0111110);//一开始以为只有在数据接受的期间才识别连1
assign disc = (seq_reg8[6:0] == 7'b0111110);
assign flag = ((curr_state == IDLE)&&(next_state == SYN) )||((curr_state == SYN)&&(next_state == IDLE));
assign err = (next_state == ERROR);
endmodule
存疑
笔者在写代码调试的时候一开始将disc的判断条件限定在了数据区域内,即只有在接收数据(SYN)的时候才会对连续的5个1发出disc信号表示忽略后面的一个0。后面发现波形出来的比较奇怪,如下图。
图中先ERROR之后进入IDLE,但是一直未出现开始标志,所以未进入SYN状态,但是此时他还是识别出了disc。然后笔者便去查阅了一下资料,wiki中是这样解释的
Because a flag sequence consists of six consecutive 1-bits, other data is coded to ensure that it never contains more than five 1-bits in a row. This is done by bit stuffing: any time that five consecutive 1-bits appear in the transmitted data, the data is paused and a 0-bit is transmitted.
The receiving device knows that this is being done, and after seeing five 1-bits in a row, a following 0-bit is stripped out of the received data. If instead the sixth bit is 1, this is either a flag (if the seventh bit is 0), or an error (if the seventh bit is 1). In the latter case, the frame receive procedure is aborted, to be restarted when a flag is next seen.
按照wiki解释还是在数据区域内对数据进行0填充,至于非数据区域并没有提及,所以这里对题目存疑了,后来想了下实际应用中是否识别数据区域之外的0填充无关紧要,毕竟根据开始和结束标志识别的包同步信号足够将这些数据区域之外的0填充信号滤除,所以这里也就不深究啦。
修改disc的判断条件为所有状态下进行识别即通过了测试用例。