精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

FPGA學習筆記:FIFO IP核的使用方法

CHANBAEK ? 來源:小小研究生 ? 作者: xxyjs ? 2023-09-07 18:30 ? 次閱讀

理論知識

FIFO(First In First Out, 先入先出 ),是一種數據緩沖器,用來實現數據先入先出的讀寫方式。數據按順序寫入 FIFO,先被寫入的數據同樣在讀取的時候先被讀出,所以 FIFO存儲器沒有地址線,有一個寫端口和一個讀端口。

FIFO 存儲器主要是作為緩存,應用在同步時鐘系統和異步時鐘系統中,分為 SCFIFO(同步 FIFO)和 DCFIFO(異步 FIFO)。后面實例中如:多比特數據做跨時鐘域的轉換、前后帶寬不同步等都用到了FIFO。

同步FIFO-SCFIFO

SCFIFO IP核配置

圖片

圖片

圖片

full:寫滿標志位,有效表示 FIFO 已經存儲滿了,此時禁止再往FIFO中寫入數據,防止數據溢出丟失。當寫入數據量達到FIFO設置的最大空間時,時鐘上升沿寫入最后一個數據同時full拉高;讀取數據時隨時鐘上升沿觸發同時拉低。

empty:讀空標志位,有效表示 FIFO 中已經沒有數據了,此時禁止FIFO繼續再讀出數據,否則讀出的將是無效數據。寫入數據同時拉低;讀到最后一個數據同時拉高。

usedw:顯示當前FIFO中已存數據個數,寫第一個數據時就置1,空或滿時值為0(滿是因為寄存器溢出)。

almost full:幾乎滿標志信號,我們可以控制FIFO快要被寫滿的時候和full信號的作用一樣。

almost empty:幾乎空標志信號,我們可以控制FIFO快要被讀空的時候和empty信號的作用一樣。

Asynchronous clear:異步復位信號,用于清空FIFO。

Synchronous clear:同步復位信號,用于清空FIFO。

后面三個沒有使用

圖片

圖片

圖片

圖片

SCFIFO IP核調用

我們需要寫一個頂層模塊,并通過testbench定義激勵來觀察信號變化,驗證SCFIFO IP核。我們可以看到生成的模塊文件中有以下幾個端口,頂層模塊需要進行實例化

圖片

輸入信號有:sys_clk、輸入256個8bit的數據pi_data(值為十進制0~255),輸入數據有效的標志信號pi_flag,寫請求信號rdreq。輸出信號有:讀取的數據po_data、空標志信號empty、滿標志信號full、指示FIFO中存在數據個數的信號usedw。

編寫代碼

module fifo(
input wire sys_clk , 
input wire [7:0] pi_data ,
input wire pi_flag , 
input wire rdreq , 
output wire [7:0] po_data ,
 output wire empty , 
 output wire full , 
 output wire [7:0] usedw 
 );


 scfifo_256x8 scfifo_256x8_inst(
 .clock (sys_clk ), 
 .data (pi_data ), 
 .rdreq (rdreq ), 
 .wrreq (pi_flag ),
 .empty (empty ), 
 .full (full ), 
 .q (po_data ), 
 .usedw (usedw ) 
 );
 endmodule

圖片

編寫testbench

//reg define
reg sys_clk ;
reg [7:0] pi_data ;
reg pi_flag ;
reg rdreq ;
reg sys_rst_n ;
reg [1:0] cnt_baud ;


 //wire define
 wire [7:0] po_data ;
 wire empty ;
 wire full ;
 wire [7:0] usedw ;


 //初始化系統時鐘、復位
 initial begin
 sys_clk = 1'b1;
 sys_rst_n <= 1'b0;
 #100;
 sys_rst_n <= 1'b1;
 end


 //sys_clk:模擬系統時鐘,每10ns電平翻轉一次,周期為20ns,頻率為50MHz
 always #10 sys_clk = ~sys_clk;


 //cnt_baud:計數從0到3的計數器,用于產生輸入數據間的間隔
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt_baud <= 2'b0;
 else if(&cnt_baud == 1'b1)
 cnt_baud <= 2'b0;
 else
 cnt_baud <= cnt_baud + 1'b1;


 //pi_flag:輸入數據有效標志信號,也作為FIFO的寫請求信號
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 pi_flag <= 1'b0;
 else if((cnt_baud == 2'd0) && (rdreq == 1'b0))
 pi_flag <= 1'b1;
 else
 pi_flag <= 1'b0;


 //pi_data:輸入頂層模塊的數據,要寫入到FIFO中的數據
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 pi_data <= 8'b0;
 else if((pi_data == 8'd255) && (pi_flag == 1'b1))
 pi_data <= 8'b0;
 else if(pi_flag == 1'b1) 
 pi_data <= pi_data + 1'b1;


 //rdreq:FIFO讀請求信號
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 rdreq <= 1'b0;
 else if(full == 1'b1) 
 rdreq <= 1'b1;
 else if(empty == 1'b1) 
 rdreq <= 1'b0;


 fifo fifo_inst(
 .sys_clk (sys_clk ), 
 .pi_data (pi_data ),
 .pi_flag (pi_flag ), 
 .rdreq (rdreq ),
 .po_data (po_data ), 
 .empty (empty ), 
 .full (full ), 
 .usedw (usedw ) 
 );


 endmodule

初始化:初始時鐘為高電平,復位有效,延遲100ns后復位釋放

模擬時鐘:每隔10ns翻轉,時鐘周期20ns,頻率50MHz

輸入間隔計數器cnt_baud:從0-3計數,復位和溢出歸0,其他情況+1,這里溢出判斷條件(cnt_baud=11)用的是位與為1

輸入有效標志信號pi_flag:也是寫請求信號,變化條件是時鐘上升沿和復位下降沿。復位有效時歸0;計數0且沒有讀請求時拉高相當于四個時鐘周期產生一次;其他情況歸0

輸入數據pi_data:是要寫到FIFO中的數據,變化條件是時鐘上升沿和復位下降沿。復位有效時歸0;輸入255且pi_flag有效時歸0;其他情況+1,意味著輸入數據從0-255循環

讀請求rdreq:變化條件是時鐘上升沿和復位下降沿。復位有效時歸0;full信號拉高時也拉高說明存滿該讀了;empty拉高時就歸0說明讀空禁讀了

實例化

波形變化

圖片

我們選擇的是普通模式,讀出數據比讀使能晚一拍圖片

圖片

對比一下"先出數據FIFO模式"的波形,就可以看出延遲不延遲一拍的區別,這里沒有演示,實際上只需要在下面這一步時選擇先出數據模式即可

圖片

圖片

異步FIFO-SCFIFO

DCFIFO IP核配置

命名為"dcfifo_256x8to128x16",我們調用的dcfifo是輸入256個深度8位寬、輸出128個深度16位寬

圖片

圖片

圖片

圖片

圖片

圖片

圖片

DSCFIFO IP核調用

我們需要寫一個頂層模塊,并通過testbench定義激勵來觀察信號變化,驗證DCFIFO IP核。我們可以看到生成的模塊文件中有以下幾個端口,頂層模塊需要進行實例化

圖片

輸入信號 :50MHz寫時鐘wrclk,輸入256個8bit的數據pi_data(值為十進制0~255),輸入數據有效的標志信號pi_flag,25MHz的讀時鐘rdclk,寫請求信號rdreq。 輸出信號 :同步于wrclk的空標志信號wrempty,同步于wrclk的滿標志信號wrfull,同步于wrclk指示FIFO中存在數據個數的信號wrusedw,從FIFO中讀取的數據po_data,同步于rdclk的FIFO空標志信號rdempty,同步于rdclk 的FIFO滿標志信號rdfull,同步于rdclk指示FIFO中存在數據個數的信號rdusedw。

編寫代碼

module fifo
(
//同步于FIFO寫時鐘
input wire wrclk , 
input wire [7:0] pi_data , 
input wire pi_flag , 
 //同步于FIFO讀時鐘
 input wire rdclk , 
 input wire rdreq , 
 //同步于FIFO寫時鐘
 output wire wrempty ,
 output wire wrfull , 
 output wire [7:0] wrusedw ,
 //同步于FIFO讀時鐘
 output wire [15:0] po_data ,
 output wire rdempty , 
 output wire rdfull , 
 output wire [6:0] rdusedw 
 );


 dcfifo_256x8to128x16 dcfifo_256x8to128x16_inst
 (
 .data (pi_data), //input [7:0] data
 .rdclk (rdclk ), //input rdclk
 .rdreq (rdreq ), //input rdreq
 .wrclk (wrclk ), //input wrclk
 .wrreq (pi_flag), //input wrreq
 .q (po_data), //output [15:0] q
 .rdempty(rdempty), //output rdempty
 .rdfull (rdfull ), //output rdfull
 .rdusedw(rdusedw), //output [6:0] rdusedw
 .wrempty(wrempty), //output wrempty
 .wrfull (wrfull ), //output wrfull
 .wrusedw(wrusedw) //output [7:0] wrusedw
 );


 endmodule

編寫testbench

`timescale 1ns/1ns
module tb_fifo();


//reg define
reg wrclk ;
reg [7:0] pi_data ;
reg pi_flag ;
reg rdclk ;
reg rdreq ;
reg sys_rst_n ;
reg [1:0] cnt_baud ;
reg wrfull_reg0 ;
reg wrfull_reg1 ;


//wire define
wire wrempty ;
wire wrfull ;
wire [7:0] wrusedw ;
wire [15:0] po_data ;
wire rdempty ;
wire rdfull ;
wire [6:0] rdusedw ;


//初始化時鐘、復位
initial begin
wrclk = 1'b1;
rdclk = 1'b1;
sys_rst_n <= 1'b0;
#100;
sys_rst_n <= 1'b1;
end


//wrclk:模擬FIFO的寫時鐘,每10ns電平翻轉一次,周期為20ns,頻率為50MHz
always #10 wrclk = ~wrclk;
//rdclk:模擬FIFO的讀時鐘,每20ns電平翻轉一次,周期為40ns,頻率為25MHz
always #20 rdclk = ~rdclk;


//cnt_baud:計數從0到3的計數器,用于產生輸入數據間的間隔
always@(posedge wrclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_baud <= 2'b0;
else if(&cnt_baud == 1'b1)
cnt_baud <= 2'b0;
else
cnt_baud <= cnt_baud + 1'b1;


//pi_flag:輸入數據有效標志信號,也作為FIFO的寫請求信號
always@(posedge wrclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_flag <= 1'b0;
else if((cnt_baud == 2'd0) && (rdreq == 1'b0))
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;


//pi_data:輸入頂層模塊的數據,要寫入到FIFO中的數據
always@(posedge wrclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_data <= 8'b0;
else if((pi_data == 8'd255) && (pi_flag == 1'b1))
pi_data <= 8'b0;
else if(pi_flag == 1'b1) 
pi_data <= pi_data + 1'b1;


//將同步于rdclk時鐘的寫滿標志信號wrfull在rdclk時鐘下打兩拍
always@(posedge rdclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
wrfull_reg0 <= 1'b0;
wrfull_reg1 <= 1'b0;
end
else
begin
wrfull_reg0 <= wrfull;
wrfull_reg1 <= wrfull_reg0;
end


//rdreq:FIFO讀請求信號同步于rdclk時鐘
always@(posedge rdclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rdreq <= 1'b0;


//如果wrfull信號有效就立刻讀,則不會看到rd_full信號拉高,
//所以此處使用wrfull在rdclk時鐘下打兩拍后的信號
else if(wrfull_reg1 == 1'b1)
rdreq <= 1'b1;
else if(rdempty == 1'b1)//當FIFO中的數據被讀空時停止讀取FIFO中的數據
rdreq <= 1'b0;

 fifo fifo_inst(
 .wrclk (wrclk ), 
 .pi_data(pi_data),
 .pi_flag(pi_flag),
 .rdclk (rdclk ),
 .rdreq (rdreq ), 
 .wrempty(wrempty), 
 .wrfull (wrfull ), 
 .wrusedw(wrusedw), 
 .po_data(po_data), 
 .rdempty(rdempty), 
 .rdfull (rdfull ), 
 .rdusedw(rdusedw) 
 );


 endmodule

初始化:和同步fifo的區別在于讀寫時鐘是異步的,需要初始化兩個時鐘

時鐘模擬:寫時鐘50MHz每隔10ns翻轉一次,讀時鐘25MHz每隔20ns翻轉一次

cnt_baud:計數器是基于寫時鐘的,將變化條件中時鐘上升沿改為寫時鐘的上升沿

pi_flag:輸入數據有效標志信號,基于寫時鐘,同上

pi_data:輸入數據,基于寫時鐘,同上

wrfull:寫滿標志信號,基于讀時鐘,變化條件是讀時鐘上升沿和復位下降沿。wrfull在讀時鐘下打兩拍,(always塊中的語句是順序執行的,使用兩個寄存器b,c,令b=輸入a,c=b,并輸出c,那么c相對于a而言波形不會產生變化,只是有兩個時鐘周期的延遲,這個就叫打拍,使用幾個寄存器就是延遲幾個周期就是打幾拍),這里打兩拍的原因是如果wrfull有效立刻就讀,就看不到rd_full拉高

rdreq:讀請求信號,基于讀時鐘,變化條件是讀時鐘上升沿和復位下降沿。復位時歸0;寫滿信號打兩拍之后的信號拉高就拉高表示寫滿需要讀,讀空信號拉高就拉低表示讀空不能讀

波形變化

圖片

可以看到當pi_flag為高且pi_data為255的同時wrfull滿標志信號先拉高了,延后一段時間rdfull滿標志信號也拉高了,說明FIFO的存儲空間已經滿了。wrfull滿標志信號和rdfull滿標志信號同步于 不同的時鐘 ,所以拉高的時間不同步。

還可以看到wrusedw信號是8位的計數到255,而rdusedw信號是7位的計數到127,因為輸入是8btit的,輸出是16bit的,8256=16128。wrusedw信號從255變成了0、rdusedw信號從127變成0的原因和SCFIFO中的情況一樣,都是因為數據存儲滿了,FIFO內部的計數器溢出所導致的。

另外可以看出讀出的16bit數據,是兩次的輸入8bit數據拼湊而成,先輸入的在低位,后輸入的在高位,例如輸入00,01,02,03...,兩次輸入的數據拼湊為01_00,03_02進行輸出。

如果不打兩拍會發生什么呢?我們來看波形

圖片

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FPGA
    +關注

    關注

    1626

    文章

    21665

    瀏覽量

    601818
  • 存儲器
    +關注

    關注

    38

    文章

    7452

    瀏覽量

    163602
  • 緩沖器
    +關注

    關注

    6

    文章

    1917

    瀏覽量

    45450
  • fifo
    +關注

    關注

    3

    文章

    387

    瀏覽量

    43548
  • IP核
    +關注

    關注

    4

    文章

    326

    瀏覽量

    49428
收藏 人收藏

    評論

    相關推薦

    關于FPGA IP

    對于深入學習使用FPGA的小伙伴們,特別是一些復雜的、大規模的設計應用,適宜的IP核對開發能起到事半功倍的作用。IP的概念與我們sdk里庫
    發表于 04-29 21:01

    FPGAIP使用技巧

    的工作原理、使用方法和限制條件。 參數化配置 : 如果IP提供了參數化配置選項,可以根據項目需求進行配置。例如,對于RAM IP
    發表于 05-27 16:13

    #FPGA點撥 生成FIFOIP

    fpgaIP
    電子技術那些事兒
    發布于 :2022年10月12日 21:52:56

    #硬聲創作季 #FPGA FPGA-27-04 Quartus中fifo IP介紹與仿真測試-1

    fpgafifoIP
    水管工
    發布于 :2022年10月29日 02:28:30

    #硬聲創作季 #FPGA FPGA-27-04 Quartus中fifo IP介紹與仿真測試-2

    fpgafifoIP
    水管工
    發布于 :2022年10月29日 02:28:50

    #硬聲創作季 #FPGA FPGA-27-04 Quartus中fifo IP介紹與仿真測試-3

    fpgafifoIP
    水管工
    發布于 :2022年10月29日 02:29:13

    #硬聲創作季 #FPGA FPGA-27-04 Quartus中fifo IP介紹與仿真測試-4

    fpgafifoIP
    水管工
    發布于 :2022年10月29日 02:29:34

    LabVIEW FPGA CORDIC IP的arctan使用方法

    使用LabVIEW FPGA模塊中的CORDIC IP,配置arctan(X/Y)算法,配置完成之后,IP只有一個輸入。我參考網上VHD
    發表于 09-10 20:07

    基于IPFPGA設計方法是什么?

    的分類和特點是什么?基于IPFPGA設計方法是什么?
    發表于 05-08 07:07

    FPGA零基礎學習IP CORE 之 FIFO設計

    學習FPGA設計方法及設計思想的同時,實操結合各類操作軟件,會讓你在技術學習道路上無比的順暢,告別技術學習小BUG卡破腦殼,告別目前忽悠性
    發表于 03-15 16:19

    講解幾點關于FIFO IP使用時的注意事項

    FIFO?還是FIFO IP?這也需要寫總結嗎?太容易了吧。如果我是一個正在處于面試找工作中的年輕人,肯定關注的是如何手撕FIFO,這也是
    發表于 06-21 14:22 ?1423次閱讀
    講解幾點關于<b class='flag-5'>FIFO</b> <b class='flag-5'>IP</b><b class='flag-5'>核</b>使用時的注意事項

    如何在Vivado中配置FIFO IP

    Vivado IP提供了強大的FIFO生成器,可以通過圖形化配置快速生成FIFO IP
    的頭像 發表于 08-07 15:36 ?4053次閱讀
    如何在Vivado中配置<b class='flag-5'>FIFO</b> <b class='flag-5'>IP</b><b class='flag-5'>核</b>

    FPGA學習筆記:PLL IP使用方法

    IP(Intellectual Property)是知識產權的意思,半導體行業的IP是“用于ASIC或FPGA中的預先設計好的電路功能模塊”。一些常用的復雜的功能模塊(如FIFO、RA
    的頭像 發表于 08-22 15:04 ?4497次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>:PLL <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>

    FPGA學習筆記:ROM IP使用方法

    上一篇介紹了常用的鎖相環IP,這一節將介紹一種較為常用的 存儲類IP ——ROM的使用方法。ROM是 只讀存儲器 (Read-Only Memory),顧名思義,我們只能讀出事先存放
    的頭像 發表于 08-22 15:06 ?4701次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>:ROM <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>

    FPGA學習筆記:RAM IP使用方法

    我們知道除了只讀存儲器外還有隨機存取存儲器,這一篇將介紹另一種 存儲類IP ——RAM的使用方法。RAM是 隨機存取存儲器 (Random Access Memory),是一個易失性存儲器,斷電丟失。RAM工作時可以隨時從任何
    的頭像 發表于 08-29 16:46 ?3450次閱讀
    <b class='flag-5'>FPGA</b><b class='flag-5'>學習</b><b class='flag-5'>筆記</b>:RAM <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>