赞
踩
参考csdn
(1)格雷码与二进制码之间的相互转换_格雷码与二进制码的互转-CSDN博客
参考其他:
(1)【数字IC】异步FIFO设计详解(含源码) - 知乎 (zhihu.com)
异步FIFO读写采用不同的时钟,它主要有两个作用,一个是实现数据在不同时钟域进行传递,另一个作用就是实现不同数据宽度的数据接口互联。对于我本人来说,学习异步fifo主要就是为了跨时钟域数据传输。
异步FIFO主要由六部分组成:
1)写、读数据控制模块:生成写地址指针、生成写数据使能;
2)数据控制模块:生成写地址指针、生成写数据使能;
3)格雷码转换模块:将二进制码转换为格雷码;
4)格雷码同步模块:将格雷码同步到目标时钟域;
5)空满信号生成模块:读写指针经格雷码转换、同步后进行比较,生成full & empty信号;
6)数据存储模块:利用双口ram实现数据存储。
为了理解异步FIFO的工作原理,因此根据参考文章学习重写了一遍代码,下图是模块的端口定义,本文主要就异步FIFO的设计代码进行展开,包含一些我在学习过程中的理解。
这部分涉及到四个信号,读指针、写指针、full信号、empty信号。读写指针是每一次读使能或写使能时候进行+1,使得能够准确获取当前两个时钟域的数据所在的位置。
但是如果只使用到两个指针,当fifo被写满的时候再来写信号,fifo就会溢出;当fifo被读完时候再来读信号,fifo就会空读。
为了避免以上两种情况出现,加入了full和empty信号。full信号控制写指针,当高电平时表示当前fifo已经写满,不能再被写入;empty信号控制读指针,当高电平时表示当前fifo已经读空,不能再被读出。
代码实现如下:
异步fifo和同步fifo相比,会多出来一个进行格雷码转换的部分,这部分就是为了跨时钟域而设计的。由于读写指针处于不同的时钟域中,为了能够将其进行比较,必须将它们同步到对方的时钟域中。而指针出现跳变的时候有可能出现错误值,甚至多位同时跳变,出现错误的、不可控的中间值,从而产生错误的空满信号。
格雷码能够保证每次从一个值变化到相邻的一个值时,有且仅有一位发生变化,因此通过将二进制转换成格雷码,我们就可以将多bit指针同步问题转化为单bit指针同步问题。
二进制码转换成格雷码:(1)保留二进制码的最高位作为格雷码的最高位。(2)格雷码的其余位为二进制码对应位与其上一位相异或,如下图所示。
与之相反的是格雷码转换成二进制码:(1)保留格雷码的最高位作为二进制码的最高位。(2)二进制码的其余位为格雷码对应位与二进制码上一位相异或,如下图所示。本次模块设计不涉及这部分转换,仅进行学习记录。
在verilog中实现将读写指针二进制转换格雷码只需要如下:
读写指针无法直接进行比较,所以利用两级触发器,将转换为格雷码后的指针同步到目标时钟域。full信号位于写时钟域,需要将读指针同步到写时钟域后进行比较;而empty信号位于读时钟域,需要将写指针同步到读时钟域后进行比较。
采用的是打两拍消除亚稳态的形式,代码如下:
这部分我自己第一次写的时候在敏感事件列表将两个复位信号的位置写反了,其实正确的应该是写时钟和读复位,以及读时钟和写复位放在一起,复位信号需要采取的是原本时钟域的信号,而不是目标时钟域。这点很好理解,只不过写的时候很顺手就会写错,特地记录一下。
这段是原文关于这部分的内容以及示意图:
直接对同步过后的读写指针进行比较,将指针在满足双口ram深度的基础上多设计一位,读写指针各位全部相同时,代表数据被读空了,empty信号拉高,读写指针最高位、次高位(因为是格雷码)不同,其余位相同时,代表双口ram被写满,full信号拉高。
我对于这部分代码的理解是:1、在原有深度上扩充一位,最高位用于表示写指针超过读指针之后又写完了一次fifo的深度,此时按照格雷码的来说,会出现最高位次高位不同,其他位完全相同的情况。2、这样格雷码设计的时候就必须要满足fifo深度是2的幂次方的形式(实际上异步fifo本来就是有这个深度要求的),使得最高位为0和最高位为1的情况能够中心对称。
然后原文评论有一段话我觉得说的很有道理,也把它粘贴过来:“例如,本来是0-15,现在我取1-14,或者2-13,你会发现都是可以用格雷码的,而且这样深度不一定是2的幂数,但是有个条件就是,想0-15,1-14,2-13这些都是关于0-15中点对称的,你如果随便去起止点就不可以,例如1-5,这样每次每次改变就不一定是变1bit了。”
所以关于格雷码这部分的重点我的理解是:中心对称。代码实现如下:
一个双口ram,用来实现写读过程中的数据储存,这部分没什么要特别说明的,很常规的写法,代码实现如下:
以上就是关于异步fifo进行跨时钟域数据处理的全部内容,可以看到这部分有三个需要理解的重点。1、二进制源码转换成格雷码的原因。2、格雷码跨时钟域打两拍防止亚稳态。3、full信号和empty信号的定义。
最后附上异步FIFO整体代码以及测试所用tb文件,这部分也可以在原文中找到。
模块代码:
- module Async_FIFO
- #(
- parameter FIFO_DEPTH = 8,
- parameter DATA_WIDTH = 4,
- parameter PTR_WIDTH = 3
- )
- (
- input clk_r,
- input clk_w,
- input rst_r_n,
- input rst_w_n,
- input w_en,
- input r_en,
- input [DATA_WIDTH-1:0] w_data,
-
- output reg [DATA_WIDTH-1:0] r_data,
- output reg full,
- output reg empty
- );
-
- reg [PTR_WIDTH:0] w_ptr;
- reg [PTR_WIDTH:0] r_ptr;
- wire [PTR_WIDTH:0] w_ptr_gray;
- wire [PTR_WIDTH:0] r_ptr_gray;
- reg [PTR_WIDTH:0] w_ptr_gray_d1,w_ptr_gray_d2;
- reg [PTR_WIDTH:0] r_ptr_gray_d1,r_ptr_gray_d2;
- reg [DATA_WIDTH-1:0] data_mem[0:FIFO_DEPTH-1];
- reg [PTR_WIDTH:0] i;
-
-
- // write ptr control
-
- always @(posedge clk_w or negedge rst_w_n)
- begin
- if(!rst_w_n)
- begin
- w_ptr <= 0;
- end
- else if(w_en && !full)
- begin
- w_ptr <= w_ptr + 1;
- end
- end
-
- // read ptr control
-
- always @(posedge clk_r or negedge rst_r_n)
- begin
- if(!rst_r_n)
- begin
- r_ptr <= 0;
- end
- else if(r_en && !empty)
- begin
- r_ptr <= r_ptr + 1;
- end
- end
-
-
- //bin 2 gray
-
- assign w_ptr_gray = w_ptr ^ (w_ptr >> 1);
- assign r_ptr_gray = r_ptr ^ (r_ptr >> 1);
-
- // gray sync
-
- always @(posedge clk_r or negedge rst_w_n)
- begin
- if(!rst_w_n)
- begin
- w_ptr_gray_d1 <= 0;
- w_ptr_gray_d2 <= 0;
- end
- else
- begin
- w_ptr_gray_d1 <= w_ptr_gray;
- w_ptr_gray_d2 <= w_ptr_gray_d1;
- end
- end
-
- always @(posedge clk_w or negedge rst_r_n)
- begin
- if(!rst_r_n)
- begin
- r_ptr_gray_d1 <= 0;
- r_ptr_gray_d2 <= 0;
- end
- else
- begin
- r_ptr_gray_d1 <= r_ptr_gray;
- r_ptr_gray_d2 <= r_ptr_gray_d1;
- end
- end
-
-
- //full and emtpy control
-
- assign empty = r_ptr_gray == w_ptr_gray_d2;
- assign full = w_ptr_gray == {~r_ptr_gray_d2[PTR_WIDTH:PTR_WIDTH-1], r_ptr_gray_d2[PTR_WIDTH-2:0]};
-
-
- //data buf(ram)
-
- always @(posedge clk_w or negedge rst_w_n)
- begin
- if(!rst_w_n)
- begin
- for(i=0; i<FIFO_DEPTH; i=i+1)
- begin
- data_mem[i] <= 0;
- end
- end
- else if(w_en && !full)
- begin
- data_mem[w_ptr[PTR_WIDTH-1:0]] <= w_data;
- end
- end
-
- always @(posedge clk_r or negedge rst_r_n)
- begin
- if(!rst_r_n)
- begin
- r_data <= 0;
- end
- else if(r_en && !empty)
- begin
- r_data <= data_mem[r_ptr[PTR_WIDTH-1:0]];
- end
- end
-
- endmodule

tb代码:
- `timescale 1ns/1ps
-
- module tb_FIFO;
- reg w_clk_i, r_clk_i;
- reg w_rst_n_i, r_rst_n_i;
-
- reg wr_en_i ;
- reg [3:0] wr_data_i;
-
- reg rd_en_i ;
- wire [3:0] rd_data_o;
-
- wire full_o ;
- wire empty_o ;
-
- parameter w_clk_period = 1000; //1GHz时钟: T = 1000ns
- parameter r_clk_period = 500; //2GHz时钟: T = 500ns
-
-
- Async_FIFO u_Async_FIFO
- (
- .clk_w (w_clk_i ),
- .clk_r (r_clk_i ),
- .rst_w_n (w_rst_n_i),
- .rst_r_n (r_rst_n_i),
- .w_en (wr_en_i ),
- .w_data (wr_data_i),
- .r_en (rd_en_i ),
- .r_data (rd_data_o),
- .full (full_o ),
- .empty (empty_o )
- );
-
-
- // 生成写端clk:
- initial
- begin
- w_clk_i = 1'b1;
- forever
- begin
- #(w_clk_period/2) w_clk_i = ~w_clk_i;
-
- end
- end
- //生成读端clk
- initial
- begin
- r_clk_i = 1'b1;
- forever
- begin
- #(r_clk_period/2) r_clk_i = ~r_clk_i;
-
- end
- end
-
- //生成写复位、写使能、写数据
- initial
- begin
- w_rst_n_i = 1 ;
-
-
- wr_en_i = 0 ;
- wr_data_i = 4'b0;
- #(w_clk_period) w_rst_n_i = 0;
- #(w_clk_period*2) w_rst_n_i = 1;
- @(posedge w_clk_i)
- begin
- wr_en_i = 1;
- end
- @(posedge w_clk_i)
- begin
- wr_en_i = 0;
- end
- @(posedge w_clk_i)
- begin
- wr_en_i = 1;
- end
- @(posedge w_clk_i)
- begin
- wr_en_i = 0;
- end
- #(w_clk_period)
- repeat(50)
- begin
- @(posedge w_clk_i)
- begin
- wr_en_i = {$random}%2;
- wr_data_i = {$random}%5'h10;
- end
- end
-
- #(w_clk_period)
-
- @(posedge w_clk_i)
- begin
- wr_en_i = 0;
-
- end
-
- end
-
- //生成读复位、读使能
- initial
- begin
- r_rst_n_i = 1 ;
-
- rd_en_i = 0 ;
-
- #(r_clk_period) r_rst_n_i = 0;
- #(r_clk_period*2) r_rst_n_i = 1;
-
- @(posedge r_clk_i)
- begin
- rd_en_i = 0;
- end
-
- #(r_clk_period*30)
- repeat(60)
- begin
- @(posedge r_clk_i)
- begin
- rd_en_i = {$random}%2;
- end
- end
-
- #(r_clk_period*30)
-
- @(posedge r_clk_i)
- begin
- rd_en_i = 1;
- end
-
- end
-
- initial
- begin
- #(w_clk_period*125)
- $stop;
- end
-
-
- endmodule

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。