FIFO读写侧位数不同的处理

由于很多时候存入FIFO与需要读出的数据位数并不一致,所以需要对齐进行处理。可以分为两种情况:
一、写侧位数少于读侧
例:
din : [7:0] ;
dout:[15:0];
显然,输入与输出不匹配,此时有两个方法可以进行位拼接,一个方法是FIFO的位宽依旧为8Bit,在写侧进行数据的拼接,代码如下:

//读侧设置一个计数器,读两次,输出一次
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  begin
            cnt <= cnt + 1'b1; 
       end
   end
end
assign    add_cnt = rd_en;
assign    end_cnt = add_cnt && cnt == 2-1;

always @(posedge clk or negedge rst_n)begin
     if(rst_n==0)begin
         dout <= 0;
     end
     else if(add_cnt)begin
         dout[15 -8*cnt -:8] <= q[7:0];
     end
end

这种方法有个缺点,就是会浪费时钟,在读侧你无论怎么样处理,都是两个时钟才会出一次16bit数据,若对数据速度没有要求可采用本方法。
方法二:FIFO采用16bit,在写侧存两次,读侧可以保证在开始读以后每个时钟都有数据流出。
代码如下:

//写侧代码
//计数器计数,每两个数据存一次
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 && cnt == 2-1;

always@(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
        wdata <= 0;
    end
    else if(add_cnt)begin
       wdata[15 - 8*cnt -:8] <= din;
    end
end
always @(*)begin
    if(end_cnt)
        wr_en <= 1;
    else
        wr_en <= 0;
end


此方法读侧时钟不会被浪费,但是可以看出FIFO存储位由原来的8bit变为16Bit。
二、写侧数据位数多于读侧

写侧多于读侧时,处理方法也是两种,即读写两次分别进行控制,要么设置FIFO宽度与写侧相同,在读侧进行控制;要么设置FIFO宽度与读侧相同,在写侧进行控制。
方法一:

//FIFO宽度与写侧相同
//在写侧用一个计数器来控制
//din[31:0] ,dout[7:0]

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 = empty ==0 ;
assign    end_cnt = add_cnt && cnt == 4-1;
//读使能注意
assign   rd_en = end_cnt ;
//dout
always @(posedge clk or negedge rst_n)begin
     if(rst_n==0)begin
         dout <= 0;
     end
     else if(add_cnt)begin
         dout <= q[31 - 8*cnt -:8];
     end
end

方法二、

//FIFO宽度与读侧一致
//在写侧设置计数器以适应FIFO宽度
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 && cnt == 4-1;
//注意写使能和写数据
always @(*)begin
    if(add_cnt)
       wr_en = 1;
    else 
       wr_en = 0;
end

always @(posedge clk or negedge rst_n)begin
     if(rst_n == 0)begin
        wdata <= 0;
     end
     else if(add_cnt)begin
       wdata <= din[31 -8*cnt -:8];
     end
end

补充:
以8进32出为例,进来四次写一次,那么要是进来的没有4次,即没有32bit数据时怎么处理?

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 && (cnt == 4-1 || din_eop); //进来32bit或者收到din_eop时停止计数

而后面需要处理的就是无效数据的个数是多少?sop和eop应该加在什么地方等。不妨使用信号din_mty来表示无效的数据个数(8bit是一个,以输入的位数为准),其他信号设计如下

//产生数据、SOP\EOP\MTY
always @(posedge clk or negedge rst_n)begin
     if(rst_n==0)begin
         din_ff0 <= 0;
     end
     else if(add_cnt)begin
         din_ff0[31-8*cnt -:8] <= din;
     end
end
//SOP
always @(posedge clk or negedge rst_n)begin
     if(rst_n==0)begin
         din_sop_ff0 <= 0;
     end
     else if(add_cnt && cnt == 1-1)begin
         din_sop_ff0 <= din_sop;
     end
end
//EOP
always @(posedge clk or negedge rst_n)begin
     if(rst_n==0)begin
         din_eop_ff0 <= 0;
     end
     else if(end_cnt)begin
         din_eop_ff0 <= din_sop;
     end
end
//MTY
always @(posedge clk or negedge rst_n)begin
     if(rst_n==0)begin
         din_mty_ff0 <= 0;
     end
     else if(end_cnt)begin
         din_mty_ff0 <= 3 - cnt;
     end
     else begin
         din_mty_ff0 <= 0;
     end
end
//对数据进行拼接存入FIFO
//由于数据在进行赋值时使用了D触发器,所以主要使wr_en的时序与其对齐
assign    wdata = {din_sop_ff0,din_eop_ff0,din_mty_ff0,din_ff0};
always @(posedge clk or negedge rst_n)begin
    if(rst_n==0)begin
         wr_en <= 0;
    end
    else begin
        wr_en <= end_cnt;
    end
end

你可能感兴趣的:(FPGA简单练习,FPGA,FIFO,位拼接)