赞
踩
FIFO:first in,first out;数据先进先出,后进后出,是一种传统的顺序执行方法,本质上是一种双口数据缓存器,没有外部地址(由内部指针递增来充当数据地址),只能顺序写入,顺序读取,因此不能写入或读取指定地址里的数据。
在系统设计时,包含很多工作在不同时钟频率下的元件,如处理器、外设等,可能有自己的时钟振荡器,不同模块处理速度有快有慢,但是每个模块各自时钟不间歇,如果模块之间有数据交互,会造成计算紊乱,这也就是跨时钟域要解决的问题,当数据量很大,数据传输速率要求高,需要匹配不同传输速率的系统时,FIFO是处理此类问题的优解。
Uart全称为通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种通用串行数据总线,先将接收到的并行数据转成串行进行传输,然后再将串行转成并行数据,在两个uart设备之间通信,指定相同传输速率(波特率)、起始位结束位等,遵循同一通信协议。
FIFO本质上只是一个缓冲器,如果CPU处理uart数据绰绰有余,可以不用FIFO的帮助,如果在复杂系统中,CPU工作量太大,那么CPU在处理别的任务时,就会时常被收发数据中断,导致CPU工作效率很低,这时通过FIFO来缓冲,存下若干数据再集中处理就很有必要了。
FIFO和uart可以联合工作,提高收发效率。
读取与写入的时钟相同,可以用计数器或读写指针来判断空满
读取与写入的时钟不同,需要用到同步器、gray码来减少亚稳态的产生,用指针的gray来判断空满,避免使用二进制指针比较空满,这会导致指针值取样错误。
宽度:FIFO存储的每个数据的位宽
深度:FIFO存储数据的个数
写满标志:满标志拉高,则无法继续写入
若[写域写指针(gray)== 写域读指针(gray)],则full==1
读空标志:空标志拉高,则无法继续读取
若[读域读指针(gray)== 读域写指针(gray)],则null==1
写指针(写域):每存入一个数据,写指针递增1,
读指针(读域):每读取一个数据,读指针递增1
写指针(读域):将写域写指针转化成gray码同步到读域
读指针(写域):将读域读指针转化成gray码同步到写域
指针位数要比FIFO深度多一位用来判断空满!
产生可靠的空满标志是设计FIFO的关键!
格雷码是一种绝对编码方式,它的循环、单步特性消除了随机取数时出现重大误差的可能,是一种可靠的、错误最小化的编码方式,在相邻位间转换时,只有一位产生变化,出错可能大大降低。
红框与绿框里的格雷码体现了极美的对称性,最高位MSB红框为0,绿框为1,剩下的3位LSB相同。
转化公式:
bnary to Gray
g(3) = b(3) ^ 0
g(2) = b(3) ^ b(2)
g(1) = b(2) ^ b(1)
g(0) = b(1) ^ b(0)
g(n) = b(n+1) ^ b(n)
Gray to Binary
b(3) = g(3)
b(2) = g(3) ^ g(2)
b(1) = g(3) ^ g(2) ^ g(1)
b(0) = g(3) ^ g(2) ^ g(1) ^ g(0)
FIFO读空条件:write pointer == read pointer
FIFO写满条件:
1、FIFO的深度==2的幂次
假设深度为8的FIFO一开始就只写不读,写满8个后,写指针gray码为4’b1100,此时读指针是4’b0000; 再假设读指针停在4’b0011,写指针写到4‘b1111,
则此时FIFO写满。可以读写指针看到高两位相反,剩下位数相同。因此写满标志条件: (写域写指针高两位==~写域读指针高两位)&&(写域写指针剩余LSB==写域读指针剩余LSB)
2、FIFO的深度!=2的幂次
若FIFO深度为7,则首尾向内收缩一位,即4’b0001与4‘b1001,这样可以保证只有最高位取反,其余相等,深度为6同理,如红色箭头所示,收缩两位。
仿真时,如果写时钟快于读时钟,仿真图里将写指针同步到读域时,发现漏读了指针,不要惊慌!这个问题肯定会发生,基本无法解决,但是不会对读取数据产生影响,因为同步写指针到读域时,写指针还在按自己的时钟递增,读域采到的写指针数值肯定不会大于此刻写域的写指针。
这个主要影响判断读空的条件,可能会产生假空的状态,而实际上FIFO并没有空,此时读数据就会停止,直到空标志拉低,再继续读即可。
同理,如果读时钟快于写时钟,可能会出现假满状态,也不会影响读数据。
代码
module fifo #( parameter WSIZE = 8, //the width of fifo parameter DSIZE = 5 //the depth of fifo ) ( input sys_rst_n, //write input wclk, //clk of writing input w_en, //en of writing input wire [WSIZE-1:0]wdata, //data of writing output w_full, //the signal of writing fully //read input rclk, //clk of reading input r_en, //en of reading output reg [WSIZE-1:0]rdata, //data of reading output r_null, //the signal of reading nully output reg r_valid //Read the data validly ); //buffer reg [WSIZE-1:0]buffer[(1<<DSIZE)-1:0]; //Pay attention to this writing //reg of write wire [DSIZE:0]gwptr; //gray code of Writing pointer reg [DSIZE:0]bwptr, //binary code of Writing pointer bwptr_rclk, //binary code of Writing pointer of reading clk gwptr_wclk_1, //gray code of Writing pointer for hitting 1 beat gwptr_rclk_1, //gray code of reading pointer for hitting 1 beat gwptr_rclk_2; //gray code of reading pointer for hitting 2 beat //reg of read wire [DSIZE:0]grptr; //gray code of reading pointer reg [DSIZE:0]brptr, //binary code of reading pointer brptr_wclk, //binary code of reading pointer of writing clk grptr_rclk_1, //gray code of reading pointer for hitting 1 beat grptr_wclk_1, //gray code of Writing pointer for hitting 1 beat grptr_wclk_2; //gray code of Writing pointer for hitting 2 beat //b to g assign gwptr = (bwptr >> 1) ^ bwptr; //write pointers to convert to Gray code assign grptr = (brptr >> 1) ^ brptr; //read pointers to convert to Gray code //write the pointer Gray code in the read field to play two beats always @(posedge rclk, negedge sys_rst_n) begin if(~sys_rst_n) begin gwptr_rclk_1 <= 0; gwptr_rclk_2 <= 0; end else begin gwptr_rclk_1 <= gwptr; gwptr_rclk_2 <= gwptr_rclk_1; end end //read the pointer Gray code in the write field to play two beats always @(posedge wclk, negedge sys_rst_n) begin if(~sys_rst_n) begin grptr_wclk_1 <= 0; grptr_wclk_2 <= 0; end else begin grptr_wclk_1 <= grptr; grptr_wclk_2 <= grptr_wclk_1; end end //Judge full assign w_full = ((gwptr[DSIZE:DSIZE-1] == ~grptr_wclk_2[DSIZE:DSIZE-1]) && (gwptr[DSIZE-2:0] == grptr_wclk_2[DSIZE-2:0])); //Judge null assign r_null = (grptr == gwptr_rclk_2)? 1'd1 : 1'd0; //write pointer always @(posedge wclk, negedge sys_rst_n) begin if(~sys_rst_n) begin bwptr <= 0; end else if(~w_full && w_en) begin bwptr <= bwptr + 1; end else begin bwptr <= bwptr; end end //read pointer always @(posedge rclk, negedge sys_rst_n) begin if(~sys_rst_n) begin brptr <= 0; end else if(~r_null && r_en) begin brptr <= brptr + 1; end else begin brptr <= brptr; end end //module memory (); initial begin $readmemb("C:/Users/86152/Desktop/FIFO/CODE/doc/memory.txt", buffer); end //write data always @(posedge wclk, negedge sys_rst_n) begin if(~w_full && w_en) begin buffer[bwptr[DSIZE-1:0]] <= wdata; //!This expression is ture end end //read data always @(posedge rclk, negedge sys_rst_n) begin if(~r_null && r_en) begin rdata <= buffer[brptr[DSIZE-1:0]]; r_valid <= 1'd1; end else begin r_valid <= 1'd0; rdata <= rdata; end end endmodule
tb
`timescale 1ns/1ns module fifo_tb; //SIZE parameter WSIZE = 8; //the width of fifo parameter DSIZE = 5; //the depth of fifo //system reg sys_rst_n; //write reg wclk; //clk of writing reg w_en; //en of writing reg [WSIZE-1:0]wdata; //data of writing wire w_full; //the signal of writing fully //read reg rclk; //clk of reading reg r_en; //en of reading wire [WSIZE-1:0]rdata; //data of reading wire r_null; //the signal of reading nully wire r_valid; //Read the data validly initial begin sys_rst_n <= 1'b0; //clk wclk <= 1'b0; rclk <= 1'b0; //en w_en <= 1'b0; r_en <= 1'b0; #10 sys_rst_n <= 1'b1; w_en <= 1'b1; //just write r_en <= 1'b0; #64 w_en <= 1'd0; //write fully and then read completely r_en <= 1'b1; #192 w_en <= 1'd1; //just write r_en <= 1'b0; #40 w_en <= 1'd1; //write and read r_en <= 1'b1; #36 w_en <= 1'd0; //just read r_en <= 1'b1; #40 w_en <= 1'd1; //just r_en <= 1'b1; end //wclk always #1 wclk <= ~wclk; //rclk always #3 rclk <= ~rclk; //wdata always @(posedge wclk, negedge sys_rst_n) begin if(~sys_rst_n) begin wdata <= 8'b000_1111; end else begin wdata <= wdata + 8'd1; end end fifo fifo_tb( .sys_rst_n(sys_rst_n), .wclk(wclk), .w_en(w_en), .wdata(wdata), .w_full(w_full), .rclk(rclk), .r_en(r_en), .rdata(rdata), .r_null(r_null), .r_valid(r_valid) ); endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。