零基礎(chǔ)學(xué)FPGA (十八) 談可編程邏輯設(shè)計思想與技巧!對您肯定有用!
今天給大家?guī)淼氖俏覀冊?a class="contentlabel" href="http://m.butianyuan.cn/news/listbylabel/label/FPGA">FPGA設(shè)計中經(jīng)常要遇到的設(shè)計技巧與思想,即乒乓操作,串并轉(zhuǎn)換,流水線操作和跨時鐘域信號的同步問題。
本文引用地址:http://m.butianyuan.cn/article/273855.htm之前也看過一些書,也在網(wǎng)上找過一些資料,不過小墨發(fā)現(xiàn)大部分都是理論講解,僅僅是給一個框圖就沒事了,或者是好幾個網(wǎng)站的資料都是一樣的,都是復(fù)制的一個地方的,僅僅是講解,沒有實例,要不就是某個網(wǎng)站提供源碼,但是要注冊,還要花什么積分,沒有積分還得要錢...很不利于初學(xué)者的學(xué)習(xí)(人與人之間怎么就不能多點信任呢~還要錢...)。所以小墨想寫這么一篇文章來介紹一下這4種思想,理論部分書上多得是,我就不過多的解釋,主要給大家講一些實例型的幫大家理解。
一、乒乓操作
乒乓操作主要用于數(shù)據(jù)流的處理,是用面積換取速度的體現(xiàn)之一,要知道面積與速度的互換貫穿FPGA設(shè)計的始終,下面先給一個框圖
我先來解釋一下乒乓操作的過程:
首先數(shù)據(jù)需要通過一個2選一數(shù)據(jù)選擇器,在第一個時鐘周期將數(shù)據(jù)緩存到緩存模塊1,常用的緩存模塊可以是fifo,雙口RAM(DPRAM),單口RAM(SPRAM),第二個時鐘周期的時候,數(shù)據(jù)流開始往緩存模塊2里面寫數(shù)據(jù),與此同時,預(yù)處理模塊會從緩存模塊1里面讀取數(shù)據(jù),到了第三個時鐘周期數(shù)據(jù)流再往緩存模塊1里面寫數(shù)據(jù),與此同時,預(yù)處理模塊2開始從緩存模塊2讀取數(shù)據(jù),周而復(fù)始...這樣,輸入數(shù)據(jù)流和輸出數(shù)據(jù)流按節(jié)拍來回切換,可以使數(shù)據(jù)沒有停頓的進(jìn)行傳輸,使傳輸速率大大提高。
小墨同學(xué)發(fā)現(xiàn),在給這個框圖配實例的時候,幾乎所有的網(wǎng)站都是這個解釋,我用紅字標(biāo)出,個人感覺解釋的不怎么樣,還有些地方是錯的
假設(shè)端口 A 的輸入數(shù)據(jù)流的速率為 100Mbps ,乒乓操作的緩沖周期是 10ms 。以下分析各個節(jié)點端口的數(shù)據(jù)速率。
A 端口處輸入數(shù)據(jù)流速率為 100Mbps ,在第 1 個緩沖周期 10ms 內(nèi),通過 “ 輸入數(shù)據(jù)選擇單元 ” ,從 B1 到達(dá) DPRAM1 。 B1 的數(shù)據(jù)速率也是 100Mbps , DPRAM1 要在 10ms 內(nèi)寫入 1Mb 數(shù)據(jù)。同理,在第 2 個 10ms ,數(shù)據(jù)流被切換到 DPRAM2 ,端口 B2 的數(shù)據(jù)速率也是 100Mbps , DPRAM2 在第 2 個 10ms 被寫入 1Mb 數(shù)據(jù)。在第 3 個 10ms ,數(shù)據(jù)流又切換到 DPRAM1 , DPRAM1 被寫入 1Mb 數(shù)據(jù)。
仔細(xì)分析就會發(fā)現(xiàn)到第 3 個緩沖周期時,留給 DPRAM1 讀取數(shù)據(jù)并送到 “ 數(shù)據(jù)預(yù)處理模塊 1” 的時間一共是 20ms 。有的工程師困惑于 DPRAM1 的讀數(shù)時間為什么是 20ms ,這個時間是這樣得來的:首先,在在第 2 個緩沖周期向 DPRAM2 寫數(shù)據(jù)的 10ms 內(nèi), DPRAM1 可以進(jìn)行讀操作;另外,在第 1 個緩沖周期的第 5ms 起 ( 絕對時間為 5ms 時刻 ) , DPRAM1 就可以一邊向 500K 以后的地址寫數(shù)據(jù),一邊從地址 0 讀數(shù),到達(dá) 10ms 時, DPRAM1 剛好寫完了 1Mb 數(shù)據(jù),并且讀了 500K 數(shù)據(jù),這個緩沖時間內(nèi) DPRAM1 讀了 5ms ;在第 3 個緩沖周期的第 5ms 起 ( 絕對時間為 35ms 時刻 ) ,同理可以一邊向 500K 以后的地址寫數(shù)據(jù)一邊從地址 0 讀數(shù),又讀取了 5 個 ms ,所以截止 DPRAM1 第一個周期存入的數(shù)據(jù)被完全覆蓋以前, DPRAM1 最多可以讀取 20ms 時間,而所需讀取的數(shù)據(jù)為 1Mb ,所以端口 C1 的數(shù)據(jù)速率為: 1Mb/20ms=50Mbps 。因此, “ 數(shù)據(jù)預(yù)處理模塊 1” 的最低數(shù)據(jù)吞吐能力也僅僅要求為 50Mbps 。同理, “ 數(shù)據(jù)預(yù)處理模塊 2” 的最低數(shù)據(jù)吞吐能力也僅僅要求為 50Mbps 。換言之,通過乒乓操作, “ 數(shù)據(jù)預(yù)處理模塊 ” 的時序壓力減輕了,所要求的數(shù)據(jù)處理速率僅僅為輸入數(shù)據(jù)速率的 1/2 。
雖然各個網(wǎng)站上都是這么解釋的,但是個人感覺解釋的不怎么樣,下面我用我自己的理解給大家解釋一下這個例子
先看我給大家畫的一個圖,雖然畫的不怎么樣
這里我們只計算緩存模塊1的速率
首先看第一個周期10ms,數(shù)據(jù)流往緩存模塊1里面寫數(shù)據(jù),到第5ms時,預(yù)處理模塊1開始從緩存模塊1里面讀數(shù)據(jù),到10ms時,緩存模塊1寫了1M數(shù)據(jù),讀了5K數(shù)據(jù),下面切換到第二個周期,由于在第二個周期的時候預(yù)處理模塊1還可以從緩存模塊1里面讀數(shù)據(jù),所以到第15ms時,緩存模塊1里面的數(shù)據(jù)被讀完
到了第三個時鐘周期,也就是從第20ms開始數(shù)據(jù)流往緩存模塊1寫數(shù)據(jù),到第25ms時,預(yù)處理模塊開始從緩存模塊讀數(shù)據(jù),直到35ms時才讀完,這樣我們來算一下,在第一個時鐘周期讀了5K數(shù)據(jù),注意我上面畫的時鐘周期數(shù),就是那個半圓形的,
在第三個時鐘周期讀了5k數(shù)據(jù),注意每個時鐘周期只有5K,另外5K到了下一個時鐘周期了,所以我們不考慮,我們只考慮緩存模塊1的速率。再看一下時間,從第10ms讀完第一個5K,到第30ms讀完第2個5k,共用了20ms,讀了1M數(shù)據(jù),所以速率為1M/20ms=50M/s。
下面再給大家講一個實例,具體代碼我會附在文章后面
用state來控制乒乓操作的來回切換
根據(jù)剛才講的,控制緩存器的讀寫,這里只列些部分代碼,具體代碼請大家在文章后面下載
下面附上仿真時序圖,我在testbench中將數(shù)據(jù)設(shè)為從0 遞增的,可以看到仿真波形中是將奇偶數(shù)分開的,證明我們代碼是正確的
二、串并轉(zhuǎn)換
串并轉(zhuǎn)換總的來說就是將串行輸入信號轉(zhuǎn)換為并行輸出,也是用面積換取速度的一種方法,串并轉(zhuǎn)換總的來說比較簡單,小墨就只給大家講一下我自己寫的代碼吧
首先要先對串入信號進(jìn)行采集,加入我們是8位一輸出,每進(jìn)來一位數(shù)據(jù),我們便將原數(shù)據(jù)左移一位,保證數(shù)據(jù)是高位在前
然后再將數(shù)據(jù)并行輸出即可,下面附上仿真波形,我在testbench中給串入信號設(shè)為隨機(jī)數(shù),看仿真圖的,第一串信號為1101_1011,一位一位的移進(jìn)寄存器可以由波形的,分別是1,3,6……所以我們的代碼是正確的
三、流水線操作
流水線操作是高速設(shè)計中的一種常用手段,如果摸個設(shè)計的處理流程分為若干個步驟,而且數(shù)據(jù)處理是單向流的,也就是沒有反饋或者迭代運算,前一個步驟是后一個步驟的輸出,我們就可以采用流水線設(shè)計的方法來提高設(shè)計速率。
舉個例子,假如我們要計算A+B+C的值,如果不用流水線操作的話,那么需要先計算A+B的值,再計算A+B+C的值,需要兩個時鐘周期,如果我用了流水線操作那么我需要在兩個always塊中分別計算sum1= A+B,sum2= sum1+C,由于兩個always塊是并行的,輸出數(shù)據(jù)只需要等待一個時鐘周期,以后就可以有數(shù)據(jù)源源不斷的輸出,就像流水線一樣,從而提高系統(tǒng)速率
下面我們來設(shè)計一個實例,假如我要采集一系列的32位數(shù)據(jù),要對它進(jìn)行處理,處理方式假如是,先對這個數(shù)據(jù)進(jìn)行加16運算,再進(jìn)行壓縮為16位數(shù)據(jù)運算,再進(jìn)行減10運算
,最后進(jìn)行取低8位運算,采用流水線設(shè)計的話,輸出結(jié)果只需要等待幾個時鐘周期,以后就會有源源不斷地數(shù)據(jù)輸出,流程框圖如下,代碼請在后面下載
我在testbench中定義輸入信號是隨機(jī)的32位信號,分別進(jìn)行分級處理,每處理完一級要給下一級發(fā)使能信號,并把數(shù)據(jù)送到下一級,例如當(dāng)?shù)谝患壥鼓苄盘柕絹頃r,數(shù)據(jù)為29,29加16為45,即第一級輸出信號,對45取前16位仍為45,45減10為35,35取低8位仍為35,對照波形,證明我們的設(shè)計是對的
四、跨時鐘域信號同步
先來看一張圖
這個圖的意思就是,脈沖信號為一個時鐘信號,FPGA要對其進(jìn)行計數(shù),在CPU給FPGA發(fā)送讀信號的時候,將計數(shù)器的值送至CPU的數(shù)據(jù)總線, 這里就涉及三個時鐘信號,一個脈沖信號,一個CPU的讀信號,一個FPGA的自身時鐘,這三個時鐘是不同步的,我們這樣想,假如在脈沖計數(shù)的時鐘,cnt是自加1的,由于三個時鐘不同步,CPU的讀信號隨時都有可能來,加入當(dāng)cnt自加的時候,也就是cnt = cnt +1,這是對cnt的寫狀態(tài),突然來一個CPU的讀信號,即那么就要把cnt送到數(shù)據(jù)總線,即data < = cnt,這是一個讀狀態(tài),試問,一個數(shù)據(jù)既要讀又要寫,那讀的是寫之前的數(shù)據(jù)呢還是寫之后的數(shù)據(jù)呢?這就是亞穩(wěn)態(tài),確切就是不確定的意思,所以,我們要將不同的時鐘盡心同步處理,即在一個時鐘的控制下進(jìn)行脈沖計數(shù)和讀操作,這樣就不會發(fā)生亞穩(wěn)態(tài)了,要知道,在一個大的系統(tǒng)中,亞穩(wěn)態(tài)的危害是很大的
要解決同步問題,我們可以用FIFO,DPRAM 進(jìn)行同步,即用其他時鐘域?qū)ifo進(jìn)行寫操作,再用FPGA對fifo進(jìn)行讀操作,但要注意是否有數(shù)據(jù)溢出,還有一種方法就是邊沿脈沖檢測法,這里我們講第二種
即采用兩級寄存器,這兩級寄存器均有FPGA的時鐘控制,具體操作就是將不同域的信號都先賦值給第一級寄存器,再在另一個always塊中把第一級寄存器的值賦給第二級寄存器,如果是信號是高脈沖,那么就把第二級寄存器取反與第一級寄存器相與,便會得到一個高的脈沖采樣信號,用這個信號在檢測其他域信號的到來,如果是信號是低脈沖,那么就把第一級寄存器取反與第二級寄存器相與,同樣得到一個高的脈沖采樣信號,用這個信號在檢測其他域信號的到來,小墨同學(xué)把它記為“上2下1”原則,方便記憶~
具體代碼在前面鍵盤部分已經(jīng)有所講解,這里就不副代碼了
寫了好幾個小時,手都敲酸了,還望各位大神多多指教,有什么講的不對的地方還請指出,一起進(jìn)步~
fpga相關(guān)文章:fpga是什么
塵埃粒子計數(shù)器相關(guān)文章:塵埃粒子計數(shù)器原理 脈沖點火器相關(guān)文章:脈沖點火器原理
評論