摘要:同步FIFO设计,包括所有代码,分析,以及仿真结果

FIFO介绍

  要求:存入数据按顺序排放,存储器全满时给出信号并拒绝继续存入,全空时也给出信号并拒绝读出;读出时按先进先出原则;存储数据一旦读出就从存储器中消失。

特点

  先进先出( First In First Out,FIFO)与普通存储器的区别是没有外部读写地址线,其数据地址由内部读写指针自动加减1完成。

  FIFO通常利用双口RAM和读写地址产生模块来实现其功能。
FIFO信号图

读写指针

  FIFO存储器是一个环形结构,读地址计数器和写地址计数器分别代表下一次读数据操作时的读指针和下一次写数据操作时的写指针。
这种环形结构的FIFO的特点是:数据满时,FIFO内的数据个数为总存储单元个数减1,即必须至少有一个数据为空,这是因为,如果在环形结构的FIFO没有留有一个空数据,则无法区分FIFO是空还是满这两种状态。当FIFO复位后,读地址计数器和写地址计数器复位,此时FIFO为空。
FIFO信号图
  当wr_ptr=rd_ptr时,FIFO数据为空;
  当wr_ptr-rd_ptr=M-lrd_ptr-wr_ptr=l时,FIFO数据为满;
  当wr_ptr>=rd_ptr时,wr_ptr-rd_ptr为FIFO内数据个数;
  当wr_ptr<=rd_ptr时,M-(rd_ptr-wr_ptr)为FIFO内数据个数。

模块实现

双端口RAM

端口定义

entity dualram is
	generic(widthi : positive	:=8;
			depth : positive	:=8);
	port(-----port a is only for writing
		 clka	: in STD_LOGIC;
		 wr		: in STD_LOGIC;    --写信号有效
		 addra	: in STD_LOGIC_VECTOR(depth-1 downto 0);--写指针
		 datain	: in STD_LOGIC_VECTOR(widthi-1 downto 0);
		 -----port b is only for reading
		 clkb	: in STD_LOGIC;
		 rd		: in STD_LOGIC;    --读信号有效
		 addrb	: in STD_LOGIC_VECTOR(depth-1 downto 0);--读指针
		 dataout	: out STD_LOGIC_VECTOR(widthi-1 downto 0)
		 );
end dualram;

结构体实现

architecture Behavioral of dualram is
	type ram is array(2 **3 downto 0) of STD_LOGIC_VECTOR(widthi-1 downto 0);
	signal dualram:ram;
begin
	process(clka)  --写进程
	begin
		if clka'event and clka = '1' then
			if wr='1' then
				dualram(conv_integer(addra))<=datain;
			end if;
		end if;
	end process;
	
	process(clkb)  --读进程
	begin
		if clkb'event and clkb = '1' then
			if rd='1' then
				dataout<=dualram(conv_integer(addrb));
			end if;
		end if;
	end process;
end Behavioral;

写地址计数器

端口定义

entity write_pointer is
	generic(
			depth : positive	:=8);
	port(clk	: in STD_LOGIC;
		 rst	: in STD_LOGIC;
		 wr		: in STD_LOGIC;
		 full	: in STD_LOGIC;
		 wr_pt	: out STD_LOGIC_VECTOR(depth-1 downto 0)
		 );
end write_pointer;

结构体实现

architecture Behavioral of write_pointer is
	signal wr_pt_t:STD_LOGIC_VECTOR(depth-1 downto 0);--writer pointer counter
begin
	process(clk,rst)
	begin
		if rst='1' then 
			wr_pt_t<=(others=>'0');
		elsif clk'event and clk = '1' then
			if wr='1' and full='0' then
				wr_pt_t<=wr_pt_t+1;
			end if;
		end if;
	end process;
wr_pt<=wr_pt_t;
end Behavioral;

读地址计数器

端口定义

entity read_pointer is
	generic(
			depth : positive	:=8);
	port(clk	: in STD_LOGIC;
		 rst	: in STD_LOGIC;
		 rq		: in STD_LOGIC;
		 empty		: in STD_LOGIC;
		 rd_pt	: out STD_LOGIC_VECTOR(depth-1 downto 0)
		 );
end read_pointer;

结构体实现

architecture Behavioral of read_pointer is
signal rd_pt_t:STD_LOGIC_VECTOR(depth-1 downto 0);--read_pointer counter
begin
	process(clk,rst)
	begin
		if rst='1' then 
			rd_pt_t<=(others=>'0');
		elsif clk'event and clk = '1' then
			if rq='1' and empty='0'then
				rd_pt_t<=rd_pt_t+1;
			end if;
		end if;
	end process;
rd_pt<=rd_pt_t;

end Behavioral;

空满状态产生器

端口定义

entity judge_status is
	generic(
			depth : positive	:=8);
	port(clk	: in STD_LOGIC;
		 rst	: in STD_LOGIC;
		 wr_pt	: in STD_LOGIC_VECTOR(depth-1 downto 0);
		 rd_pt	: in STD_LOGIC_VECTOR(depth-1 downto 0);
		 empty	: out STD_LOGIC;
		 full	: out STD_LOGIC
		 );
end judge_status;

结构体实现

architecture Behavioral of judge_status is

begin
	process(clk,rst)--空状态产生
	begin
		if rst='1' then 
			empty<='1';
		elsif clk'event and clk = '1' then
			if wr_pt=rd_pt then
				empty<='1';
			else
				empty<='0';
			end if;
		end if;
	end process;
	
	process(clk,rst)--满状态产生
	begin
		if rst='1' then 
			full<='1';
		elsif clk'event and clk = '1' then
			if wr_pt>rd_pt then
				if (rd_pt+depth)=wr_pt then
					full<='1';
				else
					full<='0';
				end if;
			else
				if (wr_pt+1)=rd_pt then
					full<='1';
				else
					full<='0';
				end if;
			end if;
		end if;
	end process;
end Behavioral;

顶层模块(连线)

端口定义

entity fifo_all is
	generic(widthi : positive	:=8;
			depth : positive	:=8);
	port(-----port a is only for writing
		 clk	: in STD_LOGIC;
		 rst	: in STD_LOGIC;
		 wr		: in STD_LOGIC;
		 rd		: in STD_LOGIC;
		 datain	: in STD_LOGIC_VECTOR(widthi-1 downto 0);
		 dataout: out STD_LOGIC_VECTOR(widthi-1 downto 0);
		 empty_out	: out STD_LOGIC;
		 full_out	: out STD_LOGIC
		 );
end fifo_all;

内部实现

signal full,empty : std_logic;
signal rd_pt	: STD_LOGIC_VECTOR(depth-1 downto 0);
signal wr_pt	: STD_LOGIC_VECTOR(depth-1 downto 0);
begin

judge_status0: judge_status port map(clk,rst,wr_pt,rd_pt,empty,full);
dualram0: dualram port map(clk,wr,wr_pt,datain,clk,rd,rd_pt,dataout);
read_pointer0:read_pointer port map(clk,rst,rd,empty,rd_pt);
write_pointer0:write_pointer port map(clk,rst,wr,full,wr_pt);
empty_out<=empty;
full_out<=full;   

仿真结果

  可以看到,写进去的数据被依次读取除来了;
FIFO信号图
  而以上代码有错误,错误在空间写满后如果wr信号如果有效,会覆盖上次写的数据,而事实上此次写不应该有效。修改方法是在双端口rom里引入empty,full信号判断作为是否写和读的条件判断。