久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 10763|回復: 7
打印 上一主題 下一主題
收起左側

大話FPGA書(非常通俗易懂的學習資料)

  [復制鏈接]
跳轉到指定樓層
樓主
玩轉 FPGA 前言
一直以來都想寫點什么,關于 FPGA 設計,因為有點不太服氣。為什么同樣是設計,有些人可以好像玩一樣的擺弄,photoshop,很時尚,很跩。有些人可以用所謂的廣告創意玩弄人們的智商。而硬件工程師則一律的被人以為呆板沒有創意。我是說,為什么我們不可以享受設計本身的樂趣,發揮我們自己的創意,為什么就不可以很隨心所欲的擺弄我們手里的那些玩具到處炫耀,讓美女們看著我們的眼睛都發光?難道一定就是那些冷冰冰的 Datasheet, 死板的 Schedule, 老板的豬肝臉?所以我寫這些東西的目的,就是想讓大家可以和我一起起來,玩轉 FPGA。所以大家千萬別抱著學習的態度來看。看累了,不如去打打游戲,看煩了,不如自己去試著做幾個項目玩玩。FPGA 是可以玩的,而設計 FPGA 的工具也是很好玩的,為什么?我們先了解一下我們的玩具。和所有的玩具一樣,這款玩具也有它的適合玩家。你如果有一些準備,你可以玩得更開心些。首先是語言,你需要至少知道一樣設計方式吧。Verilog 或者 VHDL.我個人比較喜歡 Verilog,不過這并不重要。不會?那會畫電路圖也可以啊。或者呢,會用 Simulink 搭個模型什么的也可以。如果會寫一點 C,恐怕就更好了。那么什么是 FPGA (已經知道的朋友盡可以跳過去不看)。想知道學名,去查一下字典,想知道他的歷史,去問一下你的教授。我不說這些,因為我們的目的,就是玩。你應該知道芯片吧。對,好像因特爾的 CPU,還有 AMD。好像德州儀器的 DSP。還有 ASIC, ASSP, 反正現在這個世界,沒有芯片你恐怕活不下去。而學電子的,如果不知道芯片,那也不用活了。還有一樣東西,你一定也知道,就是 CD-RW, DVD-RW.反復可擦寫光盤。而 FPGA 就是反復可擦寫的芯片。這樣你就知道他能有多好玩了,是否還記得第一次拿到 CD-RW 的時候那種驚喜的感覺?想放什么就放什么,想做什么就做什么。你拿到的這東西就是一片巨大的空白,就看玩家怎么往里面塞東西了。 因為他已經是現成的半成品,完全不需要去等待漫長的流片時間,你就可以看到你的設計在板上實現。這就是為什么這個玩具,它可以玩,而且因為是數字電路,所以隨便你怎么玩,只要你不插錯電源,都可以。不會著火的安全玩具。

下面一個問題是,為什么要玩 FPGA。FPGA 一開始是一種附屬的玩具,主要的玩具是 ASIC。人們為了驗證 ASIC 設計的功能,往往用 FPGA 來測試。因為他不需要漫長的制造時間。就好像看看這個小孩子長什么樣吧,也就知道他長大了大概是什么樣子。但是現在這個小孩子居然也慢慢長大了。他開始普遍的被用在非常多的產品里面。首先一個原因是價格。現在的工藝水平是越來越高,這當然是好事情,但是壞事情是,也變得越來越貴。可以想象啊,線寬越來越窄,不是需要更厲害一點的放大鏡嗎?而這種高工藝導致的高價格是很多產量并不大的 ASIC 無法承受。而 FPGA 作為一個通用的器件呢,它完全可以去追求最新最好的工藝,而讓它的買家一起分攤它的成本。它是目前芯片業擁有利潤空間最大的一個分支。可以想象,如果有一天,FPGA 公司把這塊利潤釋放出來,對 ASIC,ASSP 設計公司的打擊是致命的。第二個原因,就是他可以玩,可以反復擦寫。玩這個,比玩 ASIC 要快很多,產品可以早點賣出去。另外如果有一天,你又想出了更好的玩法,你完全可以去把你已經賣給別人的東西換掉,變成更好的東西。而如果這個時候你面對的是你設計的ASIC,你只好哭吧。第三個原因,就好像廣告里面說的:方~~~~~便。

再來看看這套玩具里面有些什么.首先是硬件,各種款式的 FPGA 芯片,各種應用的開發板。根據各自己不同的玩法,選擇,拼接各種不同的產品系列。如果現成的不夠用了,完全可以自己做一塊。然后是工具。QuartusII,這是一個魔盒,它就好像 photoshop 一樣,可以把你原本看上去有點尷尬的照片,變成美輪美奐的藝術品。NiosII,嵌入式 CPU,是的,你沒聽錯,就是 CPU,而且是你想放多少就可以放多少的 CPU。還不過癮?那看看 DSPbuilder 吧(這是我的至愛)。幫你把 Simulink 模型算法變成最終硬件的工具。是的,你完全不需要寫一行代碼。好了,不要摩拳擦掌了,開始玩吧。

關于 QuartusII 的一些事情
QuartusII 其實就是一個轉換器。一個把你理解的邏輯語言轉換成為器件能理解的語言,然后可以讓 FPGA 按照你的想法去工作。我們寫的那些 VHDL 啦,Verilog 啦什么的,其實都是人類自己定義的語言,對機器來說,就是對牛彈琴了,它沒可能知道人類這些傻瓜坐在那里想做什么。所以為了交流,我們需要讓他們理解我們的意圖,而你也不至于因此而去學牛說話,所以,我們需要用 QuartusII,因為 QuartusII 就是幫助你進行這種翻譯的工具。我們分兩部分來完成這么一件事情,首先把你的邏輯思路轉變成用已經有的元件搭建出來的電路。好比你說我要一個加法,器件沒你那么聰敏,他不知道什么叫做加法,加法對他來說是沒有意義的。工具會把加法轉換成為一組邏輯,用與,或,與非,或非這些亂七八糟的連在一起,變成和加法結果一樣的電路。這樣器件一看就知道了,哦,對了,我有這些的。當然這個時候你再去看那些東西,可能就蒙了。這個過程就是綜合。綜合結果是一個網表文件(netlist),也就是一堆很無聊的電路。而這種電路還只是停留在概念上,并沒有映射到實物上面。
然后工具會做第二件事情: fitting。QuartusII 把你選擇的器件找出來,對照它擁有的資源來放剛才轉成的電路。FPGA 里面的資源都是現成已經做好的,好處是你不需要做,壞處是,你也改不了。第一步首先是放置,就是把那些邏輯一個個放到器件的相應位置上。最后,把所有的放置好的點連接起來。這樣,你的思想就在硬件上面完美的體現出來了。然后我們再回過來看看每個點都在做什么,把這些信息存成一個文件,以后你只需要每次告訴器件這個文件,就可以實現你的設計。
這一切都不需要你來做,工具都可以自動完成,因為對器件世界的理解,工具比你要熟悉的多,所以你可以相信,他一定比你做的好。但是這樣是不是太容易了呢?當然不會,否則就不好玩了,你需要知道工具去實現,因為很多事情是工具不曉得的,你需要告訴工具你的要求來實現你的設計。這就是約束。好像女孩子喜歡漂亮,當然不會隨便穿戴,要點綴這里,束縛那里,讓自己看上去至少很美。打扮沒有約束,可能頂多就是難看點。但是翻譯過程沒有約束,就完全不是一個東西了。所以,約束很重要,后果很嚴重。你要告訴工具很多信息。比如:時鐘信息,工具不可能聰明到知道你從外面送進來的時鐘是多少的。比如管腳信息,你要告訴他哪些輸入,哪些是輸出,而這些輸入輸出分別應該是什么樣子的。這些是最基本的信息,還可以提出一些更苛刻的要求出來。比如說功耗。QuartusII 在完成編譯以后會對編譯的結果進行分析,看是不是能滿足你的要求。如果不滿足,它可以再試幾次。最后告訴你:帥哥,按照你的要求,我們完成了工作了,或者說,小子,你的要求是在太過分了,我做不了。那么可能你得調整一下設計,代碼,約束條件,甚至器件。

到此為止,其實 QuartusII 的工作已經可以說完成了。但如果只是這樣,你一定會很郁悶,

因為你并不知道你的設計是不是真的可以工作。或者說,你會想知道你的設計為什么不工作。
所以必須提供仿真和 debug 工具。QuartusII 提供一個相對比較簡單的仿真工具,讓你可以通過畫波形圖的方式來做仿真。這種工具非常容易用,但是能力比較有限。他可以很直白的實現激勵和觀察輸出波形的平臺,但是他無法實現很好的交互能力。好比你需要因為一個信號而發動下一個動作時?你恐怕很難猜得出來什么時候這個信號就來了吧。所以很多時候,我們會比較喜歡用第三方工具 ModelSim. 這個東西不好的地方就是你需要自己寫仿真代碼。你會發現這是一件蠻痛苦的事情,很多時候仿真代碼比電路代碼本身還要復雜。但是,真的沒有辦法,我很同情你,因為只有你才知道你想做什么,沒有人能代替你來寫仿真。仿真畢竟只是仿真而已,不是真的,很多時候你會發現電路還是不能工作,雖然仿真看上去完全沒問題。千萬不要太自信的以為這一定就是工具的 bug,從而很興高采烈的報告說,我找到你們一個 bug。絕大多數的情況下,要么是因為你的約束有問題,要么是因為你的仿真和真實情況不符合。所以,QuartusII 不得不提供一種途徑,讓你看到,芯片里面到底發生了一些什么事情,那就是在片 debug 工具,signaltapII。我知道名字不太好聽,但是其實真的還蠻有用的。
QuartusII 就是這樣一個工具,很簡單,但要玩得好,還是需要一點功夫的。后面我會比較細化的聊聊怎么玩這個東西。我不會很老土的說怎么創建一個工具,然后按這里,按那里。這些要你自己去玩,去摸索,否則,完全沒有樂趣了。

門規
別擔心,這里不是黑幫。
我喜歡把寄存器比喻為門。所謂的電路就是由一堆這樣的門包圍著的。每個門都有一個相應的時鐘來驅動,在相同間隔后,門將會打開。一些信號從一個門出來,經過一系列的變化(組合邏輯)變成一個新的信號,走到另一個門口,當門打開的時候,進入。這就是 FPGA 里面發生的一切。或許速度會快一些,或許情況會復雜一些,但是大體就是這么回事而已。而我們要保證的就是所有的信號都可以高高興興來,安安全全回去。不會遲到,也不會早退,更不會被門夾到,就萬事大吉了。但是事情容易說不容易做,所以需要注意一些細節方面的問題。如果因為你把邏輯給做錯了,那我們就不提了。而有些事情,即使你感覺一切都做得足夠完美了,卻還是沒有結果。在這里提一些會有好處。

門規之組合電路篇
雖然我們要討論的是門,但其實我們更關注的應該是門與門之間發生的一切。因為門的作用只是把階段和另一個階段分割開來,而更多的事情,其實是在這個階段里面做的。門與門之間,或者門外面的,就都是這些組合電路了。組合電路最終影響了你的時鐘能夠飆到多快。

1. 進來的時候,請隨手關門
這是一個再簡單不過的規則。在進來的時候,請關一下門。相信如果你呆在一個有一部分沒有被包圍在墻和門里面的房子里,一定很沒安全感。尤其是在門外面的東西吧,你會整夜整夜的睡不著覺。所以進來的時候,最好可以隨手關門,把自己包圍在一個安全的環境里面。所以信號也是這樣,信號是很敏感很沒安全感的東西。所以,進來的時候最好被時鐘打一下。這在 FPGA 設計中是非常重要的,尤其是復位信號。外部信號的觸發事件是隨機的,連它自己都不曉得什么時候那個 reset 鍵就被按了一下,加上進來以后的線路會有一點延遲,恰好在時鐘觸發的時候,前面一個信號被觸發了,后一個信號恰好被門夾到。就好像指揮抬手的時候,鋼琴開始彈奏了,小提琴手還在擺 pose。 這樣導致的結果就是大家不是同時開始工作。
門分很多種,材質不一樣(時鐘頻率),大小不一樣(時鐘相位),還有很多屬性不同(全局時鐘?)。所以為了進入不同的區域,你必須關一下相應的門。這其實很容易理解,你進廚房,關廁所的門,就有點奇怪了。還是以復位信號為例,對所有你需要用到復位信號的時鐘域,最好可以被相應的時鐘打一下。提出這樣一點,是因為它經常被忽略,而且發生問題的狀況可能變成隨機的。如果你的設計仿真沒有問題,而在板子上發生一些隨機的事件,那么很有可能是你的異步信號造成的。

2. 在門與門之間請不要來回走動
門(寄存器)與門之間是什么?是組合邏輯電路。信號的傳遞就是不斷的打開一個門,然后進入另外一個門,這樣一級一級的不斷傳遞,你才可以一直從起點走到終點。在有些時候也許你并沒有注意,你在到達另外一個門之前,你轉了一個圈又回來了。雖然這只是一個簡單的圈,但是這個動作會被無限循環,因為這個動作沒有被時鐘限制。所以導致的后果可想而知了。舉一個最簡單的例子:
D = A + B + C;
Reg C = D + B;
A 和 B 都是輸入,而 C 是輸出,你會發現其實這個 C 偷偷的回去轉了一圈,而結果是使自己又多做了幾次循環。而最終結果是多少要看這段邏輯自身的延遲和你的時鐘頻率,對不起,誰都不可能預測結果。而且每次編譯的結果都會不同,因為編譯導致的電路延遲是隨機的。但是如果我們把 D 也用門關一下(寄存器),那么結果就會舒服了。
Reg D = A + B + C;
Reg C = D + B;
不妨在 QuartusII 里面嘗試這兩種電路。 工具會報告一個 combinational loop 的警告給你。也可以嘗試做一些仿真體會一下。

3. 不要為了省錢,用假門 (Latch Vs Register)
讓我們把這個門再好好的研究一下,首先是定義。我這里說的門更多是 flip-flop register. 作為現成的資源,它遍布于器件的四面八方。另外有一種叫 Latch 的東西,我把它叫做假門。
在普通數字電路中,人們會喜歡用到它。因為它的結構相對簡單,所以資源上比較節約。所以我們需要說說這個假門的問題。

那么首先需要了解一下什么是假門,其實就是一個偷工減料的門。我們來看一個簡單的圖:

這確實是一個再簡單不過的邏輯了,比 flip-flop 的那個寄存器要簡單許多。當 gate 為高的時候,Q 變成 D,否則,就保持 Q 的值。很顯然這是一個用電平來保存數據的一個邏輯,但是為什么我們不喜歡它呢?

1. 不穩定,和 flip-flop 做一個比較,register 是在開門的時候數據進去的,然后這個門馬上就關掉了,所以數據只要在開門的前后保持穩定,那么從輸出看都是可以保持一致的。但是 Latch 的結構中,當 Gate 為高的時候,Q 的數據會隨著 D 的變化而變化。所以他無法保持一個穩定的狀態。

2. 它給工具制造了麻煩。因為電路是由你設計的,工具并無法知道你的思路,所以他不會知道你想要的到底是什么時候的輸入。因為你現在門是一直那么開著的。在這過程中,狐貍也來過了,狼也來過了,老鼠也來過了,工具不知道究竟以什么為標準來判斷這個電路是不是能符合時序要求。這樣的話,或許你會很幸運的在一顆片子上面完成任務。但是一旦換一顆,情況就變了。

3. 最后,作為一個精打細算的人,我們需要知道他是不是真的就省了那些傳說中的資源了。大家不妨自己做一個 Latch 出來(QuartusII 的 megacore 中是可以找到 LPM_LATCH 的)。

真是不劃算,你發現其實整個查找表都給用上了。而后面一個簡簡單單的 register 可憐巴巴的放在那里用不到。作為 FPGA 設計中比較獨特的一個原則就是,這個世界不是你創造的,所以你必須去適應它,而不是頑固自己的意圖。換句話說:壞人也是人,不是說你不能做,但都已經告訴你壞人不好了,你干嘛還要去做呢?留一個問題給大家去嘗試,或者玩一下。什么狀況下,或者說怎么寫代碼的時候,可以把Latch 寫出來。4. 除了門,其他的一切過程都只是暫時的在 FPGA 中,除了門與門之間的延遲是固定的(時鐘頻率)外,一切的組合電路的延遲都是不確定的。你不能依靠一次編譯的延遲結果來做你的設計,雖然這樣看上去的效率會非常高。就好像接力跑一樣,可以一棒一棒的傳下去。但是電路是需要可以不斷重復的一個過充。相信每次接力跑交棒的時間點都是不同的吧,你再做一次編譯以后,你會發現整個世界都變了。所以在設計中,盡量避免使用這種手段。延遲鏈,經常會使用這種手段,比如幾級非門來增加延遲。但是它也是具有不穩定性的,所以在不到萬不得已的狀況下,不要用它來增加認為的延遲。延遲鏈在 ASIC 中另外一種用途是增加扇出。而這在 FPGA 設計中是畫蛇添足了。因為布線資源中已經加入了 buffer 了。記住這樣一個規律就好了,凡是沒有被門關過的信號都是不穩定的,都只是暫時的。

門規之時鐘篇
門本身沒什么復雜的地方,但是門的種類一多,麻煩就來了。而好玩的地方也來了。所以我們對門(主要是時鐘)的選擇就會有很多講究。好像廚房應該配什么門,臥室配什么門?對于門的屬性把握也影響到你知道工具工作的準確性。如果你給工具的信息本身就不是符合事實的話,那么結果一定是不堪的。所以,我們需要對門,提醒一些門規。

1. 再生門很多時候我們不得不用一些邏輯的結果作為時鐘去驅動一個門,我們且管他叫作再生門吧,這種門所造成的問題是最多不過的,因為有一些先天不足。所以我們把力氣主要多的放在這里。首先這些門的驅動時鐘是由組合電路組成的,還記得之前的規則么?所有的組合電路都是不可信的。是的,往往有很多的毛刺啊,或者中間過程啊不可避免的出現,這當然不是我們想要的東西。所以,在生成新的再生門之前,你最好把這個時鐘信號用原來的那種門在關一下。這樣你獲得的會是一個干凈的,純粹的時鐘信號。

2. 門之相關再生門也可以分成兩種,一種是鎖相環所產生的時鐘驅動的門。另一種是你用邏輯搭建出來的時鐘。就好像有的門是工廠制作的,有的門是你自己劈木頭造出來的,工廠造出來的驅動門會比較準確,效果比較好,可以省掉你很多麻煩,所以很多時候我們還是推薦用這種門。而且因為是工廠制造,所以工廠對這種驅動的屬性,狀態會非常清楚,所以在分析的時候,會自動獲得很多信息,而不需要你來提供。但是有的時候,你或許不得不自己造一個門。那么這個時候你就需要比較細心的呵護一下。首先就是剛才說的毛刺問題,然后就是相關性問題。你需要告訴工具你造的這個門和原始的那個門的關系。好比時鐘頻率,相位。工具是很蠢的,它沒可能了解高級生物的語言,所以你必須告訴它。所以再生門與原始門之相關性會非常重要 (derived clock )

3. 門鎖 (gated clock)門當然應該可以上鎖,就是可以把時鐘停掉,那么門就不會被打開了。而最大的好處是什么?對了,就是省電。門不會一直開來關去的,信號也不會頻繁的翻上墜下的。對芯片電力的貢獻可是相當大了。但是同時也帶來很多問題,主要是時鐘的不穩定性增強了。最最簡單的做法就是把門鎖信號和時鐘與一下。但是這樣的組合電路通過了查找表以后的驅動能力降低了,導致了時鐘從這一點到另一點的傳輸延遲變長了。另外你的門鎖信號上面可能本身帶有毛刺,那么可能反映到時鐘上,那結果就不得了了。你可能不小心就被門夾扁了。針對新的一些器件,器件本身可以提供一些時鐘控制模塊,當你需要使用門鎖的時候,盡量的使用這些模塊,會讓你的時鐘變得安全(clock control block)。或許你會說,我并不是太在乎是不是省電,我只是希望這一塊地方不需要因為新的數據而變化,等于是把功能停掉。那么這樣的話,你可以不需要去控制你的時鐘,而選擇控制你的數據。讓你的門鎖來選擇進去的是你剛才已經進去的信號,還是新的信號。想象一下,如果反復進去的都是剛才的信號,那么你的電路大部分情況下是不太會有變化的。這當然不是絕對的。但是這可以作為一種方法來避免不安全感。

當然總會有萬不得已無奈的時候,好比老板腦袋被門夾到了。你不得不使用邏輯電路來鎖門,而你的器件又沒有特定的模塊。那么最好的情況就是,你可以先用那個時鐘,把你的門鎖信號關一下。這樣的好處就是可以把毛刺信號完全的規避在門外面,使你的時鐘更加安全。

好了,好了,先就說這些好了,再說下去恐怕會因為門規太多,很多人要倒戈投降了。這些是比較容易被忽略的地方而已。如果還有什么補充,也可以一起交流一下。

你的 Q-zone,你做不了主

我的地盤我做主,這其實是一句鬼話。你很少真的有什么地盤你可以做主的,因為你很難作為規則制造者存在。你只有更好的依循規則,你才能更好的讓事情按照你的想法去做。所以為了做主你的地盤,你最好依照一些規則,而不是按照自己的喜好來做,好比寫代碼。

上電初始值
在通常的狀況下,所有的門在上電的時候輸出為低。但是這并不是不能改變的。你可以把上電設置為高,這樣綜合工具可能會做兩種事情,把輸出反向,或者使用 preset 控制(如果存在的話)把初始值放進門里。
當時上電為高的做法,并不是非常必要,因為你其實是可以使用復位信號來獲得你想要的初始狀態的。
如果你覺得這是必須的,那么有幾種方法你可以做:
z首先是在 QuartusII 里面你可以針對某個或者某些 門設置 power-up level 為高或低。
z在代碼中使用 altera_attribute
z直接寫代碼設置初始值:
reg q = 1'b1;
always @ (posedge clk or posedge aclr)
begin
if (aclr)
q <= 1'b0;
else
q <= d;
end

門的次級管理信號

每個門都有一些次級的管理裝置,好比清除信號啊,時鐘使能信號啊。而這些裝置當然都有他們自己的操作規律。如果你在寫代碼的時候可能適當的使用它們,那么綜合的時候很容易就可以使得王八看到綠豆,大家都對上了。其實實現一個功能是沒有問題的,但是如果你把功能按照它的自然規律來實現,從資源消耗還是很劃算的。當然我知道大家現在都很有錢,不太在乎這些的,但是省吃儉用似乎還是硬件設計師德傳統美德。你會發現年資越大的工程師在這方面越是注意,所以,如果你希望在別人眼里看上去比較牛的話,適當的使用這種手段,還是蠻炫的。
我們把這些信號按照優先級排列一下(不知道什么是優先級?找本字典先)
1. 異步清零信號 – aclr
2. 上電復位信號, - pre
3. 異步載入信號 – aload
4. 使能信號 – ena
5. 同步清零信號 – sclr
6. 同步載入信號 – sload
7. 數據輸入信號 – data

我建議大家可以嘗試自己用這些信號來做一個門出來看看,嘗試怎么可以使用這些信號。然后使用 quartus 來編譯驗證自己的結果。這是一種非常有趣的玩法。首先,它可以使你對器件的結構更加了解,同時也鍛煉了你寫代碼的能力。一旦兩相結合,就可以牛的亂七八糟的。

雙向信號
首先說明一件基本知識,在 FPGA 設計中,只有在輸入輸出上可以使用雙向信號,雙向信號是不能使用在內部邏輯上的。一定不要用這種信號,否則工具會綜合出一個你都不知道會是什么東西的東西。

針對一個雙向端口,你需要把它變成一個輸入信號 in,一個輸出信號:out, 和一個輸出使能信號: output_enable. 所以代碼其實很簡單:
Assign birsignal = output_enable ? out: 1’bz;
Assign in = birsignal
這里有一個小小的提示,在寫代碼的時候突然不太清楚語法怎么寫的時候,你可以在 quartus里面按一下右鍵,你可以發現一個 insert template…的選擇。試試看吧。

加法器
加法器的做法就比較有趣了,這會涉及到器件本身的結構問題。相比大家都看到了,FPGA的單元結構是前面一個查找表結果,后面接一個門(寄存器)。我們當然希望可能盡可能的使用這些結構。

最好的狀況是什么?就是使用前面的那個查找表做一個加法,然后直接送到后面的那個門里面,然后傳到下一級做加法。這樣說好像很沒意思,我們舉個例子來看看可以怎么玩:

比如我們要做這樣一個加法 res = A + B + C + D + E

我們首先需要知道一下加法是怎么做出來的,加法本身其實是很簡單的邏輯,但是問題是,你不是一個人在戰斗,你需要有進位,你還需要送進位出去。但是你真的等到進位來了你才做計算,這樣一個 100 位的加法,你大概要等到天黑了。所以,其實在實現一個加法的時候,我們會同時做兩次,一次假設進位為一,一次假設進位為二。然后用前一級下來的進位來進行選擇。所以用這種方式我們就可以理解怎么進一步在 FPGA 中實現加法了。

我們有兩種查找表類型首先是 4 輸入查找表 ( Stratix, Cyclone, 和其他那些老古董)。作為四輸入的查找表,就比較適合兩個數加,然后可以直接連到后面的門上去關一下。進位是通過進位鏈鏈接的。 所以這樣我們可以做成這樣的算法。

一號門 = A + B 二號門 = C + D.
三號門 = 一號門 + 二號門
四號門 = 三號門 + E

這樣通過一個三層門的結構做一個五輸入的加法器,來達到最好的效果。
6 輸入查找表 (StratixII, CycloneII, 和其他那些比較新的器件)
在新的結構中,我們可以使用 6 輸入的查找表,這樣,就可以用三個數加在一起 變成:
一號門 = A + B + C
二號門 = 一號門 + D + E

這樣就變成一種兩重門的結構。
說這些,可以說是一種提醒吧。我們在寫代碼的時候就可以考慮硬件的結構,用這種方法,讓你的實現可以變得更加專業起來。在 FPGA 中的硬件結構都已經是固定的,所以如果按照你的地盤的規律來寫,那一定更完美。大家不妨嘗試各種寫代碼的方式來實現。

狀態機
狀態機是設計過程中的核心部分,所以我們需要特別的提一下寫狀態機的一些注意事項。為了實現利益最大化,建議在 FPGA 中使用 one hot 模式的狀態機,而在 CPLD 中使用最少比特數的狀態機。在具體的設計中需要注意的是:

把狀態機寫全,也就是說不要漏寫了 Default:。 沒有這個首先會出現什么?對了,會有假門(latch)。

狀態機作為控制核心部分,盡量把它和算法功能和數據分離開來。好像你看到好的流水線,控制流水線的電腦和流水線本身是分開的。這樣可以保持相對的獨立性。

如果一種操作設計到幾個狀態,盡量把操作剝離狀態機本身。

使用一個簡單的復位信號來定義上電狀態。如果你的狀態機會被比較多的復位信號復位的話,工具就不會把它當作狀態機來對待。
總之,盡量的保持狀態機的很傻很單純是很重要的。盡量的不要加重核心部分的復雜性。其實道理很簡單,好比在一個公司里面,真正在工作的,其實一定不是一個這個公司的核心。

小明和小強的故事

一直以來都在想寫這么一個故事,這個故事的目的是為了說明清楚關于 timing 的一些概念。所以如果你對時序已經非常清楚的話,大可不必看下去以至于把自己反而搞糊涂了。有一天天氣很好,所以小明決定去小強家里。小明和小強家的門都是自動門,不是你想開,就可以開了的,而是在一定的時間后打開,而這時間間隔是固定的。為了讓時間變得簡單一點,我們假設它是一個小時。于是,小明在自己家門 4:00 打開的時候出去了。然后他就向小強家里走過去,小強家的門是 5:00 打開的,小明在這之前到達小強家門口。這樣小明就順利到小強家里了。這個故事就講完了。讓我們重新把它推演一下,這個故事里面關鍵的是兩點,一個就是小明到達小強家的時間,還有一個就是小強家的門的狀況。這兩個相對來說是兩件獨立事件。我們首先看一個小明從家里到小強家門口這么一個過程。首先是開門的時間點(Launch Edge),開門需要一點時間,你不能在它剛開的時候就出去吧(Tco)。最后就是從門口走到小強家門口的時間(Tdata),這個時間是不一定的,因為有很多方式可以到小強家里。我們會比較關心極端事件,就是最快的時間,和最慢的時間。這還沒結束呢,最容易忽略的,其實就是時間的問題。好比小明以為他是四點點鐘出門的,但其實他家里的鐘其實晚了 10(Tclk1)分鐘的。如果我們以一個標準時間來判斷小強和小明家的鐘。而他們家里的鐘只有可能比標準時間要晚一些 ( 時鐘傳遞到門的延遲 )。差不多可以了,我們看到這么一個公式

到達時間 = Launch Edge + Tclk1 + Tco + Tdata

如果非要給這些值賦一個固定的值,那么我來具體看一下。這里面 Launch Edge, Tco 都是固定的,我們假設他們為 Launch Edge = 4:00, Tco = 5。如果我們說小明花了半小時走過了中間的路,那么我們可以知道,當小明到小強家里的時候應該是 4:00 + 5 + 10 + 30 = 4:45。

好了,我們再來研究一下小強家的門。這個比較簡單一點,就是小強家時間不準的時間,假如說為 5(Tclk2)分鐘好了,再加上開門時間點 Latch edge。這其實說明門是晚開了 5 分鐘。所以小強家開門的時間是:

開門時間 = 時間點 + Tclk2 + Latch Edge

這其實就是 5:05 了。我們一直在說小明要在小強家門開之前到,那么究竟多久之前到他就可以安全的進去呢?這里面有一個建立時間(Tsu)好比要通過安檢啦什么的。把這個值設為 3 好了,所以其實小明應該在 5:02 (5:05 – 3)到是安全的。這點條件小明是符合了的(4:46)。但是還有一個條件。小強看到小明會很開心,所以他要和小明聊幾句才讓他進去,我們管這個叫做保持時間,在這段時間里面小明不能走了,走了的話,也就進不去門了。我們假設這個時間也是三分鐘的話。就是說,從 5:02 到 5:08 之間,小明應該很安心,很穩定的呆在小強家門口他才能進去。小明進步了小強家可能不是什么大不了的事情,不過如果你的設計時序不合格,就要打屁股了。所以我們來看看什么情況下,小明進不了門。

首先我們倆安排幾個參數。

Fmax:什么是最理想的狀況,就是小明走最長的路到達小強家門口的時候,恰好在小強家門口的建立時間點上。而我們把這中間的門開的時間間隔的頻率稱為 Fmax.以這個為例:小明 4:46 分到了,如果小強家的門在 4:49 分開就是最好的時間點了。而小強家的鐘的延遲有給了我們 5 分鐘的冗余。所以最短的時間應該是 44 分鐘。這就是 Fmax。 這也就是你的電路能夠達到的最快的頻率了。而我們規定的時間間隔大于 44 分鐘就可以保證小明可以在建立時間點前到達。

我們給這個差異一個名字 setup slack。就是建立時間點減去小明的到達時間點。結果如果是正的,說明小明可以順利到達,如果是負的,就不行。

剛才我們說過了,還有一個保持時間,我們來看看什么情況下保持時間會失敗。我們給小明在找一個弟弟,這個弟弟呢會在下一次門開的時候出來,也來小強家。弟弟來的時候,小明就必須要離開了。如果我們把小強家的鐘再搞晚一點,晚了 20 分鐘的話,那么開門的時間就會晚到 5:25。而保持時間點是 5:28 分。弟弟從 5:00 + 10 + 1 +5 = 5:16 出發,假設他走了一條近路,很快的就到了,比如只花了 10 分鐘,那么他在 5:26 分到了,小明就不得不走了。所以我們這里其實可以得到一個很有意思的結論,當發生保持時間問題的時候,往往是兩種可能。

1. 相互之間的時間誤差差距比較大
2. 中間的路徑非常的短。

所以我們往往需要分析電路的最快表現來分析保持時間。這里面也有一個 hold time slack.就是小明弟弟到的時間點減去保持時間點。

這個故事差不多講完了,大家可能已經暈了,其實我自己也差不多了。但是我們還要再接再厲。如果把兩個門開關的時間間隔變得不同。做時序分析的時候,工具會找到所有狀況中最糟糕的那個狀況來分析。不用擔心聽上去好像很復雜,這都是工具自己會做的事情。你知需要規定你想要的間隔時間,工具就會為了你的目標而努力。 對這個故事的整個的了解讓我們對電路的具體過程有更深的理解。讓我們來看看我們可以做些什么來規避 Slack 出現負值的情況。

首先看看 setup slack:

1. 把時間間隔變大,也就是降低頻率(這是廢話)
2. 把路徑縮短,就是把最長的那條路徑變短,使用各種優化手段。
3. 有的時候,我們會發現,其實小明根本不認識小強,所以我們完全沒必要管他是不是能進小強家門。(false path)我們可以告訴工具,不要去管它。
4. 如果在 5:00 到不了,6:00 到也可以,有的時候我們可能并不在乎他什么時候到,只要能到就好。我們可以設置為 multi-cycle.我們告訴工具說,沒關系不用太著急的,下次開門的時候再到也可以的。

再看看 hold time slack:

1. 把時間誤差變小。首先我們看看什么情況下可能導致小明家的鐘差 5 分鐘,而小強家卻差 20 分鐘。如果這個時鐘是一個 gated clock,那么他的驅動能力是有線的,所以時鐘傳遞的延遲會因此而變大。我們可以使用 PLL 來驅動時鐘,這樣的話驅動能力會加強,時鐘傳遞的延遲因此而變短。

2. 把最短路徑變長,這可以通過添加 LCell 來人為制造延遲

辦公室的故事 ( Incremental Compilation)

我們總是在想,有沒有那么一種可能,讓我可以少花力氣多賺錢,我們這里就開始討論這樣一個問題。

好比你現在有一個很大的公司,你有一個辦公室,里面空空的,你可以有很多方法把你的員工放在里面。當然你可以一股腦兒的把所有人全部很隨意的放在里面。但是導致的結果會是什么樣的呢?你會發現兩個工作關系很精密的人,每天需要從這頭走到那頭的交流。這樣的工作效率不可能好的。所以我們會比較希望把他們整合在一起。至少可以讓一個部門坐在一起。然后我們再在這個相對比較小的區域里面做調整來提高工作效率,這樣會容易很多了。每個部門當然就是公司的一部分(design patition),我們需要把這個部門的人都放在一個限定的空間里面,而給每個部門提供的空間,我們定義為 Logic Lock. 空間是一個物理的概念,而部門是一個人為理念造成的一個概念。我們并不是一定要把他們倆結合起來。但是,如果結合起來會有這樣一個好處。

好比,我有五個部門 A,B,C,D,E。而不給他們限制空間,他們可能隨意的去做。也許相對來說部門內的人士坐在一起了,但是這中間留下的空間變得很沒規律。兩種情況下會有問題,一個是,需要加一個新的部門,那么這個部門就需要拆開放,另外就是某些部門擴張了,新人就沒地方放了。所以,宏觀調控是非常重要的。所以我們需要把設計理念的分割和物理空間的分割緊密的結合在一起。

增量編譯的思想和這個故事是完全一致的。我們需要把設計分成一些相對比較大的部分,然后給他們安排相應的位置去放置。這樣有非常多的好處:

1. 關系相對精密的電路的位置比較接近,減少了連接線上的延遲。

2. 對一些已經表現很好的模塊可以保留他們的編譯結果。這樣可以獲得最大的好處。每一次編譯都獲得一個比較好的結果加以保留,這樣整個設計就一點點按照增量的方式獲得了最好的那個結果。

3. 由于一些模塊已經保留了,所以工具不會在那些模塊上面耗費時間,所以編譯時間大大縮短。

我們來看看有這種思想可以實現的兩種編譯過程:
自上而下:我是公司的總經理,我們去招了一堆人,然后把它們放在各個部門里面。根據每個部門人數的多少,給他們劃分相應的資源。
自下而上:我是公司的總經理,我手下有一些部門的負責人,我讓這些人去招人。我給他們一些人數的預算,然后給他們提供空間。那些部門經理自己去招人來填充自己的一畝三分地。最后把這個辦公室填滿。

和其他所有工具一樣,我們需要有一些行為準則來獲得最好的效果:
1. 盡量把工作關系精密的人放在同一個部門里面。部門和部門之間是不能進行優化的。好比兩個人需要每小時都交流工作,但是你把他們放在兩個部門,即使是相互隔壁的部門,也不能保證他們正好墻對墻的做。工具只對部門內部進行調整優化,出了部門,他們就死人不管了。
2. 關門原則。在部門和部門之間都按上門。就是說對輸出和輸入的數據都用 register 打一下。這其實是和第一條是相關的。因為部門之間不進行任何優化,為怕避免麻煩,建議大家都按上門來提高效率
3. 部門和部門之間盡量少串門。盡可能的減少互動。這個其實是可以在設計的過程中進行調整挑選的。
4. 保證一個部門的人數,不是太少(大于 2,000LE)。這很好理解,就那么幾個人,還優化什么呀。
5. 不要放不用的接口。沒有結果的連接在編譯中是會被優化掉的。但是在增量編譯中,卻會被保留。所以如果已經知道一個接口是沒有用的,不如把它干掉算了。
6. 大家知道,FPGA 內部是沒有雙向信號的,所以一定避免雙向信號。除非你這個型號是要直接連到芯片管腳上的。
7. 避免同一個信號重復輸出。
8. 不要把直接從輸入到輸出的信號放到部門內部。這是一種資源浪費
9. 公司有一些資源,好比打印機啊,傳真機啊之類的,在分配辦公區域的時候,盡量考慮資源的合理使用。由于資源位置是固定的,所以當你把區域分配給部門的時候,其實也把資源分配給他們使用了。而如果他們用不上,也就浪費了。
10. 多給部門與部門之間的交流留一些時間預算。這么看起來,如果你學會了增量編譯,好像順便把 HR 也個學了。

(本節的思維導圖請下載附件)

8. 優化那些事兒
優化是一個很麻煩的問題,因為這個話題非常的雜,細碎。好像我們介紹一個人,你會一下子不知道從什么方面說比較好,因為他會同時擁有不同的身份,存在于社會當中。所以,我盡量的完成了這么一張圖表,讓大家對優化這個懸浮于平衡中間的一個游戲方法有一定的了解。平衡,其實是優化中的一個最關鍵的詞。當然針對不同的應用,我們會有完全不同的需求,平衡點也會有算偏向。但是畢竟不能矯枉過正,太過苛求,否則只能是過猶不及了。這么說,似乎很沒意思,讓我們來說三個考量,時序,資源,功耗。這就是優化中的三個平衡極限。在有的設計中,算法對時序有要求,所以會要求設計能跑在一定的時鐘頻率上,這就需要對時序進行優化。有的公司在設計的后期開始考慮成本的問題,會希望選擇盡量小的器件,那么這個時候,資源消耗變成了重點。而在手提式器件的設計中,功耗是至關重要的。而這三點,是沒可能同時做到的。為了達到某種目的,你必須要付出其他的代價。所以,在做優化之前,做好一個優化目標是很有必要的。當然最基本的是時序,和資源。在這里我們比較重點的討論這兩方面的話題。 大家一定看到了前面這種讓你暈得亂七八糟的圖,我的任務,就是把他們解釋一下。

(本節的思維導圖請下載附件)

優化之前
在提優化之前,我們當然需要有一個提供優化的基本形態,就是你的設計。如果你的設計還沒怎么完成,大可不必就著急的開始優化。因為每次編譯都會把你的優化努力隨機掉。而最好的優化方法,其實就是可以不優化。那就是把代碼寫的很優化,退而求其次,就是把代碼寫的容易優化。這里又要提老掉牙的事情了,代碼要寫得有層次化,好處就不羅嗦了。那么在寫代碼的時候需要考慮什么問題呢?首先是你使用的目標器件的資源狀況。通過一些小實驗,你可以知道,你寫出來的代碼,大概會實現成什么樣。這對你寫代碼有一種感官上的映射非常有幫助。然后就是一些特殊零件的數目和位置,比如存儲器(memory),計算器(DSP block),特殊的管腳資源(LVDS)。其實是把模塊按照功能分割開來。從頂層電路看起來,真個設計就是一些功能模塊的組合,看上去和規劃的功能圖一模一樣。這樣做的好處,自然是不言而喻的。也比較符合常規的美學思想。然后是狀態機的問題,盡量不要寫出太大的狀態機,寧愿用一些小型的狀態機來相互關聯。(除非你希望不被老板替換掉而寫出很炫的,不過那樣你自己以后也會很麻煩,因為你的記性并不像你想像中那么可靠)工具會耗盡心機去實現你一個很宏偉的狀態機,結果可能還不能讓人足夠滿意。Glue logic. 就是兩個模塊之間的黏合邏輯。這或許是很難避免的。但他們往往會成為優化的一個盲點。這種三不管地區,最容易導致臟亂差等社會問題。所以,盡量把它們放進某個模塊的勢力范圍。在知道了寫代碼的大概規則以后,我們來看看約束。約束本身并不是優化,而是給優化制定的一個目標。你需要工具達到什么樣的目標,你當然盡可能的要告訴工具,否則讓他這么放任自流下去,后果會很嚴重。所以最簡單的,你必須要提供所有的時序信息。好比,所有的時鐘頻率,所有的管腳時序要求。這樣 fitter 才會有一個著眼點,針對距離目標最遠的路徑去努力。時序報告也才有可能報告哪些路徑是沒有通過要求的。我還是推薦大家使用timequest 來做時序約束,好處是,它可能對你的時序約束和你的設計對照做分析,在做時序分析之前,先對你的約束做分析,然后告訴你,你有多少該做的事情而沒有做的(為被約束的路徑)還有多少你要求做的,而沒有被做的(被忽略的時序要求)。這里提出一個話題,false path,有人叫假路,有人叫錯路,都是英語惹得禍,我們還是叫它flase path。具體來說,就是不該存在的路,或者說,即使存在,也沒人去走的路。那么對這種路,我們是可以讓工具看都不用看的。關于 false path,其實倒不用太過著急。大可以在發生問題以后,再去看是不是。否則讓你把每條 false path 挑出來,其實也是個蠻無聊的事情。對時鐘的約束,要重點關注兩個現象。首先是盡量少的在時鐘路徑上引入邏輯。這樣認為的造成了時鐘和時鐘之間的 skew。我們都知道這不是什么好事情。另外就是一種上下沿都需要用來采集數據的時鐘。對于時鐘的約束有很多的地方需要注意,否則你的電路都不知道會飛到哪里去。不過這東西需要一些體驗,靠嘴巴說是說不出感覺的。現在來說約束中最重要的一個關鍵,不要過約束。過約束的壞處一大堆,增加編譯時間(你可能不太在乎),資源使用過度(可能也還可以忍受),導致其他的時序問題(那可是個大麻煩了)如果你對自己的約束有些不太放心,又或者說可能器件和器件之間會有很細微的差別,你可以給約束做一些余量,但是過約束是萬萬要不得的。

時序優化:

寫了半天,終于開始寫優化了,首先我們看看這個時序優化的問題。還是先看幾個關鍵詞吧。

優化目標:一個是全局的設置,告訴工具你這個設計的優化偏向。當時序優化偏重要的時候,可以設置為 Speed。當然這使以犧牲 area, power 為代價的。也可以對某個獨立模塊做局部設置,就是說在這個模塊中,優化目標是時序。

網表再綜合( netlist re-synthesis): QuarutsII 支持一些第三方的綜合工具(說實話,Quaruts 自己的綜合工具,也還是可以的)。他們把代碼變成可以映射到 FPGA 上的網表文件,就是由一堆查找表和寄存器組成的東西。再綜合會把這些網表還原成為與非門結構的電路,然后再根據 quartus 綜合工具的算法再做綜合。這當然未必是一件好事,可能會因此而破壞了原來工具中一些好的算法做出來的邏輯而導致結果更差。

物理綜合:這是時序工具中效果最明顯的工具。它對 fitter 以后的結果,在關鍵路徑上,對電路進行調整。既然布局布線都做好了,還有什么可以做的呢?有很多。首先是組合電路。組合電路,無非就是一堆查找表的連接。而布局布線本身是一個比較隨機的過程。在完成以后,我們會發現一些路徑是比較差的,那么我們可以對這些路徑做一些調整,他們選擇更短的一條路徑,同時功能保持不變。對異步控制信號做一級同步流水線。這樣可以規避一些recovery 和 removal 的時序問題。還有一個功能是復制寄存器,比如說一個寄存器的 fanout比較多,或者說,其中的一條線會連到比較遠的地方。那么我們可以在那個比較遠的地方復制一個和這個寄存器完全一樣的寄存器,這樣可以大大提高時序效果。當然這需要犧牲一個寄存器了。還有一個好玩的事情,是寄存器的 re-timing,如果我們把寄存器看成流水線中的一層的話,它其實就是位于一條路徑中的某個點而已。他的前后兩個組合電路的延遲可能是不同的。而可能恰巧那個長的變成了一個關鍵路徑(就是大大的壞的一條),那么我們是不是可以移動一下這個寄存器的位置,讓大家的時間可以平衡一下,而結果是時序上去了。但是在功能上會有一點小小的變化,所以這個選項還是慎用。

可能造成的幾種時序問題:時鐘路徑導致問題,這個時鐘可能是個 gated clock,或者非全局時鐘。這個調整的余地相對比較小。

數據路徑導致問題,這個比較復雜,首先可能是 Fan-out 太大導致的延遲過大。也有可能是邏輯門的層數過多導致。或者布局布線的隨機隨得不好,兩個點的距離很大。還有就是一些物理限制,比如 DSP block 之間的相對位置。

用來觀察時序問題的工具:

Technology map viewer: 這東西,實在是沒辦法用中文說了,我私自反了,恐怕你會恨死我,因為在 Quartus 里面死活找不到了。它是可以用來觀察你的綜合結果以后的電路實現的。所以用它,你可以看到你的電路經過了多少層次的路徑。

Chip planner: 這是用來看你的電路具體在芯片上的實現的,通過它你可以觀察到相對之間的位置的距離,和連線上的延遲。

TimeQuest: 這是時序分析的最佳工具,無論是觀察時鐘或者路徑延遲,fanout, 或者邏輯層次,都可以使用它。雖然不一定比其他的工具更直觀,但是它是最全面的。

針對一些經典的可能性,表格里面列出了一些,大家可以自己看一下。


資源優化
和時序優化相對的,我們可以給 Quartus 一個優化指導方向,當你把它設置為 area 的時候,工具會盡量考慮資源的使用。可以做全局設置,也可以做局部設置。

Register packing: 這是一個針對 LE 資源優化的工具,在新的 Quartus 中一共有七級設置。比如把兩個互不相干的電路擠到同一個 LE 中。根據等級設置的不同,會有不同的資源消耗結果,當然付出的代價就是時序的降低。

當然對特定模塊的使用,是需要一個整體規劃的。什么樣的狀況下去使用存儲器資源,什么樣的狀況下使用 DSP-block,都需要有一定的評估。更多的時候,其實在寫代碼的時候就已經做好了計劃。

幫手:相信大家已經有點暈了,幸運的時候,我們不是一個人在戰斗。我們還是有很多幫手的。讓我們來看看這些家伙:

Design assistant: 這是一個會提供給你一些提示的助手工具。他會顯示出設計中會導致編譯結果的地方。你可以自己定制一些設計規則,他會幫助你去監督你自己,尤其在一個團隊設計中,對大家設計的同一性有比較好的效果。

Optimization advisor: 優化指導,會提出一些相關的優化選項的指導。當然這種指導是非常通用的,不可能非常針對你自己的應用,所以在是否使用這些建議的時候,還是要自己權衡一下。所以簡單的了解一些優化選項,還是有必要的。否則,莫名其妙的就被工具耍了。

Early timing estimate: 這個工具會做一些最基本的布局布線,這樣它可以很快的得到一些時序方面的信息,這在你做時序約束,和logic lock設置的時候有很多的指導意義,同時也節省了一些時間。

Seeds: 誰都靠不上,我們靠老天。布局布線基本上是一個隨機的事情,沒有人能夠了解結果能使什么樣子的。而seeds就好像一個賭博用的骰子一樣,告訴編譯從什么狀況開始布局。沒有人知道seeds 中的具體某個數字代表什么樣的狀況,所以就是不斷的碰運氣吧。給大家一個迷信,似乎17這個數字特別好,結果會比較理想一些。

Design Space Explorer: 這個是一個實在沒辦法的辦法,但凡還有一線生路,最好不要用這個東西。他會自動的對你的設計根據一些設置,不斷的嘗試布局布線。比如使用不同的優化方法,不同的算法,甚至不同的種子來做編譯,最后給你一個最符合約束要求的編譯結果。但是這樣的工作量有多大,大家可想而知了。如果你有比較多的時間,你可以試試把它扔在那里跑個幾天。

Handbook: 啥也不用說了。

我想用一種比較有效的方式來描述關于系統設計的一些事情。設計是沒有一個固定規則的過程,否則也就沒有樂趣可言了。雖然有很多標準,有很多限制,但是依然有非常多的變化空間。其實最重要的事情,是知道什么是重要的,什么是次要的。精力應該集中在重要的東西上面,而不是一些細節。做系統設計需要有一種大的氣魄,一些不拘小節的氣質,當然,還需要別出心裁的創意。FPGA 本身提供了一個非常靈活的平臺,如何最大化的利用這個平臺,是我們脫離呆板的嵌入式系統的一個重要關鍵,也是如何玩轉系統的關鍵。

不求甚解之 NiosII
所有的系統都是由模塊組成的,或大或小的模塊,拼接成一個大積木。所以我們首先需要了解這些模塊 (IP)。關于怎么去了解一個 IP,其實是很重要的問題。NiosII CPU 作為一個比較大型的模塊,可以作為一個例子來講。一個關鍵詞是不求甚解。不求甚解的目的,并不是偷懶,而是更準確,更有針對性,更快捷。IP 的作用就是為了完成一個特定的功能,所以我們并不需要知道它是如何實現的,事實上,由于很多的 IP 都是加密的代碼,所以也不可能知道具體的電路狀態。同時也不需要花很多的時間把文檔里面的每一行都了解清楚。作為工程師,大家的脾氣一般都是一種超強的好奇心和鉆研精神的集合。而往往會鉆進牛角尖里面。而作為系統設計,是需要有一種粗曠型的大氣魄,不需要在細節上浪費時間。你會發現很多的細節是沒有意義的。并不是說我們不需要去研究細節,細節是很重要的,但是細節需要在被用到的時候才去關注就好了。

作為一個 IP,最重要的,其實是接口。因為你最重要的是需要知道是怎么讓它工作起來,而不是它怎么工作的。所以在看文檔的時候,最主要看的就是接口信號,對所有的信號的作用有一個了解。NiosII 使用的是 Avalon MM 點對點接口,這其實是一個非常有趣的接口,因為它的交流更加短平快一些。它與普通的 PCI 接口不同的地方是,他可以支持同時多線控制。因為它沒有總線的概念,不會在總線被占據的時候,其他任何通訊都無法進行。NiosII是在 SOPC builder 中被直接使用的,我們不需要知道具體有哪些信號,因為沒有非常需要,我們是看不到這些接口的。在 NiosII 中,我們有兩個 Master Avalon MM 接口,一個是Instruction Master Port, 這是 CPU 用來讀取指令的接口。CPU 通過這個端口從 Memory 上讀取指令。另一個是 Data master port, 很簡單,這是用來連接數據通道的。比如說你要讀取的數據,你要存儲的數據,都是走這個通道。這兩個端口可以連接同一個內存,在這種時候需要特別小心,很有可能自己把自己的指令給改掉了。但是反過來思考一下,其實我們可以做什么?可以按照狀況改變軟件代碼。NiosII 中還有第三個端口,這是用來做 Debug 用的端口。還有其他的一些接口,比如 TCM 接口。我們需要知道這些接口的存在,但是不需要知道細節,只有在用到的時候再去看相關的文檔就好了。

第二個需要關注的問題就是參數設置。這里面是有講究的。IP 是廠家做出來的通用模塊,不是為你而特制的,所以必然有一些是你不需要的方面。我們可以通過參數的修改,讓它盡量的接近我們的需求。有很多人在做設計的時候是有思維定勢的,而且這種定勢的頑固性很強。這很容易對環境產生一種叛逆思想。就是說除了他自己假想出來的做法,其他的一切都是不對的,或者說不好的。而這在使用 IP 的時候,會遭遇到意想不到的痛苦的。所以,盡量不要依靠假設來臆想了模塊的設置。而是盡量的適應環境,來配置自己的設計。作為一個FPGA 的玩家,這種依照環境來改變的能力是必須的。

NiosII 的參數中首先是指令集或者說 CPU 復雜度的選擇,有三個選擇,根據不同的選擇,CPU 的能力會有不同,當然使用的資源也是完全不一樣的 NiosII/E (經濟型)能力最弱,當然資源也最小(600-700 LE )
NiosII/S (中間型) 中庸配置,資源消耗是 1200-1400 LEzNiosII/F (快速型) 能力最強配置,資源消耗是 1400-1800LE

然后我們考慮 Cashes 的設置,Cash 有兩種,一種是用來做指令緩存的,一種是用來做數據緩存的。Cash 的大小對程序的運行速度是有影響的。當然也沒必要使用過多的資源。夠用就好了。

再了解一下 Jtag Debug 的模式選擇,一共有五個等級的選擇。和選擇 CPU 一樣,從簡單到復雜。一般來說選擇 Level2 也就夠用的。

自定義指令設置。這是最有價值的設置。別忘記了,我們是在 FPGA 的世界里。所以 CPU并不像在其他地方那樣的鐵板一塊。我們可以選擇使用自定義的指令。所謂自定義指令,并不是一個軟件宏或者函數。而是一塊硬件。當 CPU 調用到這個指令的時候,事實上它調用的就是這個硬件模塊,它被嵌入在 CPU 中。而這其實就是 NiosII 好玩的地方。

好了,現在我們要考慮的問題,就是使用。使用 CPU 的方法,當然就是軟件編程。NiosII的軟件其實是非常簡單的。就是普通的 C,或者 C++,需要做的就是不斷的對端口的地址讀啊,寫啊,計算數據,就好了。但也可能非常的復雜,因為你不僅需要了解軟件編程,你更需要了解你使用的那些硬件,那些外設模塊。NiosII 的編程很硬件的依賴性是很強的。針對比較大型的一些外設,可以寫一些 HAL 程序。這是類似于驅動的一些指令。而軟件只需要調用這些 API 就可以了。大部分的 NiosII 程序是不需要使用操作系統的,作為一個嵌入式系統的控制核心,更多的是一些存儲式的讀寫,算法的計算的操作。除非你需要運行一些網絡協議啊,什么的。但其實我們可以用更加解構的方式來看待一個操作系統。操作系統其實就是給我們提供了一大堆的操作指令而已。沒什么更特別的作用了。所以,思考一下吧。

我用了不求甚解的方式來介紹了一下 NiosII。這是一種偷懶的方式。我要做的,其實就是把一些關鍵的點指出來,大家可以去看,同時不把時間消耗在細枝末節上面。要把 NiosII 完整的說清楚,當然不是這么三言兩語的就可以的了,否則事情也太簡單了些了。我希望可以對大家有所幫助的地方就是,對一件復雜的事情,找一個聰明的方式。

囫圇吞棗之 SOPC

SOPC builder 是 QuartusII 中用來建立,開發,維護系統的平臺。雖然很多時候我們用它作為 NiosII 的一個嵌入式系統的開發環境,但我希望大家不要把思路只是局限在 NiosII 上面。它將成為一個包容全部系統內容的一個平臺。

讓我們把一個系統分割成為兩個部分。一個是控制部分。所謂的控制,就是對很多的寄存器進行讀寫,或者是對內存存儲器進行操作。而這些操作往往是與地址相關的。所以,我們使用 Avalon-MM 進行這部分的連接。好像很多的系統一樣,這個接口的兩端是主從設備。主設備發出要求,從設備被動接受操作。舉個簡單的例子,CPU 永遠都是一個主設備,而一些存儲器,比如 Flash, SRAM 則是從設備。而 CPU 并不是唯一的主設備,比如 DMA 也可以作為主設備。由于 Avalon-MM 總線的點對點結構,當 DMA 對一個從設備進行處理的時候,CPU 可以對另一個設備進行出來。這就是這種結構最大的優勢。

但是單一的 Avalon-MM 并不能完全的解決問題。因為對于某些傳輸而言,地址是沒有意義的。而高的通過率可能更重要。這就是數據通道。一些數據的處理,比如濾波,視頻處理的操作。而這就需要用 Avalon-ST 的接口進行連接。在這種結構中,接口的兩端是相對平衡的地位。作為 SOPC builder 中的一個模塊,他可以同時擁有多個所有的端口。然后再端口和端口之間進行連接。

………………
………限于篇幅這部分請下載附件………
………………




大家一起來搭積木好了。

啥是 DSP
終于寫到 DSP 這部分了,由于是我的本行,我反而一下子不知道該怎么寫好了。或許最主要的一個原因是 DSP 涉及的范圍實在是廣得亂七八糟了點。突然之間變得有點無所適從起來。所以只好暫且寫到哪里看哪里了。

大家知道我們這里說玩轉 FPGA 的,每次我在 FPGA 里面提到了 DSP 的題目的時候,總是會有一些人打斷我說,兄弟啊,你大概走錯地方了。我們這里都是硬件工程師,或者可能有些寫 C 的,但是 DSP,那東西不會寫哦。那么好吧,我就跑到 DSP 那里去講,FPGA,然后就會有人問我,你們這個 FPGA 和 TI 的 DSP 比有什么區別呢?我暈。我想說的是,我這里的 DSP 是 Digital Signal Processing (數字信號處理),而不是 Digital Signal Processor (數字信號處理器)。

不能否認處理器在數字信號的歷史上擁有絕對的貢獻和近乎壟斷的地位。作為最簡便的一種實現方式(軟件),數字信號處理器具備非常大的靈活性,以及對系統的升級能力。但是,隨著技術越來越復雜高端(很多其實是蠻沒必要的),處理器開始不斷的在它的瓶頸上碰壁。一個是算法的復雜度,一個是對多通道的苛刻要求,使得產品對處理速度的要求幾乎成指數級增長。這就使得 FPGA 有了施展拳腳的地方。是的 FPGA 就是硬件,或許那里面的一個乘法器無法和處理器里面的乘法器相比,但是架不住人多吧。我用 100 個,兩百個,四百個同時運算呢?所以我們開始觀察這個市場的時候,FPGA 已經成為無法被忽略的一部分。再反過來看看 FPGA,那是什么玩意兒啊,一個只能用來做數字電路的芯片,不用它做數字信號處理,還真想不太出,它更適合做什么呀。

好了,讓我們重新考慮一下 DSP。DSP 的觀念其實是非常簡單的,它就是一個轉換器。好像你從這里進去,從那里出來,出來的時候你就不是你自己了,要么瘦了,要么胖了,甚至可能說性別都變了,或者可能說別人的腦袋換到你的頭上去了。總之,作為數據,你從這里進去,經過這么個玩意兒以后,變成一套新的數據。這就是 DSP。一定很多人說,你這不是廢話,要是都一樣的,要你芯片做什么?還真的,想要在數字電路里面脫離 DSP 真不是那么容易的事情了。當然也不能把話說得滿了,否則很多人要不高興了。好比網絡協議處理,就不是 DSP,因為一般會關注的都是包頭信息,而對包本身的內容,從來都不關心。而 DSP關注的是要改變數據本身的。讓我們說得更加具體一點好了,比如通訊,尤其是無線通訊。通訊嘛,很簡單就是要把信號送出去吧,但是數字信號不能就這么送出去,除非有根線。所以要對數字信號做一些改變,比如說調制,把信號變成什么 BPSK, QPSK,QAM 什么的。有了調制,在接受端,當然就要有解調。這就是我們俗稱的調制解調器。我們這里來玩一下英語,調制:Modulation,解調:Demodulation,所以調制解調器就叫做 Modem。另一個比較大的應用就是圖像處理,圖像那么大的數據,沒辦法不變化的就用,所以要對圖像進行編碼,當然在播放的時候,需要解碼出來,編碼:code,解碼:decoder,所以編解碼器我們叫做:codec。通過這些例子可以發現,DSP 一般都是一對的,這很容易理解,對數據進行變化,并不是因為我們吃飽了撐的沒事情做,而是有一定的目的的。比如為了節省帶寬,我們需要對數據進行壓縮。比如由于接受端的誤碼率會比較高,所以我們需要用糾錯算法,為了達到糾錯的目的,我們就必須對數據進行卷積編碼。而接受端就要做解卷積糾錯。所以在對數據進行變化以后,我們通常會在另一端把它恢復出來。否則誰知道那是什么東西呢。這也可以當作是 DSP 的一個特點吧。

完全沒必要把 DSP 看成多么復雜的事情,算法,聽上去多么高深的東西呀。其實只要是所有的學過加減乘除就可以自己做算法。而所有的算法都是有一個目的的,只要你理解了這個目的,至于說具體的方法,是可以仁者見仁智者見智了。舉個例子,看是不是真的超出你的智商了。傳統電視,或者說攝像的時候,我們是使用隔行掃描的方式。就是說每幅圖片其實只有一半的數據,比如我第一次給你 1,3,5,7,9 行,第二次給你 2,4,6,8,10 行。因為發現人的眼睛是很容易騙的,所以用這種方式你其實是察覺不出來的。但是我們現在用數字電視了,而且要高清,所以你不能那么忽悠我啊,為了省帶寬,可以少一半,但是放出來的時候不能那樣。所以我們要把這半幅圖在變成一幅完整的圖,這就變成了逐行掃描。你想象一下可以用什么辦法做呢?想一下。答對了,兩種方法,第一種方法是,可以直接把 1,3,5,7,9 copy 一下不就好了?這種模式叫 Bob 模式。還有一種方式,就是等到 2,4,6,8,10 也來了,再把它們兩拼起來變成一副圖,放兩次,這種模式叫做 Weave 模式。Weave 模式的好處是圖像看上去更加清晰。簡單吧?但是有一個問題,畢竟這是兩幀不一樣的圖片,是在不同時間點拍的。所以當一個東西的移動速度特別快的時候,你會發現兩幅圖片是有細微差別的。這就會在電視上看到一些鋸齒狀的邊緣。如果大家仔細看自己的電視,是可以發現的,尤其是很多廣告里面。那么為了解決這種問題,我們可以比較一下他們之間的差別,如果差別超過了一定的值,我們就用Bob 模式,如果沒超過,就用 Weave 模式。你看,簡單吧,其實算法就是這么回事情,沒什么大不了的。做 DSP 需要有一種無招勝有招的精神。因為 DSP 的算法實在太多了,你完全沒可能記住,也完全沒必要一個個的去學。只有當你需要實現的時候再去學習就好了,方法就是首先知道算法的自然原理,很容易就可以理解算法原理。而算法原理也不過就是一些加減乘而已,連除都很少的。

DSP builder 是干啥的?

DSPbuilder 就是 Altera 設計用來方便客戶設計 DSP 的工具。首先我們了解一個背景,現在最牛的算法軟件毋庸置疑的就是 Matlab 了。或許在統計學,或者其他的數學模型方面有更加專業的工具,但是對于 DSP 而言,Matlab 是不二的選擇。N 多的人在用他來搭建模型。我們可以把 Matlab 分成 matlab 和 simulink 兩部分。Matlab 更多的是對數組進行一系列的計算,而這種計算是靜態的。而 simulink 是使用模塊化的方式來搭建一個模型,而這個模型才是動態化的。當我們用 matlab 做成一個算法的時候,先不用開心太早,因為它完全有可能是無法實現的。更多的只是一種理論上的公式。只有當我們用 simulink 來搭建出一個模型的時候,我們可以知道,它是可以被實現出來的,無論是軟件,或者硬件的方式。

我們小的時候學數學,學乘法,大家一定還有美好的回憶,個位乘,然后進位到十位,然后在一步一步的算下去,算了長長的一溜,很有成就感的。我記得那個時候我們還要用尺來畫中間的那根線呢,因為老師說那條線要畫得直,好像畫不直的話就算不出正確答案了(大概所謂心誠則靈的意思吧)。后來知道了,這個世界上,居然有一個東西叫做計算器。那個東西是你無論如何光著腳都攆不上的速度,而且不會出錯(不過好像也見過 1+1=3 的計算器)。我們于是發現自己似乎被騙了,我們為什么要做那一長串的中間過程呢?是的。如果我們用這種方式來考慮問題的話,一邊是做好的算法模型,一邊是我們的 FPGA 芯片。為什么我們還需要很辛苦的寫什么 Verilog, VHDL 代碼呢?就好像在學 Verilog, VHDL 之前我們做什么?我們學數字電路,現在還有幾個人在用那些與非門搭電路呢?所謂社會的進步一定是不斷從低端向高端發展的歷史過程。所以,與非們對于 Verilog 來說是沒必要的中間過程。但其實 Verilog 本身又何嘗不是呢?當然了,Verilog, 與非門這些東西,對于我們對電路的理解和學習是做出過貢獻的,但是,是不是到了應該把它們淘汰了的時候了呢(我這里說的只是和算法相關的電路)?或許現在還沒有真的到了這個時期,但是它正在一步步的向我們靠近。而 DSP builder 就是基于這種思想的工具。讓我們看看用了 DSP builder,可以給我們省多少東西。

首先是省了時間,時間是這個功利社會最重要的東西,沒有人有耐心等待你做一個十全十美的東西出來。誰最早出來,哪怕是東西爛到不能用,都是成功的。所以時間比什么都重要。然后是省了人,不需要找一些人來把那些算法轉變成為代碼了。如果大家對 Simulink 比較熟悉的話,可以看到,simulink 的庫里面有你的一切實驗環境。好比信號發生器啊,信道啊。另外還有最全面的檢測系統,比如說示波器啊,頻譜分析儀啊,誤碼率分析器啊。有了這一切,你還要實驗室做什么?至少你不需要那一大堆昂貴的儀器了吧。

物盡其用,人盡其能,我們還是希望盡量多的去發揮一些優勢性的東西。所以千萬不要說用DSP builder 去做一個非常復雜的控制邏輯,那只能是得不償失。所以,我更建議大家用 DSPbuilder 來做一些算法方面的實現。然后作為整個系統中的一個模塊來使用。這樣可以使你的設計更有效率,并且可修改性增強。DSP builder 和 SOPC builder 的結合使用可以大大增強你的設計能力。比如說,我們可以用 DSP builder 來做一些運算模塊,然后再 SOPC builder里面連接起來。再用一個 NiosII 來作為控制,寫一些軟件代碼。一個看上去非常復雜的系統,其實已經可以看到了。而這整個過程中,我們沒有寫過一行硬件代碼。可以說,這種系統設計思路就是未來的一個趨勢。

DSP builder 設計看上去簡單,但要精通也并不容易。有兩個方面是比較讓人困惑不已的。如果你是一個做算法的人,你對 Simulink 非常熟悉,而你對硬件方面所知寥寥,那有可能犯第一個問題:時序問題。在設計中,你很難找到時序的節點,就是寄存器,因為寄存器都是存在于模塊本身里面的。有很多人設計了一個從頭到尾都是組合電路的設計。而這種設計是肯定無法通過時序驗證的。解決這樣的問題,現在有兩個模塊可以幫助。第一個是 8.0 里面新出來的,Display Pipeline Depth。很明顯,這個模塊的作用就是現實所有模塊的流水級數,就是這個模塊里面有幾層寄存器。這樣你從模型上就可以很清楚的看到兩級寄存器之間的距離,規避冗長的組合電路。另外一個就是 Resource Usage. 這個是資源使用顯示模塊,在編譯以后,可以顯示資源的使用量。但是它有一個附屬功能,其實更加有用,就是 timing。它可以用來顯示所有沒有通過時序分析的路徑,然后在模型中間 highlight 出來。這樣可以幫助你很容易的發現問題所在,然后做些亡羊補牢的事情。

針對對硬件非常熟悉,但是對 Simulink 這種東西非常不熟悉的人有一個麻煩,那就是時鐘。在 DSPbuilder 的設計中,所有的時鐘和時鐘復位信號都是隱藏的。在 simulink 中,時鐘是通過采樣率來定義的,或者叫時鐘域。從一個初始的采樣率開始,后面的模塊都是使用相同的時鐘域的。我們可以使用 Rate Change 目錄下的模塊來對時鐘進行切換。而這似乎讓人很容易暈。這里我們可以使用 simulink 的工具。它可以設置使得不同時鐘域的模塊顯示成為不同顏色。這樣看起來就舒服很多了。

再說一個 DSP builder 里面最讓人心動的東西吧。HIL ( hardware in loop)。這是一個非常有趣的概念。我們現在討論的是一個 FPGA 平臺,這個芯片是可以無限次燒錄的。不會燒一次收你一塊錢的。而我們在做設計的時候經常有這樣的問題,對設計本身沒有把握,不知道是不是對,當然可以做仿真。但是仿真有的時候很麻煩,一個是速度可能會太慢了點。一個是我依然不相信你們的這個仿真模型是不是真的夠仿真。所以,你就可以嘗試用 HIL 來加速你的仿真,同時增強你的信心。HIL 把你的設計包裹在一套接口中間,進行編譯,然后下載到板子的 FPGA 中間。Simulink 通過下載電纜把測試數據不斷的灌入,然后在輸出端不斷的獲得硬件跑出來的結果。通過這么一個過程,保證你的仿真達到多快好省的境界。但是,這也只是仿真而已,我不管它叫做測試,因為它不是在真實的時鐘頻率下操作的。時鐘是通過Jtag 的時鐘驅動的。所以你不要指望它可以跑在 100,200 兆上。但是速度依然已經夠快了。如果這樣的電路下載下去還有問題,那可能性只有一個,你的約束錯了。或者是時序有問題,或者是你的管腳出問題。而你的算法設計本身不會有問題。

咋還有個 Advanced 呢?
為啥又出來了這么一個叫做 DSP builder 高級模塊組呢?(8.0 里面才有)。讓我們首先來看看DSP builder 本身。有這么幾個問題。首先 DSP builder,號稱是用來做算法的,但是搭出來的模型看上去更像是電路圖,和本身算法的框圖區別巨大。其次,作為一個不太了解硬件的人,可能我并不知道如何才能達到我需要的能力。換句話說,我的時鐘是 100 兆的,但我并不知道怎么樣的電路就可以做成 100M 的。還有一些細節上的問題,比如說多通道的問題,比如說系統層面的問題。所以,我們需要一套更加強大,有擴展性的平臺來解決這些算法設計上的核心問題。我們來看看這個高級模塊的四大特點:

1. 多通道支持,在這個模塊組中,接口都異常的簡單,基本上就是這樣三個,V, D, C. V就是 Valid, D 就是 Data, C 就是 Channel。所以要告訴他的就是,是個數據,是不是有效數據,是那個通道上的有效數據。所以,無論你是多少通道的設計,無論你怎么修改你的通道數目,模型就還是這么個模型,都是一樣的。這樣可以使你的模型和你的算法框圖看上去幾乎是一樣的。

2. 自動插流水。這個是比較高級的一個功能。就是在設計中間自己加入寄存器。你不需要在設計里放任何一個寄存器。你只需要告訴工具,你想要的時鐘頻率,和你的目標器件,工具可以自己在電路中間插入流水寄存器。這樣可以保證你的設計完全使用器件的最大能力,同時不會出現時序問題。可能的缺點就是,你無法預知延時,而大家知道,如果一個設計是流水線模式的,其實延時是多少并不重要了。

3. 系統層面的設計。這也是一個比較新鮮的東西。所有設計里面的寄存器都會被編入一個系統地址查找表,比如說 FIR 的系數,一些控制寄存器都會有不同的地址。我們可以通過一個系統接口來對這些寄存器進行操作。這樣使整個設計更具有系統化概念。在編譯的時候,同時非常高級的生成一個寄存器列表(網頁格式),包括寄存器名字,地址,初始值。所以可以見到,通過這個高級的模塊的增強,使得算法方面的實現與設計變得更加容易。也可以很容易的實現非常復雜的系統。


后記

花了點時間,寫了一大堆自己都看不太過去的東西。也不知道是不是把人都看得煩了。總是很容易的就陷入了技術的陷阱里面,而無法到達自己定義的娛樂的境界。很有點慚愧的味道。看來再不能自詡為芯片業中娛樂能力最強的人了。大概只能算是其中之一了。不過想想也沒太必要牽強于一種觀念,不能娛樂就不能娛樂罷,關鍵是能不能因此而有一些收獲。如果說看了這么多,有了很多收獲,有一些觀念就這么莫名其妙的建立起來了。那這些別字百出的文字也就有他們存在的意義了。這些文字到這里算是一個斷點,當然我也并不希望就是一次結束。希望可以成為一種開始,一種對技術討論的新的方式的嘗試。我并不能確定這種嘗試的意義具體能有多重大,因為我能想到的就是我自己床邊桌前那一小塊地皮上的雞毛蒜皮。但是無論如何,這算件挺有意思的事情。而我本身也算是在自娛自樂了吧。

但是,問題是,我依然是盲目的。我不知道看我的這些文字的人在想些什么,他們具體的需要什么,他們想知道什么。我只是摸著腦袋猜,阿門,他們大概應該知道這些吧,于是我就寫了。這當然肯定是不精準的。我也并不太想去寫那些文檔中已經有的東西,所以一些教科書式樣的文字在我這里是沒有的,雖然那樣可以消耗很多篇幅,比如說,第一步,第二步。拜托,大家都是成年人了,能不能有點創意呀?完蛋了,又跑題了。所以呢,其實我想說的是,我需要反饋,我需要反饋來讓我做的更好。我不希望我只是一個孤獨的行走的人,我希望看到有多少人在看著我行走。

所以,如果你,可以給我一些你的想法,你的需求,或者你的問題,哪怕你的理想。都可以一股腦的灌給我。垃圾郵件暫時還是免了。

祝大家玩得開心。

完整的pdf格式文檔51黑下載地址(共52頁):
大話FPGA.pdf (3.29 MB, 下載次數: 294)


評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏17 分享淘帖 頂4 踩
回復

使用道具 舉報

沙發
ID:621747 發表于 2019-10-10 15:21 | 只看該作者
很好的資料,想下載下來學習!
回復

使用道具 舉報

板凳
ID:653521 發表于 2020-5-9 22:26 | 只看該作者
謝謝樓主分享!
回復

使用道具 舉報

地板
ID:748235 發表于 2020-5-10 12:17 | 只看該作者
謝謝樓主分享
回復

使用道具 舉報

5#
ID:653521 發表于 2021-3-16 21:46 | 只看該作者
學習學習!頂!
回復

使用道具 舉報

6#
ID:491589 發表于 2021-4-2 23:56 | 只看該作者
樓主能用如此貼切的例子,讓FPGA降低了認識的難度。
回復

使用道具 舉報

7#
ID:691028 發表于 2021-4-9 09:13 | 只看該作者
謝謝樓主的無私共享!學習了
回復

使用道具 舉報

8#
ID:1045548 發表于 2022-9-23 11:04 | 只看該作者
樓主是大神啊!跟著大神直接起飛,6666
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日日操操操 | 中文字幕第一页在线 | 亚洲精品视频一区 | 午夜视频在线 | 91精品国产综合久久久亚洲 | 羞羞视频在线观看免费观看 | 91视频网址 | 免费不卡视频 | 免费一区二区三区 | 国产日韩欧美精品一区二区三区 | 国产一区免费 | 天天天插 | 神马久久av | 亚洲欧美v| 992人人草| 亚洲视频不卡 | www.日韩| 久久精品国产久精国产 | 久优草| 中文字幕在线观看日韩 | 日本a视频 | 国产中文字幕在线观看 | 日韩精品| 亚洲香蕉 | 国产一二三区电影 | 欧美一区二区三区久久精品 | 成人影视网 | 国产片侵犯亲女视频播放 | 久久一区视频 | 91亚洲精品国偷拍自产在线观看 | 视频一区二区国产 | 成人免费视频网站在线观看 | 丁香五月网久久综合 | 日干夜操 | 精品国产乱码久久久久久图片 | 欧美成年网站 | 国产精品99久久久久久动医院 | 国产精品久久久久久久久久久久午夜片 | 伊大人久久 | 亚洲午夜精品一区二区三区 | 在线资源视频 |