异步fifo程序
异步fifo的uvm验证原理
异步fifo的uvm验证原理异步FIFO(First-In-First-Out,先进先出)是一种常用的数据缓冲区结构,常用于解决不同速率的数据传输问题。
UVM (Universal Verification Methodology,通用验证方法学)是一种系统级验证方法学,用于验证硬件设计。
在UVM中,对异步FIFO的验证需要对FIFO的功能和时序进行验证。
以下是异步FIFO的UVM验证原理:1. 创建FIFO模型:首先,需要创建一个FIFO模型,包括FIFO的输入端口和输出端口,以及FIFO的内部数据存储器。
可以使用SystemVerilog语言创建FIFO模型。
2. 编写验证环境:在UVM中,需要编写一个验证环境(testbench),用于生成测试用例,驱动输入数据到FIFO中,并验证FIFO的输出数据是否符合预期。
验证环境包括以下组件:- 驱动(driver):负责将测试向量输入到FIFO中。
- 监视器(monitor):监控FIFO的输出数据,并将其与预期结果进行比较。
- 预测器(predictor):根据输入数据预测FIFO的输出结果。
- 生成器(generator):生成各种测试用例。
3. 设置时序约束:对于异步FIFO的验证,需要设置时序约束,以确保FIFO的输入和输出数据能够按照预期的时序要求进行传输。
时序约束包括FIFO的读写时钟频率和时钟间隔等参数。
4. 进行功能验证:验证FIFO的功能,包括数据的读写操作是否正确,数据的顺序是否符合FIFO原则等。
可以通过在测试用例中使用不同的输入数据和读写操作顺序来验证FIFO的功能。
5. 进行时序验证:验证FIFO的时序,包括输入数据的时序要求是否满足,输出数据的时序是否符合预期。
可以通过在测试用例中使用不同的时序生成输入数据来验证FIFO的时序。
6. 进行性能验证:验证FIFO的性能,包括写入速率和读出速率是否满足要求,以及FIFO的深度是否足够。
quartus 异步fifo用法
quartus 异步fifo用法在Quartus中使用异步FIFO,可以通过IP Core Catalog中的"ALTAsyncFIFO"来实现。
以下是使用异步FIFO的步骤:1. 打开Quartus Prime软件。
点击"File"菜单,选择"New Project"来创建一个新的项目。
2. 在"New Project Wizard"中,选择项目的名称、储存位置和顶层实体的文件。
点击"Next"继续。
3. 在"Add Files"步骤中,添加设计文件,包括顶层实体和其他组件文件。
点击"Next"继续。
4. 在"Family and Device Settings"步骤中,选择您的目标FPGA 器件。
点击"Next"继续。
5. 在"EDA Tool Settings"步骤中,选择Quartus使用的EDA工具。
点击"Next"继续。
6. 在"Summary"步骤中,查看项目设置的摘要。
点击"Finish"完成项目创建。
7. 在Quartus主界面的左侧面板中,点击"IP"选项卡,然后选择"Library"。
在IP Core Library窗口中,搜索"ALTAsyncFIFO"。
8. 在搜索结果中,选择"ALTAsyncFIFO"并点击"OK"来添加该IP到项目中。
9. 在设计文件中实例化ALTAsyncFIFO组件。
可以使用Quartus的"IP Catalog"来生成实例化代码。
10. 配置ALTAsyncFIFO的参数,包括FIFO大小、输出宽度、寄存器位宽等。
quartus 异步fifo用法 -回复
quartus 异步fifo用法-回复quartus异步FIFO用法引言:在数字电路设计中,FIFO(First In First Out)是一种常见的数据存储器,它允许数据以先进先出的顺序进出。
在使用Quartus进行FPGA设计时,异步FIFO是一种非常有用的工具,它可以帮助我们处理不同速度的数据流,并实现数据的缓冲和流量控制。
本文将介绍Quartus异步FIFO的基本概念和使用方法,并给出一些实例。
第一部分:Quartus异步FIFO概述1.1 什么是异步FIFO?异步FIFO是一种数据存储器,在其中数据可以以不同速度进入和退出。
与同步FIFO不同,异步FIFO的读写时钟可以是不同的,这使得它可以处理速度不匹配的数据流。
Quartus提供了异步FIFO的库函数和IP核,使得它可以在FPGA设计中方便地使用。
1.2 Quartus异步FIFO的特点Quartus异步FIFO具有以下特点:- 可以使用不同的时钟频率进行读写操作。
- 可以配置不同的缓冲深度来满足特定的设计需求。
- 可以实现流量控制和数据的重排序。
- 可以支持并行读写和读写使能信号。
- 可以适应不同的数据宽度和时钟域要求。
第二部分:Quartus异步FIFO的使用方法2.1 创建异步FIFO在Quartus中创建异步FIFO的方式有两种:使用库函数和使用IP核。
使用库函数创建异步FIFO的步骤如下:- 首先,在Quartus中打开设计工程,并创建一个新的源文件。
- 然后,将异步FIFO的库函数导入到源文件中,以便在设计中调用它。
- 接着,实例化异步FIFO,并通过参数配置其属性,例如宽度,深度,时钟域等。
- 最后,将异步FIFO连接到其他逻辑模块,完成设计。
使用IP核创建异步FIFO的步骤如下:- 首先,在Quartus中打开设计工程,并创建一个新的IP核。
- 然后,在IP核的界面中选择合适的FIFO类型和配置参数。
- 接着,将异步FIFO实例化到设计中,将其连接到其他逻辑模块。
跨时钟域之异步FIFO
跨时钟域之异步FIFOAsynchronous FIFO Design异步FIFO的读写指针写指针写指针指向当前将要写⼊数据的位置,复位之后,读写指针被置零。
执⾏写操作的时候,向写指针指向的存储区写⼊数据,之后写指针加1,指向接下来要被写⼊数据的位置。
On a FIFO-write operation, the memory location that is pointed to by the write pointer is written, and then the write pointer is incremented to point to the next location to be written.读指针:读指针指向当前要被读取数据的位置,复位时,读写指针被置零,FIFO为空读指针指向⼀个⽆效的数据(FIFO为空,empty信号有效——拉⾼)。
当第⼀个有效数据被写⼊FIFO之后,写指针增加,empty flag信号被拉低,且读指针⼀直指向FIFO第⼀FIFO空标志:当读写指针是相等的时候:分两种情况1.当读写指针执⾏复位操作的时候。
2.当读指针赶上写指针的时候,最后⼀笔数据从FIFO读出后FIFO为空FIFO满标志:读写指针相等,当FIFO⾥⾯的写指针写满⼀圈之后⼜转回到和读指针同样的位置。
有个问题,读写指针相等的时候怎么判断FIFO是empty还是full?设计的时候增加⼀位bit去辅助判断FIFO是空还是满。
当写指针超过FIFO的最⼤寻址范围时,写指针将使辅助位zhi⾼,其余位为0.FIFO满的时候:读写指针的低位(n-1位bit)相等,⾼位(第n位bit)不同。
FIFO空的时候,读写指针的低位和⾼位都相等。
(针对⼆进制)但是⼆进制FIFO指针综合电路复杂,⼀般采⽤**格雷码**,⽂章中采⽤⼆进制转换格雷码的⽅法,判断FIFO的空满标志4位⼆进制格雷码,有效地址位为三位。
⼆进制转换为格雷码的算法:rgraynext = (rbinnext>>1) ^ rbinnext;1.顶层模块fifo:例化各个⼦模块//顶层模块实例化各个⼦模块module fifo#(parameter DSIZE = 8, //读写数据位宽均设置为8位parameter ASIZE = 4 // 存储地址位宽设置)(output [DSIZE-1:0] rdata,output wfull,output rempty,input [DSIZE-1:0] wdata,input winc, wclk, wrst_n,input rinc, rclk, rrst_n);wire [ASIZE-1:0] waddr, raddr;wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;// 内部线⽹// synchronize the read pointer into the write-clock domainsync_r2w sync_r2w(.wq2_rptr (wq2_rptr),.rptr (rptr ),.wclk (wclk ),.wrst_n (wrst_n ));// synchronize the write pointer into the read-clock domainsync_w2r sync_w2r(.rq2_wptr(rq2_wptr),.wptr(wptr),.rclk(rclk),.rrst_n(rrst_n));//this is the FIFO memory buffer that is accessed by both the write and read clock domains.//This buffer is most likely an instantiated, synchronous dual-port RAM.//Other memory styles can be adapted to function as the FIFO buffer.fifomem#(DSIZE, ASIZE)fifomem(.rdata(rdata),.wdata(wdata),.waddr(waddr),.raddr(raddr),.wclken(winc),.wfull(wfull),.wclk(wclk));//this module is completely synchronous to the read-clock domain and contains the FIFO read pointer and empty-flag logic.rptr_empty#(ASIZE)rptr_empty(.rempty(rempty),.raddr(raddr),.rptr(rptr),.rq2_wptr(rq2_wptr),.rinc(rinc),.rclk(rclk),.rrst_n(rrst_n));//this module is completely synchronous to the write-clock domain and contains the FIFO write pointer and full-flag logicwptr_full#(ASIZE)wptr_full(.wfull(wfull),.waddr(waddr),.wptr(wptr),.wq2_rptr(wq2_rptr),.winc(winc),.wclk(wclk),.wrst_n(wrst_n));endmodule2.时钟域同步模块sync_r2w:读指针同步到写时钟域wclk// 采⽤两级寄存器同步读指针到写时钟域module sync_r2w#(parameter ADDRSIZE = 4)(output reg [ADDRSIZE:0] wq2_rptr, //读指针同步到写时钟域input [ADDRSIZE:0] rptr, // 格雷码形式的读指针,格雷码的好处后⾯会细说input wclk, wrst_n);reg [ADDRSIZE:0] wq1_rptr;always @(posedge wclk or negedge wrst_n)if (!wrst_n) beginwq1_rptr <= 0;wq2_rptr <= 0;endelse beginwq1_rptr<= rptr;wq2_rptr<=wq1_rptr;endendmodule原理图3.时钟域同步模块sync_w2r:写指针同步到读时钟域rclk//采⽤两级寄存器同步写指针到读时钟域module sync_w2r#(parameter ADDRSIZE = 4)(output reg [ADDRSIZE:0] rq2_wptr, //写指针同步到读时钟域input [ADDRSIZE:0] wptr, //格雷码形式的写指针input rclk, rrst_n);reg [ADDRSIZE:0] rq1_wptr;always @(posedge rclk or negedge rrst_n)if (!rrst_n)beginrq1_wptr <= 0;rq2_wptr <= 0;endelse beginrq1_wptr <= wptr;rq2_wptr <= rq1_wptr;endendmoduleRTL原理图4.存储模块//存储模块module fifomem#(parameter DATASIZE = 8, // Memory data word widthparameter ADDRSIZE = 4 // 深度为8即地址为3位即可,这⾥多定义⼀位的原因是⽤来判断是空还是满,详细在后⽂讲到) // Number of mem address bits(output [DATASIZE-1:0] rdata,input [DATASIZE-1:0] wdata,input [ADDRSIZE-1:0] waddr, raddr,input wclken, wfull, wclk);////////////////////////////////这部分没⽤到,可以单独写⼀个模块来调⽤//////////////`ifdef RAM //可以调⽤⼀个RAM IP核// instantiation of a vendor's dual-port RAMmy_ram mem(.dout(rdata),.din(wdata),.waddr(waddr),.raddr(raddr),.wclken(wclken),.wclken_n(wfull),.clk(wclk));//////////////////////////这部分没⽤到,可以单独写⼀个模块来调⽤//////////////////`else //⽤数组⽣成存储体// RTL Verilog memory modellocalparam DEPTH = 1<<ADDRSIZE; // 左移相当于乘法,2^4 将1左移4位reg [DATASIZE-1:0] mem [0:DEPTH-1]; //⽣成2^4个位宽位8的数组assign rdata = mem[raddr];always @(posedge wclk) //当写使能有效且还未写满的时候将数据写⼊存储实体中,注意这⾥是与wclk同步的if (wclken && !wfull)mem[waddr] <= wdata;`endifendmodule原理图5. rptr_empty模块:产⽣rempty和raddr信号//产⽣empty信号和raddar信号的模块module rptr_empty#(parameter ADDRSIZE = 4)(output reg rempty,output [ADDRSIZE-1:0] raddr, //⼆进制形式的读指针output reg [ADDRSIZE :0] rptr, //格雷码形式的读指针input [ADDRSIZE :0] rq2_wptr, //同步后的写指针同步到读时钟域input rinc, rclk, rrst_n);reg [ADDRSIZE:0] rbin;wire [ADDRSIZE:0] rgraynext, rbinnext;// GRAYSTYLE2 pointer//将⼆进制的读指针与格雷码进制的读指针同步always @(posedge rclk or negedge rrst_n)if (!rrst_n) beginrbin <= 0;rptr <= 0;endelse beginrbin<=rbinnext; //直接作为存储实体的地址rptr<=rgraynext;//输出到 sync_r2w.v模块,被同步到 wrclk 时钟域end// Memory read-address pointer (okay to use binary to address memory)assign raddr = rbin[ADDRSIZE-1:0]; //直接作为存储实体的地址,⽐如连接到RAM存储实体的读地址端。
uart fifo 流程
uart fifo 流程UART FIFO流程一、引言UART(通用异步收发传输器)是一种常用的串行通信协议,用于在嵌入式系统中实现设备之间的数据传输。
其中,FIFO(First In First Out)是一种常见的数据缓冲区,用于解决数据传输过程中的速度不匹配问题。
本文将介绍UART FIFO的工作原理和流程。
二、UART FIFO的概念UART FIFO是一种先进先出的数据缓冲区,用于存储待发送或已接收的数据。
它的主要作用是解决数据传输过程中速度不匹配的问题。
当发送端和接收端的数据传输速度不一致时,FIFO可以暂时存储数据,以平衡两者之间的速度差异。
三、UART FIFO的工作原理1. 发送端工作原理当发送端有数据要发送时,数据首先被写入到FIFO缓冲区中。
如果FIFO缓冲区为空,则数据可以直接写入;如果FIFO缓冲区已满,则发送端需要等待,直到FIFO缓冲区有足够的空间。
发送端通过检查FIFO的状态位来确定是否可以写入数据。
2. 接收端工作原理当接收端准备好接收数据时,它会从FIFO缓冲区中读取数据。
如果FIFO缓冲区为空,则接收端需要等待,直到FIFO缓冲区有数据可读。
接收端通过检查FIFO的状态位来确定是否可以读取数据。
四、UART FIFO的流程1. 发送端流程(1)检查FIFO状态位,确定是否可以写入数据;(2)如果FIFO缓冲区已满,则等待;(3)将数据写入FIFO缓冲区;(4)检查数据是否成功写入FIFO缓冲区;(5)重复上述步骤,直到所有数据发送完毕。
2. 接收端流程(1)检查FIFO状态位,确定是否有数据可读;(2)如果FIFO缓冲区为空,则等待;(3)从FIFO缓冲区中读取数据;(4)检查数据是否成功读取;(5)重复上述步骤,直到所有数据接收完毕。
五、UART FIFO的优势1. 缓冲作用:FIFO缓冲区可以暂时存储数据,以平衡发送端和接收端之间的速度差异,避免数据丢失或溢出。
quartus 异步fifo用法 -回复
quartus 异步fifo用法-回复Quartus 异步FIFO 用法说明引言:在现代数字系统设计中,FIFO(先进先出)是一种常见的数据缓冲区,用于解决数据在不同速度的模块之间的数据流问题。
在Quartus 中,异步FIFO 提供了一种灵活和方便的方式来实现数据的缓冲和流控。
本文将逐步介绍Quartus 异步FIFO 的基本用法,帮助读者了解其操作和配置。
第一步:创建FIFO首先,在Quartus 中打开自己的设计项目,选择要创建异步FIFO 的模块。
然后,点击菜单栏中的"Project",选择"New",再选择"FIFO MegaWizard"。
接下来,按照提示选择FIFO 的类型、数据位宽和深度等配置参数。
请注意,深度是指FIFO 可以容纳的数据数量。
点击"Next"继续,然后会出现一个界面,该界面将由Quartus 生成FIFO 的RTL(寄存器传输级)代码。
在这个界面上,您可以选择生成的接口样式以及其他自定义选项。
完成配置后,点击"Finish",Quartus 将自动生成FIFO 的VHDL 或Verilog 代码,并将其添加到项目中。
第二步:添加FIFO 的输入和输出端口一旦FIFO 生成完成并添加到项目中,您需要将其引入到适当的模块中,并为其添加输入和输出端口。
假设我们将FIFO 引入到名为"Top_Module"的模块中,请按照以下步骤进行操作:1. 在"Top_Module"的代码中,将FIFO 的引用添加为一个实例,例如:fifo_inst : entity work.my_fifoport map (clk => internal_clk,reset => reset,wr_data => data_in,wr_en => write_enable,rd_data => data_out,rd_en => read_enable,full => fifo_full,empty => fifo_empty);2. 根据您的设计需要,为FIFO 添加输入和输出信号。
altera fifo异步清零信号的时序
altera fifo异步清零信号的时序一、引言在数字电路设计中,FIFO(First In First Out)是一种常见的数据缓冲器,用于解决不同速度的数据传输之间的数据流失问题。
Altera是一家知名的FPGA芯片制造商,其FIFO模块提供了异步清零信号来实现清空缓冲区的功能。
二、FIFO异步清零信号的定义FIFO异步清零信号是一种特殊的控制信号,用于将FIFO缓冲区中的数据全部清空。
当该信号被激活时,FIFO模块会将缓冲区中的数据全部丢弃,并将指针重置为初始状态。
三、FIFO异步清零信号的工作原理FIFO异步清零信号的工作原理如下:1. 当FIFO异步清零信号被激活时,FIFO模块会检测到该信号的变化。
2. FIFO模块会立即停止写入数据和读取数据的操作,并将指针重置为初始状态。
3. FIFO模块会将缓冲区中的数据全部丢弃,不再进行任何处理。
4. FIFO异步清零信号被取消激活后,FIFO模块会恢复正常的读写操作。
四、FIFO异步清零信号的时序特性FIFO异步清零信号的时序特性如下:1. 异步清零信号可以随时激活,无需与其他信号同步。
2. 异步清零信号的激活时间和激活持续时间可以根据设计要求进行调整。
3. FIFO模块在接收到异步清零信号后会立即响应,无需等待时钟信号。
4. 异步清零信号的取消激活时间可以根据设计要求进行调整。
5. 异步清零信号的取消激活时间应保证足够长,以确保FIFO模块完全恢复正常操作。
五、FIFO异步清零信号的注意事项在使用FIFO异步清零信号时,需要注意以下几点:1. 异步清零信号的激活和取消激活应遵循设计规范,不得出现脉冲信号或持续激活导致异常操作。
2. 异步清零信号的激活和取消激活时间应考虑到FIFO模块的响应时间和恢复时间,避免信号过短或过长导致操作不稳定。
3. 在设计中,应考虑到异步清零信号与其他控制信号的相互作用,避免冲突或误操作。
六、总结FIFO异步清零信号是一种重要的控制信号,用于清空FIFO缓冲区中的数据。
基于乒乓操作的异步FIFO设计及VHDL实现
基于乒乓操作的异步FIFO设计及VHDL实现乒乓操作是一种常用的同步操作,可以实现数据的交换和缓存。
基于乒乓操作的异步FIFO设计,则是在原有的乒乓操作基础上,加入异步读写功能,实现了先进先出的数据存储。
在设计过程中,我们需要考虑以下几个关键点:1.写入数据的操作:当有新的数据要写入到FIFO中时,首先需要判断FIFO是否已满。
如果已满,则需要等待读取操作后再进行写入;如果未满,则直接将数据写入到空闲位置,并更新写指针。
2.读取数据的操作:当有读取操作时,首先需要判断FIFO是否为空。
如果为空,则需要等待写入操作后再进行读取;如果不为空,则从第一个有效数据开始读取,并将读取完的数据位置清空,并更新读指针。
3.FIFO的容量:FIFO的容量应该根据实际需求进行设置。
当FIFO中的数据量达到容量上限时,写操作将被阻塞,直到有读取操作释放空间。
基于以上设计思路,下面是一个简单的基于乒乓操作的异步FIFO的VHDL实现代码:```vhdllibrary ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity Async_FIFO isgenericWIDTH : integer := 8; -- 数据位宽DEPTH : integer := 16 -- FIFO深度portclk : in std_logic; -- 时钟reset : in std_logic; -- 复位write : in std_logic; -- 写操作使能信号read : in std_logic; -- 读操作使能信号data_in : in std_logic_vector(WIDTH-1 downto 0); -- 输入数据data_out: out std_logic_vector(WIDTH-1 downto 0); -- 输出数据empty : out std_logic; -- FIFO为空标志位full : out std_logic -- FIFO为满标志位end Async_FIFO;architecture behavioral of Async_FIFO istype fifo_type is array (0 to DEPTH-1) ofstd_logic_vector(WIDTH-1 downto 0); -- FIFO存储类型signal fifo : fifo_type; -- FIFO数组signal write_ptr : integer range 0 to DEPTH-1 := 0; -- 写指针signal read_ptr : integer range 0 to DEPTH-1 := 0; -- 读指针signal count : integer range 0 to DEPTH := 0; -- FIFO计数器beginprocess(clk, reset)beginif reset = '1' then--复位write_ptr <= 0;read_ptr <= 0;count <= 0;elsif rising_edge(clk) then--写操作if write = '1' and count < DEPTH thenfifo(write_ptr) <= data_in;write_ptr <= write_ptr + 1;count <= count + 1;end if;--读操作if read = '1' and count > 0 thendata_out <= fifo(read_ptr);fifo(read_ptr) <= (others => '0');read_ptr <= read_ptr + 1;count <= count - 1;end if;end if;end process;empty <= '1' when count = 0 else '0';full <= '1' when count = DEPTH else '0';end behavioral;```上述代码中,首先定义了一个`fifo_type`类型,它是一个包含`DEPTH`个元素的数组,每个元素的大小为`WIDTH`位。
异步fifo实现原理
异步fifo实现原理小伙伴!今天咱们来唠唠异步FIFO这个超有趣的东西哦。
异步FIFO呢,简单说就是一种数据缓存的小能手。
想象一下,你有两个小伙伴,一个小伙伴干活特别快,另一个呢有点慢悠悠的。
快的那个小伙伴想把东西交给慢的那个,可直接交的话就乱套了。
这时候异步FIFO就像个小管家,把快的小伙伴的东西先好好收着,再按照慢小伙伴能接受的速度给他。
那它到底是怎么做到的呢?这里面可有不少小秘密呢。
咱们先来说说FIFO的基本结构。
它就像一个小仓库,有入口和出口。
在异步FIFO里,这个小仓库被分成了好多小格子,每个小格子都能放一个数据。
这个小仓库的大小可是很重要的哦,如果太小了,可能数据就会丢啦,就像一个小盒子装不下太多东西一样。
再说说读写指针。
这俩指针就像是在小仓库里巡逻的小保安。
读指针呢,就负责看看从哪里把数据拿出去,写指针就负责看看把新数据放在哪里。
在异步FIFO里,这两个指针可有点特别,因为它们工作的时钟不一样呢。
就像两个小伙伴,一个按照白天的时间作息,一个按照晚上的时间作息。
当写数据的时候,写指针就会向前移动一格,就像小保安巡逻到下一个小格子一样。
这个时候,数据就被妥妥地放在了新的小格子里。
读数据的时候呢,读指针也会向前走一格,然后把数据取出来。
这里面有个很关键的点哦,就是怎么知道这个FIFO 是空的还是满的呢?如果读指针和写指针指向了同一个小格子,那这个FIFO可能是空的,因为没有新的数据被写进去嘛。
但是呢,也有可能是满的哦,这就有点绕了。
为了区分这两种情况,异步FIFO会用一些小技巧。
比如说,用多几位的指针,或者用一些额外的逻辑来判断。
这就像是给小保安多一些判断的依据,让他们能准确知道仓库的状态。
还有哦,异步FIFO里面的跨时钟域问题。
因为读写指针工作在不同的时钟下,就像两个不同节奏的音乐在同时演奏。
这时候就很容易出问题啦。
为了让它们能和谐共处,就需要一些特殊的处理。
比如说,用同步器把指针的信号从一个时钟域同步到另一个时钟域。
4.异步FIFO的设计
利用异步FIFO在跨时钟域中降低亚稳态发生概率在数字电路设计中,时钟是整个电路最重要、最特殊的信号,系统内大部分器件的操作都是在时钟的跳变沿上进行,如果时序不满足要求,就可能造成逻辑状态出错甚至整个系统设计的失败。
随着SOC技术的不断发展,数字系统设计的复杂度也在日益增加,经常需要跨时钟域的数据传输,通信技术等异步设计才能实现特定的功能需求。
本文设计的异步FIFO就是为了解决将数据从一个时钟域同步的读/写到另一个时钟域,并且能很好的避免亚稳态的发生。
1.异步系统任意的两个系统如果满足以下条件之一,如图1-2所示,就可称其为异步的:(1)工作在不同的时钟频率上;(2)工作在相同频率上,但相位不同图1-2 异步系统时钟当两个不同时钟域的系统进行数据传输,由于接口处是异步的,就可能会违反建立时间和保持时间规则导致亚稳态以及不可靠的数据传输,因此处理起来较同步逻辑复杂困难。
在同步系统中,输入信号必须总是满足寄存器时序要求,所以亚稳态不会发生。
亚稳态问题通常发生在当一个信号在无关的线路中或异步时钟域中传输。
在所有的异步系统中,亚稳态是不可避免的。
1.1亚稳态所有的数字器件寄存器都定义了一个信号时序要求,满足了这个要求寄存器才可以正确地在输入端获取(capture)数据在输出端产生数据。
为了确保数据的可靠与正确性,在数据传输过程中必须满足寄存器的建立时间和保持时间,如图1-1,即输入数据在时钟沿之前必须稳定一段时间(寄存器建立时间Tsu)并且在时钟沿之后稳定一段时间(寄存器保持时间Th),然后寄存器输出经过一个特定的时钟到输出延时(clock to output ,Tco)后有效。
图1-1 建立时间与保持时间如果一个数据信号在翻转中违反了一个寄存器的建立和保持时间的要求,寄存器的输出可能就会出现亚稳态。
在亚稳态中,寄存器的输出值在高和低之间徘徊一段时间,这就意味着输出翻转到一个确定的高或低的延时会超过固定的时钟到输出延时。
一个异步FIFO的设计示例
一、异步FIFO 技术规范1. 总体描述1.1. 功能定义异步FIFO ( First In First Out)指的是在两个相互独立的时钟域下, 数据从一个时钟域写入FIFO 而另一个时钟域又从这个FIFO 中将数据读出。
本设计用8*256的RAM 实现异步FIFO 。
具体功能:1. 写使能有效,且FIFO 不为满时,在写时钟的上升沿向FIFO 中写入数据。
2. 读使能有效,且FIFO 不为空时,在读时钟的上升沿从FIFO 中读出数据。
3. 当FIFO 写满时产生满信号,当FIFO 读空时产生空信号。
1.2. 应用范围异步FIFO 是用来作为缓冲的存储器, 它能对数据进行快速、顺序的存储和发送, 主要用来解决不同速率器件间的速率匹配问题。
2. 引脚描述8*256异步FIFO rst r_clkr_en data_in[7:0]full empty w_clkw_endata_out[7:0]图12.1. 引脚功能描述 信号名输入/输出 功能描述r_clk输入 读数据时钟信号 w_clk 输入 写数据时钟信号data_in[7:0] 输入8位的输入数据r_en 输入读使能,高电平有效,在FIFO非空时,clk上升沿读入数据;w_en 输入写使能,高电平有效,在FIFO非满时,clk上升沿写入数据;rst 输入异步清零,低电平有效,低电平时读地址,写地址,计数器都清零。
empty 输出空信号,高电平有效,当FIFO读空时其值为1full 输出满信号,高电平有效,当FIFO写满时其值为1 data_out[7:0] 输出8位的输出数据2.2.引脚时序描述当写满时full由低变高,当读空时empty由低变高。
只要不为满full就为低,不为空empty就为低。
3.顶层模块划分。
异步FIFO设计
【转】/s/blog_6592e7700100x68n.html异步FIFO是一种先进先出电路,用在需要实时数据接口的部分,用来存储、缓冲在两个异步时钟之间的数据传输。
异步FIFO与同步FIFO最大的不同在于异步FIFO读写时钟不同,通常异步FIFO用来做数据的时钟域转换,FIFO设计中难度最大的地方在FIFO的空满标识的产生,对同步FIFO来说,由于读写指针的增加时钟频率相同,因此读写指针可以直接进行比较产生出空满标志,而异步FIFO某由于读写两端时钟频率不同,读写指针需要进行时钟域转换后才能进行比较,也就是读时钟域的读地址要先转到写时钟域,然后与写时钟域的写地址进行比较,而实际这种比较时存在一定风险的。
异步FIFO设计一般的结构有:双口存储器、读地址产生逻辑、写地址产生逻辑、空/满标志产生逻辑四部分构成。
图1是一种常用的异步FIFO设计方案,其中,读地址(rptr)和空标志(rempty)由读时钟(rclk)产生,而写地址(wptr)和满标志(wfull)由写时钟(wclk)产生。
把写地址与读地址相互比较以产生空/满标志。
由于读写地址的变化由不同的时钟产生,所以对FIFO 空或满的判断是跨时钟域的。
如何避免异步传输带来的亚稳态以及正确地产生空/满标志是设计异步FIFO的难点。
图1在设计时,需要弄清楚以下几个方面:1.首先确定输入输出接口,异步FIFO在一个时钟域中进行写数据操作,而在另一个时钟域中进行读数据操作,所以在写数据模块,需要有写数据wdata,写时钟wclk,写复位wrst_n,写请求wreq,写满标志wfull;在读数据模块,需要有读数据rdata,读时钟rclk,读复位rrst_n,读请求rreq,读空标志rempty。
其中rdata,rempty,wfull为输出信号,其余为输入信号。
其FIFO用来存储16*8数据(数据宽为8,数据深度为16)的顶层模块如下://异步FIFO缓存16*8数据,即数据宽度为8,深度为16//module yibufifo(rdata,rempty,rrep,rclk,rrst_n,wdata,wfull,wrep,wclk,wrst_n);input wclk,wrep,wrst_n;input rclk,rrep,rrst_n;input[7:0]wdata;output[7:0]rdata;output rempty,wfull;wire wclk,wrep,wrst_n;wire rclk,rrep,rrst_n;wire [7:0]wdata;wire [7:0]rdata;wire [3:0]wptr,rptr;wire [3:0]waddr,raddr;wire aempty_n,afull_n;ram i1(.wdata(wdata),//读写存储模块.rdata(rdata),.waddr(wptr),//地址与指针同步.raddr(rptr),//.wrep(wrep),.wclk(wclk));async_cmp i2(.aempty_n(aempty_n),//异步比较读写指针产生异步空满标志.afull_n(afull_n),.wptr(wptr),.rptr(rptr),.wrst_n(wrst_n));rptr_empty2 i3(.rempty(rempty),//根据rclk产生读指针rptr和空标志rempty.rptr(rptr),.aempty_n(aempty_n),.rrep(rrep),.rclk(rclk),.rrst_n(rrst_n));wptr_full2 i4(.wfull(wfull),//根据wclk产生写指针wptr和满标志wfull.wptr(wptr),.afull_n(afull_n),.wrep(wrep),.wclk(wclk),.wrst_n(wrst_n));endmodule顶层模块图:其中2.1 读写地址产生逻辑(本设计中读写地址与读写指针同步)读写地址线一般有多位,如果在不同的时钟域内直接同步二进制码的地址指针,则有可能产生亚稳态。
FIFO同步、异步以及Verilog代码实现
FIFO同步、异步以及Verilog代码实现FIFO 很重要,之前参加的各类电⼦公司的逻辑设计的笔试⼏乎都会考到。
FIFO是英⽂First In First Out 的缩写,是⼀种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使⽤起来⾮常简单,但缺点就是只能顺序写⼊数据,顺序的读出数据, 其数据地址由内部读写指针⾃动加1完成,不能像普通存储器那样可以由地址线决定读取或写⼊某个指定的地址。
FIFO⼀般⽤于不同时钟域之间的数据传输,⽐如FIFO的⼀端是AD数据采集, 另⼀端是计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,⽽PCI总线的速度为33MHz,总线宽度32bit,其最⼤传输速率为 1056Mbps,在两个不同的时钟域间就可以采⽤FIFO来作为数据缓冲。
另外对于不同宽度的数据接⼝也可以⽤FIFO,例如单⽚机位8位数据输出,⽽ DSP可能是16位数据输⼊,在单⽚机与DSP连接时就可以使⽤FIFO来达到数据匹配的⽬的。
FIFO的分类根均FIFO⼯作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。
同步FIFO是指读时钟和写时钟为同⼀个时钟。
在时钟沿来临时同时发⽣读写操作。
异步FIFO是指读写时钟不⼀致,读写时钟是互相独⽴的。
FIFO设计的难点 FIFO设计的难点在于怎样判断FIFO的空/满状态。
为了保证数据正确的写⼊或读出,⽽不发⽣益处或读空的状态出现,必须保证FIFO在满的情况下,不 能进⾏写操作。
在空的状态下不能进⾏读操作。
怎样判断FIFO的满/空就成了FIFO设计的核⼼问题。
.........................................................................................................................................同步FIFO的Verilog代码之⼀在modlesim中验证过。
异步fifo时序约束
异步FIFO时序约束在数字电路设计中,异步FIFO(First-In First-Out)是一种常见的同步和异步信号之间的缓冲器。
由于FIFO是在不同的时钟域上操作,因此需要考虑时序约束以确保数据正确传输。
本文将介绍异步FIFO的时序约束及其重要性。
一、异步FIFO简介异步FIFO是一种存储器,它可以在不同的时钟域上读写数据。
在数字电路设计中,FIFO被广泛应用于解决不同时钟域之间的数据传输问题。
由于异步FIFO 涉及跨时钟域的操作,因此需要特别注意时序约束,以避免数据冲突和亚稳态问题。
二、异步FIFO时序约束异步FIFO的时序约束主要包括以下几个方面:1.读/写时钟域的约束:为了保证数据的正确传输,读/写时钟域必须满足一定的时序要求。
具体来说,写时钟域的频率应该高于读时钟域的频率,以避免数据在FIFO中溢出。
同时,两个时钟域之间的相位差也应该控制在一定的范围内,以避免数据读写时出现冲突。
2.读/写指针的约束:读/写指针是FIFO中用于追踪读写位置的变量。
为了保证数据的正确读写,读/写指针必须满足一定的时序要求。
具体来说,写指针的更新应该发生在写时钟域的上升沿,而读指针的更新应该发生在读时钟域的上升沿。
这样可以确保在正确的时钟周期内进行数据读写操作。
3.数据有效性的约束:由于异步FIFO涉及跨时钟域的操作,因此需要考虑数据的有效性。
具体来说,当读指针小于写指针时,FIFO中的数据是有效的;而当读指针大于或等于写指针时,FIFO中的数据是无效的。
因此,需要根据实际情况对数据的读写进行控制,以确保数据的正确性。
4.空/满标志的约束:空/满标志是用于指示FIFO是否为空或满的标志位。
为了保证数据的正确传输,空/满标志必须满足一定的时序要求。
具体来说,当FIFO为空或满时,相应的标志位应该被及时更新;而当FIFO不为空或满时,相应的标志位应该保持不变。
这样可以确保在正确的时钟周期内进行数据读写操作。
三、结论异步FIFO时序约束是数字电路设计中需要考虑的重要问题之一。
异步FIFO的verilog代码实现(包含将满和将空逻辑)
异步FIFO的verilog代码实现(包含将满和将空逻辑)异步FIFO的verilog代码实现(包含将满和将空逻辑)代码参考来源:1. Clifford E. Cummings, "Simulation and Synthesis Techniques for Asynchronous FIFO Design".2.⽬录异步FIFO简介使⽤场景:在有⼤量的数据需要进⾏跨时钟域传输,并且对数据传输速度要求⽐较⾼的场合。
⼀个异步 FIFO ⼀般由如下部分组成:1. Memory, 作为数据的存储器;2.写逻辑部分,主要负责产⽣写信号和地址;3.读逻辑部分,主要负责产⽣读信号和地址;4.地址⽐较部分,主要负责产⽣ FIFO 空、满的标志。
跟普通的FIFO相⽐,异步FIFO实际上多了读写地址的跨时钟域同步的逻辑,以及两个时钟域中读写信号的⽐较逻辑。
异步FIFO关键技术1 -- 读写信号跨时钟域同步⾸先,FIFO的关键是需要判断读空和写满,⽽这两个信号的产⽣依赖读地址和写地址。
在异步FIFO中,读和写是分在两个时钟域中的,在写时钟域,需要得到读地址的信息进⽽判断是否写满(写指针是否追上读指针),同理,在读时钟域,也需要写地址的信息。
我们知道跨时钟域的单⽐特数据⼀般可以⽤双寄存器法进⾏同步,但读写地址通常都是多⽐特的信号,此时如何进⾏同步呢?当然,多⽐特的同步肯定可以通过增加握⼿信号来解决,但实际上对于数值上连续的信号,可以采⽤格雷码进⾏多⽐特到单⽐特的传输。
格雷码再次不做介绍,具体原理可以参考:有了格雷码,就可以将读写地址同步到各⾃的时钟域了。
异步FIFO关键技术2 -- 读写地址的⽐较跟普通fifo⼀样,异步fifo也是通过⽐较读写地址是否相同来判断当前fifo是否空满。
区别在于,异步FIFO因为使⽤了格雷码对地址进⾏编码传输。
⽐如读信号通过格雷码编码后同步到写时钟域,此时需要只需要写信号对应的格雷码和读信号格雷码是否相同(有效位相同)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
高速异步FIFO的设计与实现摘要:本文主要研究了用FPGA芯片实现异步FIFO的一种方法。
通过对FPGA芯片内部EBRSRAM的深入研究.提出了一种利用格雷码对地址进行编码的异步FIFO设计方案。
实践证明.增加了系统可靠性和应用灵活性。
引言现代集成电路芯片中,随着设计规模的不断扩大.一个系统中往往含有数个时钟。
多时钟带来的一个问题就是,如何设计异步时钟之间的接口电路。
异步FIFO(First In First Out)是解决这个问题的一种简便、快捷的解决方案。
使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据.在网络接口、图像处理等方面,异步FIFO都得到广泛的应用。
异步FIFO是一种先进先出的电路,使用在数据接口部分,用来存储、缓冲在两个异步时钟之间的数据传输。
在异步电路中,由于时钟之间周期和相位完全独立,因而数据的丢失概率不为零。
如何设计一个可靠性高、速度高的异步FIFO电路便成为一个难点。
1 异步FIFO的工作原理及逻辑框图本文根据实际工作的需要.给出了一种利用片内RAM构造FIFO器件的设计,重点强调了设计有效.可靠的握手信号FULL和EMPTY的方法。
并在LATTICE公司的FPGA芯片LFXP2-5E上实现。
LFXP2-5E属于LATIICE 公司XP2系列的一款,他采用优化的FlexiFLASH结构。
内部包含有基于查找表的逻辑、分布式和嵌入式存储器,锁相环(PLL)。
工程预制的源同步I/0以及增强的Sys DSP块。
有166Kbits的EBRSRAM。
利用其内部的EBRSRAM可以实现一定容量的异步FIFO.而无需单独购买FIF0器件。
由图1可以看出:异步FIFO一般由四个模块构成:数据存储单元,写地址产生模块,读地址产生模块,标志位产生模块。
整个系统分为两个完全独立的时钟域—读时钟域和写时钟域:在写时钟域部分由写地址产生逻辑产生写控制信号和写地址:读时钟域部分,由读地址产生逻辑产生读控制信号和读地址;在标志位产生模块部分,由读写地址相互比较产生空/满标志。
异步FIFO的操作过程为:在写时钟的上升沿.当写使能有效时,将数据写入到双口RAM中写地址对应的位置中:在读时钟的上升沿,当读使能有效时。
则按先进先出顺序读出数据。
在FIFO写满或读空的情况下。
分别对满标志FuLL或空标志EMPTY信号置位。
来表示FIFO的两种特殊状态。
图1异步FIFO逻辑框图2 异步FIFO的VHDL实现读时钟2.1 FIFO设计的难点如何同步异步信号,使触发器不产生亚稳态是设计异步FIFO的难点。
国内外解决此问题的较成熟办法是对写地址膜地址采用格雷码,本文也直接采用格雷码。
异步FIFO设计的另一个难点是如何判断FIFO的空/满状态。
为了保证数据正确的写入或读出。
必须保证异步FIFO在满的状态下.不能进行写操作:在空的状态下不能进行读操作。
通常情况下将存储器组织成一个环形链表。
满/空标志产生的原则是:写满不溢出.读空不多读。
即无论在什么情况.都不应出现读写地址同时对一个存储器地址操作的情况。
在读写地址相等或相差一个或多个地址的时候,满标志应该有效。
表示此时FIFO已满,外部电路应停止对FIFO发数据。
在满信号有效时写数据应根据设计的要求,或保持、或抛弃重发。
同理,空标志的产生也是如此。
为了更好的判断满/空标志。
采用在FIFO原来深度的基础上增加一位的方法,而由该位组成的格雷码并不代表新的地址。
也就是说3位格雷码可表示8位的深度,若再加一位最高位MSB,则这一位加其他三位组成的格雷码并不代表新的地址,也就是说格雷码的0100表示7,而1100仍然表示7,只不过格雷码在经过一个以0位MSB的循环后进入一个以1为MSB的循环,然后又进入一个以0位MSB的循环。
其他的三位码仍然是格雷码。
举例说明:一个深度为8字节的FIFO怎样工作(使用已转换为二进制的指针),N=3,指针宽度为N+I=4。
开始rd_ptr_bin和wr_ptr_bin均为“0000”。
此时FIFO中写入8个字节的数据。
wr_ptr_bin=“1000",rd_ptr_bin=“0000”。
当然,这就是满条件。
现在,假设执行了8次的读操作.使得rd_ptr_bin=“1000”,这就是空条件。
另外的8次写操作将使wr_ptr_bin 等于“0000”,但rd_ptr_bin仍然等于“1000”,因此,FIFO为满条件。
由以上可知。
满标志的产生条件为:写指针赶上读指针.即写满后,又从零地址开始写直到赶上读指针,这时期读写指针的最高位不同,其他位相同,这就是满条件。
空标志的产生条件为:复位或者是读指针赶上写指针.即在写指针循环到第二轮时读指针赶上写指针,这时读写指针的高低位均相同,这就是空条件。
2.2异步F1F0的VHDL语言实现以下为本程序的核心部分程序1格雷码计数器的实现3 仿真验证基于以上的分析结合实际本文构造了一个8192x8的FIFO,用MODELSIM进行仿真。
对该异步FIFO编写测试向量进行仿真,如图2所示。
图2仿真波形图图2中,WClk为写时钟,Writeen_in为写使能,Full_out为满信号,Data_in为数据入,RClk为读时钟,ReadEn_in为读时能,Empty_out为空信号,Data_out为数据出,Clear_in为系统清零信号。
上面部分为写地址产生模块部分的信号波形,从图2中可以看出.在写时钟的上升沿.在写时能为高有效期间擞据开始输入到RAM里面,而在读时钟的上升沿,在读时能有效时,在本仿真时间的195ns处.开始输出数据。
将程序下载到LATTICE公司的FPGA芯片中,经过测试验证,系统的时钟频率可达33MHz。
4 总结本文主要研究了用FPGA芯片实现异步FIFO的一种方法。
详细阐述了空,满标志信号的产生方法。
按照以上思想所设计的异步FIFO已经在实际电路中得到了应用。
实践证明他可以解决大多数异步FIFO电路常见的错误。
同时增加了系统的可靠性和应用灵活性。
FPGA异步FIFO设计中的问题与解决办法21IC中国电子网随着数字电子系统设计规模的扩大,一些实际应用系统中往往含有多个时钟,数据不可避免地要在不同的时钟域之间传递。
如何在异步时钟之间传输数据,是数据传输中一个至关重要的问题,而采用FIFO 正是解决这一问题的有效方法。
异步FIFO是一种在电子系统中得到广泛应用的器件,多数情况下它都是以一个独立芯片的方式在系统中应用。
本文介绍一种充分利用FPGA内部的RAM资源,在FPGA内部实现异步FIFO模块的设计方法。
这种异步FIFO比外部FIFO 芯片更能提高系统的稳定性。
1 FIFO的基本结构和工作原理FIFO(First In First Out)是一种采用环形存储结构的先进先出存储器。
其使用一个双端口存储器存放数据,数据发送方在一端写入数据,接收方在另一端读出数据,能够协调好两个时钟域的工作,满足高时钟频率的要求。
FIFO在FPGA设计中主要用来缓冲数据和隔离时钟或相位差异。
访问FIFO时不需要地址线,只需要数据线和读写控制信号线,且数据地址由内部读写指针自动加1完成,因此利用FIFO实现数据的缓存具有接口简单、读写方便的优点。
根据FIFO的工作时钟,可将FIFO分为同步FIFO和异步FIFO。
同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时进行读写操作;异步FIFO是指读写时钟不是同一个时钟,而是相互独立的。
实际上,工作在同一时钟的FIFO很少用到,多数都是读写时钟独立的异步FIFO。
本文设计的异步FIFO位宽为8,深度(即FIFO可以存储8位数据的个数)为1 024。
异步FIFO的结构如图1所示。
双端口RAM存储器具有独立的读写端口。
如果用一个单端口RAM存储器实现异步FIFO,还应该包含一个仲裁器来保证同一时刻只能有一种操作(读或写操作)。
本文选择的双端口RAM并不一定是真正的双端口,只要有独立的读写端口即可。
读写控制逻辑由加法计数器构成,实现读写地址的自动加1功能。
空/满标志位的产生逻辑给系统提供空(empty)和满(full)信号。
2 异步FIFO设计中的问题与解决办法2.1 亚稳态问题在含有触发器的电路中往往会出现亚稳态问题。
亚稳态会使异步FIFO的读写地址发生错误,产生误读或者误写。
为此异步FIFO设计中亚稳态问题也是一个比较重要的问题。
亚稳态不可能完全消除,只能使其出现的概率降到最低。
主要有2种方法来降低亚稳态出现的概率:①采用触发器冗余方式。
即采用多个触发器级联的方式,使本来出现概率为P的亚稳态,其出现概率降低到P2,但这种方式会导致延时增加。
②使用格雷码。
格雷码的相临码元之间只有一位发生变化,这就大大地降低了亚稳态出现的概率。
本文采用格雷码方式。
2.2 空/满标志位的判断为保证数据的正确写入和读出,不发生写满和读空操作,怎样判断空/满标志位的产生就成为异步FIFO设计的核心问题。
异步FIFO是环形存储的,当读写地址指针相等时,意味着空标志位或者满标志位的产生。
但是却不能确定是写满还是读空状态。
为解决这一问题,本文将转换为格雷码后的读写地址指针分别经过检测和计数器。
每当读写指针遍历一圈(当读写地址指针指向双端口RAM的最后一个地址)时,写计数i加1,读计数j加1。
这样写满状态和读空状态的判断就需要同时满足两个条件。
下面分别给出写满和读空状态的判断。
①写满状态的判别:当读地址指针等于写地址指针,并且i>j时,产生满标志。
②读空状态的判别:当写地址指针等于读地址指针,并且i=j时,产生空标志。
由于空/满标志位产生的结构图对称,故本文只给出满标志位产生的结构图,如图2所示。
其中,主数i为写地址指针遍历的圈数,计数j为读地址指针遍历的圈数。
从图2中可看出,地址指针转换为格雷码后,经过检测和计数环节,将读写地址和读写指针遍历的圈数分别送入比较器进行比较,从而准确地产生满标志位。
3 FPGA内部软异步FIFO设计本设计中FPGA采用的是Xilinx Spartan3系列中的XC3S400PQ208。
内部有56 Kb的分布式RAM 和288 Kb的RAM,以及4个DCM(数字时钟管理器)单元,为系统提供独立的读写时钟频率。
可以利用这些资源在FPGA内部实现异步FIFO模块。
本文采用VHDL语言对双端口RAM的读写操作进行编程,实现FPGA内部软FIFO的设计。
部分读写双端口RAM和空/满标志位的判断源程序如下:4 系统仿真如果系统的读时钟频率大于写时钟频率,就有可能出现读空的情况;如果系统的写时钟频率大于读时钟频率,就可能出现写满的情况。
在实际系统中,一般都设置写时钟频率大于读时钟频率,故本文只考虑后一种情况。