数字IC面试手撕代码(九)

题目

正常情况下,数据包由起始码(16bit)、数据段(n字节,n<256)、结束码(16bit)三部分构成。起始码为0xFF00,结束码为0xFF01。在一个完整的数据包中,数据段部分不会出现起始码和结束码。请设计一个电路,在码流中检测完整且有效的数据包,并输出当前数据包的有效长度n。

分析

一个完整的数据包,需要满足两个要求,第一个是长度小于256,另一个是数据包中不能出现起始码和结束码。因此,我们需要设置一个2bit的error信号,当它取01时,表示在数据包中检测到起始码,发生错误,当它取10时,表示数据包的长度大于等于256,超出规定的范围,为00时表示数据包无误。
我们通过状态机,来实现码流的检测:
IDLE:空闲状态,未检测到起始码,当它检测到8’h00时跳转到START
START:起始码状态,表明已经检测到起始码的第一个字节8’h00,之后接收到8’hff,则跳转到DATA状态,若接收到8’h00,则保持状态不变,若接收到其他数据,则跳转为IDLE,没有接收到数据时状态保持不变。
DATA:数据包状态,表示正在接收数据段部分,当接收的数据个数大于255时,跳转到IDLE状态,同时error信号变为10,表示数据长度超出范围,当上一个数据为8’h00,并且本次接收到的数据为8’hff时,说明在数据段中检测到起始码,跳转到IDLE状态,同时error信号变为01,当上一个接收的数据为01,且本次接收的数据为8’hff时,跳转到END状态,表示检测到结束码。
END:结束状态,当检测到8’h00时,跳转到START状态,否则跳转到IDLE状态。

代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/18 21:37:17
// Design Name: 
// Module Name: demo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module demo
(
input logic clk,
input logic rst_n,
input logic [7:0] din,
input logic din_vld,
output logic [9:0] data_cnt_o,
output logic data_cnt_vld,
output logic [1:0] error
);
typedef enum bit[31:0] {
    IDLE,
    START,
    DATA,
    END
} State;
State cur_state,next_state;
logic [7:0] pre_din;
logic [9:0] data_cnt;
//
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    cur_state<=IDLE;
else 
    cur_state<=next_state;
//
always_comb
begin
    case(cur_state)
        IDLE:if(~rst_n)
                 next_state=IDLE;
             else if(din_vld&&din==8'h00)          
                 next_state=START;
             else
                 next_state=IDLE;
        START:if(din_vld&&din==8'hFF)
                   next_state=DATA;
               else if(din_vld&&din==8'h00)
                   next_state=START;
               else if(din_vld)
                   next_state=IDLE;
               else
                   next_state=START;
        DATA:if(din_vld&&din==8'hFF&&pre_din==8'h00)              //在接收数据时又接收到起始码,数据包错误
                 next_state=IDLE;
             else if(din_vld&&data_cnt==255)                      //数据个数超出最大值,数据包错误
                 next_state=IDLE;
             else if(din_vld&&din==8'hff&&pre_din==8'h01)          //接收到结束码,进入END状态,数据包接收完成
                 next_state=END;
             else 
                 next_state=DATA;
        END:if(din_vld&&din==8'h00)
                next_state=START;
            else
                next_state=IDLE;
        default:next_state=IDLE;
    endcase
end
//pre_din
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    pre_din<=8'h11;                     //不能为00或01
else if(din_vld)
    pre_din<=din;
//data_cnt
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    data_cnt<=0;
else if(cur_state==DATA&&din_vld)
    data_cnt<=data_cnt+1;
else if(cur_state==END||cur_state==IDLE)
    data_cnt<=0;
//error
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
   error<=0;
else if(cur_state==DATA)
    if(din_vld&&pre_din==8'h00&&din==8'hff)                   //在接收数据时检测到起始码,错误
        error<=2'b01;
    else if(din_vld&&data_cnt==255)                           //数据包超出长度
        error<=2'b10;
    else
        error<=0;
else
    error<=0;
//
assign data_cnt_vld=(cur_state==END)?1'b1:1'b0;    
assign data_cnt_o=data_cnt-2;                          //去掉尾部的2个字节 
endmodule

测试平台:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/18 21:45:51
// Design Name: 
// Module Name: test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module test;
logic clk;
logic rst_n;
logic [7:0] din;
logic din_vld;
logic [9:0] data_cnt_o;
logic data_cnt_vld;
logic [1:0] error;
logic [31:0] cnt;
//
initial begin
    clk=0;
    forever begin
        #5 clk=~clk;
    end
end
//
initial
begin
    rst_n=0;
    #50
    rst_n=1;
end
//cnt
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    cnt<=0;
else if(din_vld)
    cnt<=cnt+1;
else if(data_cnt_vld)
    cnt<=0;
//din,din_vld
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
begin
    din<=0;
    din_vld<=0;
end
//数据包中有起始码错误检测
else if(cnt==0)
begin
    din_vld<=1;
    din<=8'h00;
end
else if(cnt==1)
begin
    din<=8'hff;
    din_vld<=1;
end
else if(cnt==100)
begin
    din<=8'h00;
    din_vld<=1;
end
else if(cnt==101)
begin
    din<=8'hff;
    din_vld<=1;
end
else if(cnt>=2&&cnt<264)
begin
    din<=8'h34;
    din_vld<=1;
end
else if(cnt==264)
begin
    din<=8'h01;
    din_vld<=1;
end
else if(cnt==265)
begin
    din<=8'hff;
    din_vld<=1;
end                                         
//300-500,数据包长度超出限制错误检测
else if(cnt==300)
begin
    din<=8'h00;
    din_vld<=1;
end
else if(cnt==310)
begin
    din<=8'hff;
    din_vld<=1;
end
else if(cnt>=311&&cnt<590)
begin
    din<=8'h00;
    din_vld<=1;
end
//
else if(cnt==600)
begin
    din<=8'h00;
    din_vld<=1;
end
else if(cnt==612)
begin
    din<=8'hff;
    din_vld<=1;
end
else if(cnt>=613&&cnt<700)
begin
    din<=8'h01;
    din_vld<=1;
end
else if(cnt==700)
begin
    din<=8'hff;
    din_vld<=1;
end

demo U
(.*
// input logic clk,
// input logic rst_n,
// input logic [7:0] din,
// input logic din_vld,
// output logic [7:0] data_cnt,
// output logic data_cnt_vld,
// output logic [1:0] error
);
endmodule

仿真结果

测试平台一共测试了三种情况,第一种情况是在数据段中出现起始码,第二种情况是数据段长度超出范围,第三种则是正常的情况,下面三幅图分别是三种情况的波形:
case1:数据段中出现起始码
在这里插入图片描述
case2:数据段长度超过255
在这里插入图片描述
case3:正常接收数据
在这里插入图片描述
当然,代码无法保证百分百正确,如有读者发现错误,欢迎指出!

更新

上述代码在数据包长度为255时会误检测为数据包超出长度,因此我们做了如下修改:当读到第256个数据时,如果值不为01,则一定超出长度,报错,否则,有可能是结束码的低字节,因此继续保持DATA状态,当第257个数据到来时,如果它的确为8’hff,则数据包正确,并检测到结束码,状态跳到END,否则说明第256,257个数据组成的16bit并不是结束码,数据包长度超出范围,报错。修改后的代码如下所示

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/18 21:37:17
// Design Name: 
// Module Name: demo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module demo
(
input logic clk,
input logic rst_n,
input logic [7:0] din,
input logic din_vld,
output logic [9:0] data_cnt_o,
output logic data_cnt_vld,
output logic [1:0] error
);
typedef enum bit[31:0] {
    IDLE,
    START,
    DATA,
    END
} State;
State cur_state,next_state;
logic [7:0] pre_din;
logic [9:0] data_cnt;
//
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    cur_state<=IDLE;
else 
    cur_state<=next_state;
//
always_comb
begin
    case(cur_state)
        IDLE:if(~rst_n)
                 next_state=IDLE;
             else if(din_vld&&din==8'h00)          
                 next_state=START;
             else
                 next_state=IDLE;
        START:if(din_vld&&din==8'hFF)
                   next_state=DATA;
               else if(din_vld&&din==8'h00)
                   next_state=START;
               else if(din_vld)
                   next_state=IDLE;
               else
                   next_state=START;
        DATA:if(din_vld&&din==8'hFF&&pre_din==8'h00)              //在接收数据时又接收到起始码,数据包错误
                 next_state=IDLE;
             else if(din_vld&&data_cnt==255)                      //数据个数超出最大值,数据包错误
                 if(pre_din==8'h01&&din==8'hff)                   //数据包共254个数据
                    next_state=END;
                 else if(din==8'h01)
                    next_state=DATA;                              //有可能第256个数据是结束码
                 else
                    next_state=IDLE;
             else if(din_vld&&data_cnt==256)                      //第257个数据
                 if(din==8'hff)
                    next_state=END;                               //第256,257个数据组成结束码,数据包正确
                 else if(din==8'h00)                              //第256,257个数据不是结束码,但检测到00,跳转到START
                    next_state=START;
                 else
                    next_state=IDLE;                              //数据包长度超出范围
             else if(din_vld&&din==8'hff&&pre_din==8'h01)         //接收到结束码,进入END状态,数据包接收完成
                 next_state=END;
             else 
                 next_state=DATA;
        END:if(din_vld&&din==8'h00)
                next_state=START;
            else
                next_state=IDLE;
        default:next_state=IDLE;
    endcase
end
//pre_din
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    pre_din<=8'h11;                     //不能为00或01
else if(din_vld)
    pre_din<=din;
//data_cnt
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    data_cnt<=0;
else if(cur_state==DATA&&din_vld)
    data_cnt<=data_cnt+1;
else if(cur_state==END||cur_state==IDLE)
    data_cnt<=0;
//error
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
   error<=0;
else if(cur_state==DATA)
    if(din_vld&&pre_din==8'h00&&din==8'hff)                   //在接收数据时检测到起始码,错误
        error<=2'b01;
    else if(din_vld&&data_cnt==255&&din!=8'h01)               //第256个数据不是8'h01,则数据包一定超出长度
        error<=2'b10;
    else if(din_vld&&data_cnt==256&&din!=8'hff)               //256,257个数据不是结束码,数据包超出长度
        error<=2'b10;
    else
        error<=0;
else
    error<=0;
//
assign data_cnt_vld=(cur_state==END)?1'b1:1'b0;    
assign data_cnt_o=data_cnt-2;                          //去掉尾部的2个字节 
endmodule

数据包为255个数据时,现在也能正确检测了:
在这里插入图片描述
254个数据检测也正确
在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA硅农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值