由于很多时候存入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