本原創教程由芯驛電子科技(上海)有限公司(ALINX)創做,版權歸本公司全部,如需轉載,需受權並註明出處。node
AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E/AXU4EV-P/AXU5EV-E/AXU5EV-P /AXU9EG/AXU15EG緩存
實驗Vivado工程爲「fifo_test」。異步
FIFO是FPGA應用當中很是重要的模塊,普遍用於數據的緩存,跨時鐘域數據處理等。學好FIFO是FPGA的關鍵,靈活運用好FIFO是一個FPGA工程師必備的技能。本章主要介紹利用XILINX提供的FIFO IP進行讀寫測試。測試
1.實驗原理ui
FIFO: First in, First out表明先進的數據先出,後進的數據後出。Xilinx在VIVADO裏爲咱們已經提供了FIFO的IP核, 咱們只需經過IP核例化一個FIFO,根據FIFO的讀寫時序來寫入和讀取FIFO中存儲的數據。spa
其實FIFO是也是在RAM的基礎上增長了許多功能,FIFO的典型結構以下,主要分爲讀和寫兩部分,另外就是狀態信號,空和滿信號,同時還有數據的數量狀態信號,與RAM最大的不一樣是FIFO沒有地址線,不能進行隨機地址讀取數據,什麼是隨機讀取數據呢,也就是能夠任意讀取某個地址的數據。而FIFO則不一樣,不能進行隨機讀取,這樣的好處是不用頻繁地控制地址線。設計
雖然用戶看不到地址線,可是在FIFO內部仍是有地址的操做的,用來控制RAM的讀寫接口。其地址在讀寫操做時以下圖所示,其中深度值也就是一個FIFO裏最大能夠存放多少個數據。初始狀態下,讀寫地址都爲0,在向FIFO中寫入一個數據後,寫地址加1,從FIFO中讀出一個數據後,讀地址加1。此時FIFO的狀態即爲空,由於寫了一個數據,又讀出了一個數據。3d
能夠把FIFO想象成一個水池,寫通道即爲加水,讀通道即爲放水,假如不間斷的加水和放水,若是加水速度比放水速度快,那麼FIFO就會有滿的時候,若是滿了還繼續加水就會溢出overflow,若是放水速度比加水速度快,那麼FIFO就會有空的時候,因此把握好加水與放水的時機和速度,保證水池一直有水是一項很艱鉅的任務。也就是判斷空與滿的狀態,擇機寫數據或讀數據。code
根據讀寫時鐘,能夠分爲同步FIFO(讀寫時鐘相同)和異步FIFO(讀寫時鐘不一樣)。同步FIFO控制比較簡單,再也不介紹,本節實驗主要介紹異步FIFO的控制,其中讀時鐘爲75MHz,寫時鐘爲100MHz。實驗中會經過VIVADO集成的在想邏輯分析儀ila,咱們能夠觀察FIFO的讀寫時序和從FIFO中讀取的數據。orm
2.1 添加FIFO IP核
在添加FIFO IP以前先新建一個fifo_test的工程, 而後在工程中添加FIFO IP,方法以下:
2.1.1點擊下圖中IP Catalog,在右側彈出的界面中搜索fifo,找到FIFO Generator,雙擊打開。
2.1.2 彈出的配置頁面中,這裏能夠選擇讀寫時鐘分開仍是用同一個,通常來說咱們使用FIFO爲了緩存數據,一般兩邊的時鐘速度是不同的。因此獨立時鐘是最經常使用的,咱們這裏選擇「Independent Clocks Block RAM」,而後點擊「Next」到下一個配置頁面。
2.1.3 切換到Native Ports欄目下,選擇數據位寬16;FIFO深選擇512,實際使用你們根據須要自行設置就能夠。Read Mode有兩種方式,一個Standard FIFO,也就是平時常見的FIFO,數據滯後於讀信號一個週期,還有一種方式爲First Word Fall Through,數據預取模式,簡稱FWFT模式。也就是FIFO會預先取出一個數據,當讀信號有效時,相應的數據也有效。咱們首先作標準FIFO的實驗。
2.1.4 切換到Data Counts欄目下,使能Write Data Count(已經FIFO寫入多少數據)和Read Data Count(FIFO中有多少數據能夠讀),這樣咱們能夠經過這兩個值來看FIFO內部的數據多少。點擊OK,Generate生成FIFO IP。
2.2 FIFO的端口定義與時序
信號名稱 | 方向 | 說明 |
rst | in | 復位信號,高有效 |
wr_clk | in | 寫時鐘輸入 |
rd_clk | in | 讀時鐘輸入 |
din | in | 寫數據 |
wr_en | in | 寫使能,高有效 |
rd_en | in | 讀使能,高有效 |
dout | out | 讀數據 |
full | out | 滿信號 |
empty | out | 空信號 |
rd_data_count | out | 可讀數據數量 |
wr_data_count | out | 已寫入的數據數量 |
FIFO的數據寫入和讀出都是按時鐘的上升沿操做的,當wr_en信號爲高時寫入FIFO數據,當almost_full信號有效時,表示FIFO只能再寫入一個數據,一旦寫入一個數據了,full信號就會拉高,若是在full的狀況下wr_en仍然有效,也就是繼續向FIFO寫數據,則FIFO的overflow就會有效,表示溢出。
標準FIFO寫時序
當rd_en信號爲高時讀FIFO數據,數據在下個週期有效。valid爲數據有效信號,almost_empty表示還有一個數據讀,當再讀一個數據,empty信號有效,若是繼續讀,則underflow有效,表示下溢,此時讀出的數據無效。
標準FIFO讀時序
而從FWFT模式讀數據時序圖能夠看出,rd_en信號有效時,有效數據D0已經在數據線上準備好有效了,不會再延後一個週期。這就是與標準FIFO的不一樣之處。
FWFT FIFO讀時序
關於FIFO的詳細內容可參考pg057文檔,可在xilinx官網下載。
3. FIFO測試程序編寫
咱們按照異步FIFO進行設計,用PLL產生出兩路時鐘,分別是100MHz和75MHz,用於寫時鐘和讀時鐘,也就是寫時鐘頻率高於讀時鐘頻率。
`timescale1ns/1ps ////////////////////////////////////////////////////////////////////////////////// module fifo_test ( input clk, //25MHz時鐘 input rst_n //復位信號,低電平有效 ); reg [15:0] w_data ; //FIFO寫數據 wire wr_en ; //FIFO寫使能 wire rd_en ; //FIFO讀使能 wire[15:0] r_data ; //FIFO讀數據 wire full ; //FIFO滿信號 wire empty ; //FIFO空信號 wire[8:0] rd_data_count ; //可讀數據數量 wire[8:0] wr_data_count ; //已寫入數據數量 wire clk_100M ; //PLL產生100MHz時鐘 wire clk_75M ; //PLL產生100MHz時鐘 wire locked ; //PLL lock信號,可做爲系統復位信號,高電平表示lock住 wire fifo_rst_n ; //fifo復位信號, 低電平有效 wire wr_clk ; //寫FIFO時鐘 wire rd_clk ; //讀FIFO時鐘 reg [7:0] wcnt ; //寫FIFO復位後等待計數器 reg [7:0] rcnt ; //讀FIFO復位後等待計數器 wire clkbuf ; BUFG BUFG_inst ( .O(clkbuf),// 1-bit output: Clock output. .I(clk)// 1-bit input: Clock input. ); //例化PLL,產生100MHz和75MHz時鐘 clk_wiz_0 fifo_pll ( // Clock out ports .clk_out1(clk_100M), // output clk_out1 .clk_out2(clk_75M), // output clk_out2 // Status and control signals .reset(~rst_n), // input reset .locked(locked), // output locked // Clock in ports .clk_in1(clkbuf) // input clk_in1 ); assign fifo_rst_n = locked ; //將PLL的LOCK信號賦值給fifo的復位信號 assign wr_clk = clk_100M ; //將100MHz時鐘賦值給寫時鐘 assign rd_clk = clk_75M ; //將75MHz時鐘賦值給讀時鐘 /* 寫FIFO狀態機 */ localparam W_IDLE =1 ; localparam W_FIFO =2 ; reg[2:0] write_state; reg[2:0] next_write_state; always@(posedge wr_clk