FIFO加包文,切割包文

一、模块没收到一个包文时,先发送一个开始包文,再发送数据包文,最后发送结束包文。
输入的包文是32bit,而输出的包文格式要求为8bit
开始包文格式如下:

8’h558’'h558’h558’hd58’hd5pack_id

数据包文格式与上游输入的包文一致

结束包文格式如下:

8’h558’'h558’h558’hfd8’hfdpack_id

注:pack_id是指进来包文的id信号,第一个包文id为0,后面依次累加

//部分信号列表
input        [31:0]         din           ;
input                       din_sop       ;
input                       din_eop       ;
input        [1:0]          din_mty       ;
output       [7:0]  reg     dout          ;
output              reg     dout_sop      ;
output              reg     dout_eop      ;
output              reg     dout_vld      ;

分析:
显然,输入与输出位数不匹配,那么应该怎么办?很简单,采用计数器分四次将一个32bit数据传输完成。
问题1:如何划分开始、数据和结束包文?
不妨设计两个计数器,一个计数器记开始与结束,因为都是6*8bit,这个计数器记完会跳入数据计数器,计数完毕后则又会跳回结束计数器。

//写侧数据FIFO和信息FIFO的使能及数据
assign    wr_en = din_vld ;
assign    wdata = din;

assign    msg_wr_en = din_vld && din_eop;
assign    msg_wdata = 1;


//因为开始跟结束包文都是6bit,所以需要计数器计数
//需要避过发送数据阶段,使用cnt0表示开始结束,使用cnt1表示三个阶段
// cnt1 == 1-1 :开始阶段
// cnt1 == 2-1 :发送数据阶段
// cnt1 == 3-1 :结束阶段
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
      cnt0 <= 0;
   end
   else if(add_cnt0)begin
      if(end_cnt0)begin
         cnt0 <= 0;
      end
      else 
         cnt0 <= cnt0 + 1'b1;
   end
end
assign    add_cnt0 = msg_empty == 0 && cnt1 != 2-1;
assign    end_cnt0 = add_cnt0 && cnt0 == 6-1;

//计数条件是开始包文发送完成,数据包文发送完成,结束包文发送完成
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
      cnt1 <= 0;
   end
   else if(add_cnt1)begin
      if(end_cnt1)begin
         cnt1 <= 0;
      end
      else 
         cnt1 <= cnt1 + 1'b1;
   end
end
assign    add_cnt1 = end_cnt0 && dout_eop_tmp;
assign    end_cnt1 = add_cnt1 && cnt1 == 3-1;
assign    dout_eop_tmp = rd_en && q[34];
//将32bit做并串转换。转换成8Bit
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
      cnt2 <= 0;
   end
   else if(add_cnt2)begin
      if(end_cnt2)begin
         cnt2 <= 0;
      end
      else 
         cnt2 <= cnt2 + 1'b1;
   end
end
assign    add_cnt2 = msg_empty == 0 && cnt1 == 2-1;
assign    end_cnt2 = add_cnt2 && cnt2 == X - 1; //一般计数是4个,但是要看din_mty

always @(*)begin
  if(q[34])begin
     X = 4 - q[33:32];
  end
  else begin
     X = 4;
  end
end

//数据FIFO的读使能
//输出4个8bit数据才读一次
assign   rd_en = end_cnt2;
//信息FIFO的读使能
assign   msg_rd_en = end_cnt1; //msg_q 一定要在最后一刻清0

//pack_id代码
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
      pack_id <= 0;
   end
   else if(end_cnt1)begin
      pack_id <= pack_id + 1'b1;
   end
end

//dout
//先将数据组合起来方便传输
assign   data_sel = (cnt1 == 1-1) ? 16'hd5d5:16'hfdfdl;
assign   ctrl_data = {8'h55,8'h55'8'h55,data_sel,pack_id};

always @(posedge clk or negedge rst_n)begin
   if(rst_n == 0)begin
      dout <= 0;
   end
   else if(add_cnt0)begin
      dout <= ctrl_data[47 - 8*cnt0 -:8];
   end
   else begin
      dout <= q[32 -8*cnt2 -:8];
   end
end

//dout_sop

always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
      dout_sop <= 0;
   end
   else begin
      dout_sop <= (add_cnt0 && cnt0 == 1-1) || (add_cnt1 && cnt1 == 2-1  && q[35]) ;
   end
end

//dout_eop
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
      dout_eop <= 0;
   end
   else begin
      dout_eop <= end_cnt0 || dout_eop_tmp ;
   end
end
//dout_vld
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
      dout_vld <= 0;
   end
   else begin
      dout_vld <= add_cnt0 || add_cnt2;
   end
end

二、包文分段
要求:模块将输入的包文切成1个或者多个小于等于256字节的数据包文发送给下游模块。假设包文长度为len当len <=256字节时,无须切割,数据包文长度为len:当len > 256,且<=256字节时,切割成2个数据包文,第一个包文长度为256,第二个包文长度为len-256,依次类推。
输入8bit,输出8bit
开始包文格式如下:

8’h558’'h558’h558’hd58’hd5pack_id

数据包文格式与上游输入的包文一致

结束包文格式如下:

8’h558’'h558’h558’hfd8’hfdpack_id

注:pack_id是指进来包文的id信号,第一个包文id为0,后面依次累加
关于区分开始包文,数据包文和结束包文的方法与【一】相同,此处就不再重复。
分析:
关于切割部分,使用计数器将其切割

always @(posedge clk or negedge rst_n)begin
  if(rst_n==0)begin
    cnt2 <= 0;
  end
  else if(add_cnt2)begin
    if(end_cnt2)begin
       cnt2 <= 0;
    end
    else begin
       cnt2 <= cnt2 + 1;
    end
  end
end
//256个一段,除非是最后一段碰到DOUT_EOP
assign   add_cnt2 = msg_empty == 0 && cnt1 == 2-1;
assign   end_cnt2 = add_cnt2 && (cnt2 == 256 - 1 || last_data);
assign   last_data = cnt1 == rd_en && q[8];

//dout_sop
//注意此处的sop,在切割包文中也是有的
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
     dout_sop <= 0;
   end
   else begin
     dout_sop <= (add_cnt0 && cnt0 == 1-1)||(add_cnt2 && cnt2 == 1-1);
   end
end
//dout_eop
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
     dout_eop <= 0;
   end
   else begin
     dout_eop <= end_cnt0 ||end_cnt2;
   end
end

//dout_vld
always @(posedge clk or negedge rst_n)begin
   if(rst_n==0)begin
     dout_vld <= 0;
   end
   else begin
     dout_vld <= add_cnt0 || add_cnt2;
   end
end


三、模拟以太网切割包文
此处切割后并不知道这是第几个包文,只知道分成了1500和46以内,功能较为简单,后面会说如何设计知道这是被分成了几个包文。
以太网包模块的功能是对输入的包文进行切割,使输出的每个包文都控制在46~1500字节范围内。
如果输入包文长度len < 46字节,则通过在末尾补0的方式,输出长度为46字节的包文;
如果输入包文长度len > (1500n)且len<=(1500n + 46)[n>=1]时,切分成n-1个1500长度的包文,1个(len-1500*(n-1)-46)长度包文和1个46字节的包文。
如果输入包文长度len <= (1500*(n+1))且len>(1500n+46)[n>=1]时,切分成n个1500长度的包文,1个(len-1500n)长度包文

//数据FIFO的写数据和写使能
assign    wr_en = din_vld;
assign    wdata = {din_sop,din_eop,din};

//在写侧进行包文的计数
//写侧进行切割的话,读侧就可以直接读
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       cnt <= 0;
   end
   else if(add_cnt)begin
       if(end_cnt)begin
           cnt <= 0;
       end
       else 
          cnt <= cnt + 1'b1;
   end
end
assign    add_cnt = din_vld ;
assign    end_cnt = add_cnt && (din_eop || add_cnt == 1500-1);

//信息FIFO的写使能和写数据
//将切割后的长度存入信息FIFO
assign    msg_wr_en = end_cnt;
assign    msg_wdata = cnt + 1;

//读出的包文长度
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       cnt1 <= 0;
   end
   else if(add_cnt1)begin
       if(end_cnt1)begin
           cnt1 <= 0;
       end
       else 
          cnt1 <= cnt1 + 1'b1;
   end
end
assign    add_cnt1 = msg_empty == 0;
assign    end_cnt1 = add_cnt1 && cnt1 == x-1;

always @(*)begin
  if(msg_q < 46)begin
    x = 46;
  end
  else
    x = msg_q;
end

四、设计指示将以太网按照要求切割了多少个包文

//使用两个计数器,一个计1500,一个计46,使用flag信号来告诉计数器什么时候计1500,什么时候计46
//为什么要计46?
//因为若是只计数1500,那么大于1500而小于1546的部分便无法分辨,从而有可能导致切割出错
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       cnt <= 0;
   end
   else if(add_cnt)begin
       if(end_cnt)begin
           cnt <= 0;
       end
       else 
          cnt <= cnt + 1'b1;
   end
end
assign    add_cnt = din_vld ;
assign    end_cnt = add_cnt && (din_eop || add_cnt == 1500-1);

//
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       cnt1 <= 0;
   end
   else if(add_cnt1)begin
       if(end_cnt1)begin
           cnt1 <= 0;
       end
       else 
          cnt1 <= cnt1 + 1'b1;
   end
end
assign    add_cnt1 = din_vld && flag == 1;
assign    end_cnt1 = add_cnt1 && (din_eop || add_cnt1 == 46-1);

//flag :当cnt计数了1500时,拉高,cnt1开始计数,计数完46时将flag拉低
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
        flag <= 0;
    end
    else if(end_cnt && din_eop == 0)begin
        flag <= 1;
    end
    else if(end_cnt1)begin
        flag <= 0;
    end
end

//数据FIFO存储的数据和写使能与上面相同,但是此处的信息FIFO需要注意
//信息FIFO的写使能和写数据

always @(*)begin
   if(din_vld && din_eop)begin
       if(flag == 1)
          msg_wdata = 1500 + cnt1 + 1;
       else
          msg_wdata = cnt + 1;
   end
   else 
     msg_wdata = 1500;
end


//遇到EOP写或者end_cnt1记完
//46记完是指包文长度大于1546了,所以写1500到信息FIFO
assign   msg_wr_en = end_cnt1 || (din_vld && din_eop);

//读侧的计数器
//计数读侧输出的数据字节
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       cnt2 <= 0;
   end
   else if(add_cnt1)begin
       if(end_cnt2)begin
           cnt2 <= 0;
       end
       else 
          cnt2 <= cnt2 + 1'b1;
   end
end
assign    add_cnt2 = msg_empty == 0;
assign    end_cnt2 = add_cnt2 && cnt2 == x+z-1;

//计数分成了多少个包文
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       cnt3 <= 0;
   end
   else if(add_cnt3)begin
       if(end_cnt3)begin
           cnt3 <= 0;
       end
       else 
          cnt3 <= cnt3 + 1'b1;
   end
end
assign    add_cnt3 = end_cnt2;
assign    end_cnt3 = add_cnt3 && add_cnt3 == y-1;

//x 是 发送的实际数据,z是补0的个数
//当大于1500,发两个包文,一个是46,一个是长度-46
always @(*)begin
   if(msg_q < 46)begin
      x = msg_q ;
      y = 1  ;
      z = 46 - msg_q;
   end
   else if(msg_q < 1501)begin
      x = msg_q ;
      y = 1;
      z = 0;
   end
   else begin //msg_q >1500
      if(cnt3 == 0)begin
         x = msg_q - 46; //长度大于1500,一个包文发46,一个发长度-46
         y = 2 ;
         z = 0 ;
      end
      else begin
        x = 46 ;
        y = 2;
        z = 0;   
      end
   end
end

//数据FIFO的读使能
//*****注意不必输出补的0位字节********
assign   zero_n = add_cnt2 && cnt2 < x ;
assign   rd_en  = add_cnt2 && zero_n;
//信息FIFO的读使能
assign   msg_rd_en  = end_cnt3 ;

//dout
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       dout <= 0;
   end
   else begin
       dout <= q[7:0];
   end
end

//dout_sop
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       dout_sop <= 0;
   end
   else begin
       dout_sop <= add_cnt2 && cnt2 == 1-1;
   end
end
//dout_eop
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       dout_eop <= 0;
   end
   else begin
       dout_eop <= end_cnt2;
   end
end

//dout_vld
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
       dout_vld <= 0;
   end
   else begin
       dout_vld <= add_cnt2;
   end
end


  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值