Verilog学习笔记简单功能实现(八)...............同步FIFO
Part 1,功能定义:
用16*8 RAM实现一个同步先进先出(FIFO)队列设计。由写使能端控制该数据流的写入FIFO,并由读使能控制FIFO中数据的读出。写入和读出的操作(高电平有效)由时钟的上升沿触发。当FIFO的数据满和空的时候分别设置相应的高电平加以指示。FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
所谓同步FIFO是指读时钟和写时钟采用同一个时钟。同时,异步FIFO就是指读写时钟不一致。
Part 2.顶层信号定义:
信号名称 |
I/O |
功能描述 |
源/目标 |
备注 |
Rst |
In |
全局复位(低有效) |
管脚 |
|
Clk |
In |
全局时钟 |
管脚 |
频率10Mhz;占空比:50% |
W_en |
In |
高有效写使能 |
管脚 |
|
R_en |
In |
高有效读使能 |
管脚 |
|
Data_in[7:0] |
In |
数据输入端 |
管脚 |
|
Data_out[7:0] |
Out |
数据输出端 |
管脚 |
|
Empty |
Out |
空指示信号 |
管脚 |
为高时表示fifo空 |
Full |
Out |
满指示信号 |
管脚 |
为高时表示fifo满 |
Part 3.顶层模块即划分:
该同步fifo可划分为如下四个模块,如图所示:
①存储器模块(RAM) ——用于存放及输出数据;
②读地址模块(r_addr) ——用于读地址的产生;
③写地址模块(w_addr)——用于写地址的产生
④标志模块(flag_gen) ---- 用于产生FIFO当前空满状态。
Part 4.RAM块:
RAM块的源码
本设计中采用16*8的双扣RAM,以循环读写的方式实现。
根据r_addr模块产生的读地址在,读使能(ren==1)时,将r_addr[4:0]地址中的对应单元的数据在时钟上升沿到来时,读出到data_out[7:0]中;
根据w_addr模块产生的写地址,在写实能(wen==1)时,在时钟沿的上升沿到来时,将data_in[7:0]中的数据写入到w_addr[4:0]地址对应的单元。
1 //16*8 RAM define (七个端口) 2 module RAM(clk,ren,wen,r_addr,w_addr,data_in,data_out); 3 input clk,ren,wen; 4 input [4:0]r_addr,w_addr; 5 input [7:0]data_in; 6 output [7:0]data_out; 7 reg [7:0]data_out; 8 reg [7:0]fifo[15:0]; 9 always @(posedge clk) 10 begin 11 if(ren==1) 12 begin data_out<=fifo[r_addr]; end 13 end 14 always @(posedge clk) 15 begin 16 if(wen==1) 17 begin fifo[w_addr]<=data_in; end 18 end 19 endmodule
Part 5.r_addr产生块:
该模块用于产生FIFO读数据时所用的地址。由于16个RAM单元可以用4位地址线寻址。本模块用5位计数器(rd_addr[4:0])实现读地址的产生。
在复位时(rst=0),读地址值为0。
如果FIFO未空(~empty)且有读使能(r_en)有效,则r_addr[4:0]加1;否则不变。
1 //read address genaration 2 module r_addr_gen(clk,rst,ren,r_addr,empty); 3 input clk,rst,ren,empty; 4 output [4:0]r_addr; 5 reg [4:0]r_addr; 6 always @(posedge clk) //negedge rst can be here to make it asynchronous 7 begin 8 if (!rst) begin r_addr<=5'b00000; end 9 else if(ren==1&&empty==0) begin r_addr<=r_addr+1;end 10 else begin r_addr<=5'b00000; end 11 end 12 endmodule
Part 6.w_addr产生块:
该模块用于产生FIFO写数据时所用的地址。由于16个RAM单元可以用4位地址线寻址。
在复位时(rst=0),写地址值为0。
如果FIFO未满(~full)且有写使能(w_en)有效,则w_addr[4:0]加1;否则不变。
1 //write address genaration 2 module w_addr_gen(clk,rst,wen,w_addr,full); 3 input clk,rst,wen,full; 4 output [4:0]w_addr; 5 reg [4:0]w_addr; 6 always @(posedge clk) //negedge rst can be here to make it asynchronous 7 begin 8 if (!rst) begin w_addr<=5'b00000; end 9 else if(wen==1&&full==0) begin w_addr<=w_addr+1;end 10 else begin w_addr<=5'b00000; end 11 end 12 endmodule
Part 7.空满标志产生块:
flag_gen模块产生FIFO空满标志。本模块设计并不用读写地址判定FIFO是否空满。设计一个计数器,该计数器(pt_cnt)用于指示当前周期中FIFO中数据的个数。由于FIFO中最多只有16个数据,因此采用5位计数器来指示FIFO中数据个数。具体计算如下:
1)复位的时候,count=0;
2)如果w_en和r_en同时有效的时候,count不加也不减;表示同时对FIFO进行读写操作的时候,FIFO中的数据个数不变。
3)如果w_en有效且full=0,则count+1;表示写操作且FIFO未满时候,FIFO中的数据个数增加了1;
4)如果r_en有效且empty=0,则count-1; 表示读操作且FIFO未满时候,FIFO中的数据个数减少了1;
5)如果count=0的时候,表示FIFO空,需要设置empty=1;如果count=16的时候,表示FIFO现在已经满,需要设置full=1。
1 //empty and full flag gennaration 2 module flag_gen(clk,rst,ren,wen,empty,full); 3 input clk,ren,wen,rst; 4 output empty,full; 5 reg empty,full; 6 reg [4:0]count; 7 parameter max=5'b01111; 8 9 always @(posedge clk) 10 begin 11 if(!rst) begin count<=0;end 12 else case({ren,wen}) 13 2'b00: count<=count; 14 2'b01: if(count!=max) count<=count+1; 15 2'b10: if(count!=5'b0)count<=count-1; 16 2'b11: count<=count; 17 default:count<=count; 18 endcase 19 end 20 21 always @(count) 22 begin 23 if (count==max) full<=1; 24 else full<=0; 25 end 26 27 always @(count) 28 begin 29 if (count==5'b0) empty<=1; 30 else empty<=0; 31 end 32 endmodule