同步FIFO
同步FIFO相对异步FIFO较为简单,FIFO:先入先出
FIFO原则:满不能写,空不能读。
关键:full和empty信号如何产生?
方法1:用长度计数器factor。执行一次写操作,factor加1,执行一次读操作,factor减1。
方法2:地址位扩展一位,用最高位来判断空满。读地址=写地址,则空;读地址与写地址相差一个存储空间长度,则满。
对于方法1来说比较简单,本文重点讲异步FIFO,对于同步FIFO我们给出伪代码,读者自行补全该模块全部代码。
异步FIFO
异步FIFO的整体结构大致如下:
Write_control:控制写操作与满信号(w_full)的判断与产生。
Read_control:控制读操作与空信号(r_empty)的判断与产生。
RAM:双端口数据存取RAM。
Bin_to_gray:二进制码转格雷码模块。用于将读写地址二进制码转成格雷码。
SYN:跨时钟同步模块,即将读地址的格雷码(r_g_addr)向w_clk同步;将写地址的格雷码(w_g_addr)向r_clk同步。主要操作就是通过寄存器打两拍。
使用扩展地址位来判断空满,读写信号时钟不同。
关键在于格雷码使用,同步可以不用格雷码,异步两时钟不一样,采用出错概率大,普通二进制码会出现多个错误,而格雷码每次跳转只会有一位发生变化,出错概率小且顶多是使得FIFO的读或者写操作暂停。
详细解释:
在中间状态采样,这个是不可能避免的,这是异步系统天生的缺陷。我们的目标是:即使在中间状态采样,也不能影响空满状态的判断。符合这个要求的编码方式是:每次只能有1个bit发生改变。为什么这么说呢?因为当只有一一个bit发生改变时,即使在中间状态采样,其结果也不外乎两种:递增前原指针和递增后新指针。显然递增后新指针是最新情况的反映,如果采样到这个指针,那么和我们的设计预期是一致的,如果采样到递增前的原指针,会有什么结果呢?假设现在采样读指针,那么最坏的情况就是把“不满”判断成了“满”,使得本来被允许的写操作被禁止了,但是这并不会对逻辑产生影响,只是带来了写操作的延迟。同样的,如果现在采样写指针,那么最坏的情况就是把“不空”判断成“空”,使得本来被允许的读操作被禁止了,但是这也不会对逻辑产生影响,只是带来了读操作的延迟
显然每次之变化1个bit的编码方案可以有效解决中间态下空满状态的判断问题,格雷码就是这样一种编码。
关键点解释
1.跨时钟域传递信号做时钟同步一般通过打两拍。
2.采用格雷码编码(解决汇聚问题),因为格雷码每次跳转只会有一位发生变化,所以如果出现不确定状态也只会有两种状况,即正确变化了和不变。因此在读写时钟不一样的情况下,纵使读写地址每bit同步过程中出现延时不一致,也不会使得FIFO在实际空或者满之后,FIFO却没有正确的产生出空满信号。只有可能是实际没有空或者满,但产生了空满信号,但这对于FIFO的功能不会有影响,只会使得FIFO的读或者写操作暂停。
3.读比写时钟更快,只会只出现实际没满,但误判为满;不会对功能(数据流)造成错误。
4.写比读时钟更快,只会出现实际没空,但误判为空;不会对功能(数据流)造成错误。
verilog格雷码生成
观察下面码表,格雷码最高位与原码一致,其它位对应原码相邻两位相互异或的结果
module bin_to_gray #(
parameter WIDTH_D = 5
)(
input [WIDTH_D-1:0] bin_c,
output [WIDTH_D-1:0] gray_c
);
wire h_b;
assign h_b = bin_c[WIDTH_D-1];
reg [WIDTH_D-2:0] gray_c_d;
integer i;
always @( * )
for( i=0;i<WIDTH_D-1;i=i+1 )
gray_c_d[i] = bin_c[i]^bin_c[i+1];
assign gray_c = {h_b,gray_c_d};
endmodule
评论 (0)