赞
踩
异步fifo 非二的整数次方;
怎么进行跨时钟域处理?
格雷码的性质:1、相邻两个数只有一个BIT不同;2、去掉首位相同个数的位数后剩下的数仍满足相邻数只有一个bit不同,包括绕回;
这里就可以用来对设计深度不满足2的n次方的fifo做文章了;假设设计深度为28的fifo那么我们不用格雷码需要5bit表示地址,用格雷码需要6bit表示地址;那么我们截取6bit表示地址的中间2*28=56个地址;相当于去掉头尾2^5-28=4个地址;
在拿深度为5的fifo举例;2^3-5=3;去掉头尾3个地址;用格雷码可以表示为:
那么用格雷码表示读写指针进行跨时钟域的问题得以解决;
接下来需要将相应的二级制序列映射到实际的RAM地址中去,方法直接判断高位是否为1,为一截取,不为一减去去掉的头地址值;
空满判断,空格雷码相同为空;满则是将格雷码转换为二进制码进行判断,绝对值为FIFO深度时,FIFO即为满;
//假设FIFO深度不是2的n次幂,但要满足时4的倍数 //这里设计为深度28,利用格雷码的对称性,则格雷码转换的时候需要加32-28=4个地址 // ```c //假设FIFO深度不是2的n次幂,但要满足时4的倍数 //这里设计为深度28,利用格雷码的对称性,则格雷码转换的时候需要加32-28=4个地址 // module async_fifo #( parameter data_width = 16, parameter data_depth = 28, parameter addr_width = 5, parameter read_width = 16 ) ( input s_rstn, //write input wr_clk, input wr_en, input [data_width-1:0] wr_data, //read input rd_clk, input rd_en, output reg [read_width-1:0] rd_data, output wire out_full_w, output wire out_empty_w ); reg [addr_width:0] wr_address; reg [addr_width:0] rd_address; reg [addr_width:0] gray_wr_address; reg [addr_width:0] gray_rd_address; reg [addr_width:0] g2b_r2w; //wire out_full_w; //wire out_empty_w; reg [addr_width:0] async_w2r_r2,async_w2r_r1; reg [addr_width:0] async_r2w_r2,async_r2w_r1; always @(posedge rd_clk or negedge s_rstn) begin if(~s_rstn) begin rd_address<='d4; end else if (rd_en && ~out_empty_w) begin if(rd_address=='d59) rd_address<='d4; else rd_address<=rd_address+1'b1; end end always @(posedge wr_clk or negedge s_rstn) begin if(~s_rstn) begin wr_address<='d4; end else if (wr_en && ~out_full_w) begin if(wr_address=='d59) wr_address<='d4; else wr_address<=wr_address+1'b1; end end always @(posedge wr_clk ) begin gray_wr_address<=(wr_address) ^ ((wr_address)>>1); end always @(posedge rd_clk) begin gray_rd_address<=(rd_address) ^ ((rd_address)>>1); end //assign gray_wr_address=(wr_address) ^ ((wr_address)>>1); //assign gray_rd_address=(rd_address) ^ ((rd_address)>>1); always @(posedge rd_clk or negedge s_rstn) begin if(~s_rstn) begin {async_w2r_r2,async_w2r_r1}<='b0; end else begin {async_w2r_r2,async_w2r_r1}<={async_w2r_r1,gray_wr_address}; end end always @(posedge wr_clk or negedge s_rstn) begin if(~s_rstn) begin {async_r2w_r2,async_r2w_r1}<='b0; end else begin {async_r2w_r2,async_r2w_r1}<={async_r2w_r1,gray_rd_address}; end end //full and empty signal sheng cheng /* always @(posedge rd_clk or negedge s_rstn) begin if(~s_rstn) begin out_empty_w<=1'b1; end else out_empty_w<=(async_w2r_r2==gray_rd_address); end*/ assign out_empty_w=(async_w2r_r2==gray_rd_address); integer i; always @(*) begin for(i=0;i<=addr_width;i=i+1) g2b_r2w[i]=^(async_r2w_r2>>i); end assign out_full_w=((g2b_r2w+'d28)==wr_address)||((g2b_r2w-'d28)==wr_address); /* always @(posedge wr_clk or negedge s_rstn) begin if(~s_rstn) begin out_full_w<=1'b0; end else out_full_w<=((g2b_r2w+'d28)==wr_address)||((g2b_r2w-'d28)==wr_address); end*/ reg [data_width-1:0] register1 [data_depth-1:0]; always @(posedge rd_clk) begin if (rd_en && ~out_empty_w) begin if(rd_address[addr_width]==1) //判断高位是否为1,为一直接截取就可以,为0则要减去相应的数值 rd_data<=register1[rd_address[addr_width-1:0]];//直接截取低位就可以 else begin rd_data<=register1[rd_address[addr_width-1:0]-'d4]; end end end always @(posedge wr_clk ) begin if (wr_en && ~out_full_w) begin if(wr_address[addr_width]) register1[wr_address[addr_width-1:0]]<=wr_data; else begin register1[wr_address[addr_width-1:0]-'d4]<=wr_data; end end end endmodule
tb:
`timescale 1ns/1ns module tb_async_fifo(); reg s_rstn; //write reg wr_clk; reg wr_en; reg [16-1:0] wr_data; //read reg rd_clk; reg rd_en; wire [16-1:0] rd_data; wire out_full; wire out_empty; parameter period = 10; parameter rd_period =15; initial begin s_rstn=00; #(period*2) s_rstn=1; end initial begin wr_clk=0; rd_clk=0; wr_en=0; rd_en=0; wr_data=0; #(period*20) wr_en=1; #(period*32) wr_en=0;rd_en=1; #(period*50) wr_en=1; #(period*100) wr_en=0; #(period*150) rd_en=0; $finish; end always #(period/2) wr_clk=~wr_clk; always #(rd_period/2) rd_clk=~rd_clk; always @(posedge wr_clk) begin if(wr_en) wr_data<=wr_data+1'b1; end async_fifo #( .data_width(16), .data_depth(28), .addr_width(5), .read_width(16) ) async_fifo_inst ( .s_rstn(s_rstn), //write .wr_clk(wr_clk), .wr_en(wr_en), .wr_data(wr_data), //read .rd_clk(rd_clk), .rd_en(rd_en), .rd_data(rd_data), .out_full_w(out_full), .out_empty_w(out_empty) ); endmodule
直接用modelsim就可以仿真;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。