摘要:给出了一个利用格雷码对地址编码的羿步FIFO的实现方法,并给出了VHDL程序,以解决异步读写时钟引起的问题。
关键词:FIFO 双口RAM 格雷码 VHDL
FIFO (先进先出队列)是一种在电子系统得到广泛应用的器件,通常用于数据的缓存和用于容纳异步信号的频率或相位的差异。FIFO的实现通常是利用双口RAM和读写地址产生模块来实现的。FIFO的接口信号包括异步的写时钟(wr_clk)和读时钟(rd_clk)、与写时钟同步的写有效(wren)和写数据(wr_data)、与读时钟同步的读有效(rden)和读数据(rd_data)。为了实现正确的读写和避免FIFO的上溢或下溢,通常还应该给出与读时钟和写时钟同步的FIFO的空标志(empty)和满标志(full)以禁止读写操作。
1 异步FIFO功能描述
图1给出了FIFO的接口信号和内部模块图。
由图1可以看出,写地址产生模块根据写时钟和写有效信号产生递增的写地睛,读地址产生模块根据读时钟和读有效信号产生递增的读地址。FIFO的操作如下:在写时钟wr_clk的升沿,当wren有效时,将wr_data写入双口RAM中写地址对应的位置中;始终将读地址对应的双口RAM中的数据输出到读数据总线上。这样就实现了先进先出的功能。
由于空标志和满标志控制了FIFO的操作,因此标志错误会引起操作的错误。如上所述,标志的产生是通过对读写地址的比较产生的,当读写时钟完全异步时,对读写地址进行比较时,可能得出错误的结果。例如,在读地址变化过程中,由于读地址的各位变化并不同步,计算读写地址的差值,可能产生错误的差值,导致产生错误的满标志信号。若将未满标志置为满标志时,可能降低了应用的性能,降低写数据速率;而将满置标志置为未满时,执行一次写操作,则可能产生溢出错误,这对于实际应用来说是绝对应该避免的。空标志信号的产生也可能产生类似的错误。
2 异步FIFO的改进设计
从以上分析中可以看出,异步FIFO之所以会发生错误是国为在地址变化时,由于多位地址各位变化时间不同,异步时钟对其进行采样时数值可能为不同于地址变化丧后数值的其他值,异步产生错误的空标志和满标志,以致于产生FIFO的操作错误。
格雷码是一种在相邻计数值之间只有一位发生变化的编码方式。可以看出,若读写地址采用格雷码编码方式,就可以解决上面的问题。
为了应用的灵活,还增加了两个标志信号,将满(almosf_full)标志和空(almost_empty)标志分别定义如下:当写地址与读地址的距离小于某个预先定义数值时,almost_full为1;当读地址与写地址的距离小于这个预先定义的数值时,almost_empty为1。
3 异步FIFO的VHDL实现
硬件描述语言VHDL(Very-high speed IC Hardware Description Language)是一种应用于电路设计的高层次描述语言,具有行为级、寄存器传输级和门级等多层次描述,并且具有简单、易读、易修改和与工艺无关等优点。目前VHDL语言已经得到多种EDA工具的支持,综合工具得到迅速发展,VHDL语言的行为级综合也已经得到支持和实现,因此利用VHDL语言进行电路设计可以节约开发成本和周期。
首先给出格雷码和普通自然码之间的转换模块的VHDL程序。
程序1:自然码码到格雷码的转换程序
entity norm_to_gery is
generic(width:integer:=8);
port(
din:in std_logic_vector(width-1 downto 0);
dout:out std_logic_vector(width-1 downto 0);
end norm_to_grey;
architecture norm_to_grey of norm_to_grey is begin
dout<=din xor('0' & din(width-1 downto 1));
end norm_to_grey;
程序2:格雷码到自然码的转换程序
process(din)
variable tempd:std_logic;
begin
for i in width-1 downto 0 loop tempd:='0';
for j in width-1 downto i loop tempd:=tempd xor din(j);
end loop;
dout(i)<=tempd;
end loop;
end process;
在给出异步FIFO的VHDL程序之前,先给出一些内部信号的解释:
wadd ——自然码写地址
wadd_grey ——格雷码写地址
wr_radd_grey ——写时钟采样的格雷码读地址
wr_radd ——写时钟采样的自然码读地址
almost_length ——产生将满和将空标志的予定义读写地址差值
程序3:写地址产生模块,此程序同时产生写地址的自然码和格雷码
waddp<=wadd+1;
u1:norm_to_grey
port map(waddp,wadd_grey_temp);
wadd_process:process(clr,wr_clk)
begin
if clr='0'then
wadd<=(others=>'0');
wadd_grey<=(others=>'0');
elsif wr_clk'event and wr_clk='1'then
if wren='1'then
wadd<=waddp;
wadd_grey<=wadd_grey_temp;
end if;
end if;
end process;
程序4:满标志和满标志产生模块,以8位地址为例。
u2:grey_to_norm
port map(wr_radd_grey,wr_radd_temp);
process(clr,wr_clk~
begin
if clr='0'then
wr_radd_grey<=(others=>'0');
wr_radd<=(Others=>'0')
elsif wr_clk'event and wr_clk='1'then
wr_radd_grey<=radd_grey;
wr_radd<=wr_radd_temp;
end if;
end process;
wr_compare<=wadd-wr_radd;
full_process:process(clr,wr_clk)
begin
if clr='0'then
full<='0';
elsif wr_clk'event and wr_clk='1'then
if(wren='1')then
if wr_compare="11111110"then full<='1';
else full<='0';
end if;
else
if wr_compare="11111111"then full<='1';
else full<='0';
end if;
end if;
end if;
end process;
almost_full_process:process(clr,wr_clk)
begin
if clr='0' then
almost_full<='0';
elsif wr_clk'event and wr_clk='1'then
if(wren='1')then
if wr_compare>("11111110"-almost_length)then almost_full<='1';
else almost_full<='0';
end if;
else
if wr_compare>("11111111"-almost_length)then almost_full<='1';
else almost_full<='0';
end if;
end if;
end if;
end process;
读地址的产生模块和空标志及空标志的产生模块与写地址模块类似。
4 结论
为了解决FIFO的异步操作问题,本文提出了一种利用格雷码对地址进行编码的异步FIFO的设计,并采用VHDL语言进行电路设计,利用Altera公司 FLEX10KE系列FPGA得以实现,该电路软件仿真和硬件实现已经通过验证,并被应用到各种电路中。实践证明它可以解决由于异步产生的错误,同时增加了应用灵活性。