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 的警告給你。也可以嘗試做一些仿真體會一下。
一號門 = A + B 二號門 = C + D.
三號門 = 一號門 + 二號門
四號門 = 三號門 + E
這樣通過一個三層門的結構做一個五輸入的加法器,來達到最好的效果。
6 輸入查找表 (StratixII, CycloneII, 和其他那些比較新的器件)
在新的結構中,我們可以使用 6 輸入的查找表,這樣,就可以用三個數加在一起 變成:
一號門 = A + B + C
二號門 = 一號門 + D + E
Design Space Explorer: 這個是一個實在沒辦法的辦法,但凡還有一線生路,最好不要用這個東西。他會自動的對你的設計根據一些設置,不斷的嘗試布局布線。比如使用不同的優化方法,不同的算法,甚至不同的種子來做編譯,最后給你一個最符合約束要求的編譯結果。但是這樣的工作量有多大,大家可想而知了。如果你有比較多的時間,你可以試試把它扔在那里跑個幾天。
不求甚解之 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
再了解一下 Jtag Debug 的模式選擇,一共有五個等級的選擇。和選擇 CPU 一樣,從簡單到復雜。一般來說選擇 Level2 也就夠用的。
自定義指令設置。這是最有價值的設置。別忘記了,我們是在 FPGA 的世界里。所以 CPU并不像在其他地方那樣的鐵板一塊。我們可以選擇使用自定義的指令。所謂自定義指令,并不是一個軟件宏或者函數。而是一塊硬件。當 CPU 調用到這個指令的時候,事實上它調用的就是這個硬件模塊,它被嵌入在 CPU 中。而這其實就是 NiosII 好玩的地方。
好了,現在我們要考慮的問題,就是使用。使用 CPU 的方法,當然就是軟件編程。NiosII的軟件其實是非常簡單的。就是普通的 C,或者 C++,需要做的就是不斷的對端口的地址讀啊,寫啊,計算數據,就好了。但也可能非常的復雜,因為你不僅需要了解軟件編程,你更需要了解你使用的那些硬件,那些外設模塊。NiosII 的編程很硬件的依賴性是很強的。針對比較大型的一些外設,可以寫一些 HAL 程序。這是類似于驅動的一些指令。而軟件只需要調用這些 API 就可以了。大部分的 NiosII 程序是不需要使用操作系統的,作為一個嵌入式系統的控制核心,更多的是一些存儲式的讀寫,算法的計算的操作。除非你需要運行一些網絡協議啊,什么的。但其實我們可以用更加解構的方式來看待一個操作系統。操作系統其實就是給我們提供了一大堆的操作指令而已。沒什么更特別的作用了。所以,思考一下吧。
大家知道我們這里說玩轉 FPGA 的,每次我在 FPGA 里面提到了 DSP 的題目的時候,總是會有一些人打斷我說,兄弟啊,你大概走錯地方了。我們這里都是硬件工程師,或者可能有些寫 C 的,但是 DSP,那東西不會寫哦。那么好吧,我就跑到 DSP 那里去講,FPGA,然后就會有人問我,你們這個 FPGA 和 TI 的 DSP 比有什么區別呢?我暈。我想說的是,我這里的 DSP 是 Digital Signal Processing (數字信號處理),而不是 Digital Signal Processor (數字信號處理器)。
1. 多通道支持,在這個模塊組中,接口都異常的簡單,基本上就是這樣三個,V, D, C. V就是 Valid, D 就是 Data, C 就是 Channel。所以要告訴他的就是,是個數據,是不是有效數據,是那個通道上的有效數據。所以,無論你是多少通道的設計,無論你怎么修改你的通道數目,模型就還是這么個模型,都是一樣的。這樣可以使你的模型和你的算法框圖看上去幾乎是一樣的。
3. 系統層面的設計。這也是一個比較新鮮的東西。所有設計里面的寄存器都會被編入一個系統地址查找表,比如說 FIR 的系數,一些控制寄存器都會有不同的地址。我們可以通過一個系統接口來對這些寄存器進行操作。這樣使整個設計更具有系統化概念。在編譯的時候,同時非常高級的生成一個寄存器列表(網頁格式),包括寄存器名字,地址,初始值。所以可以見到,通過這個高級的模塊的增強,使得算法方面的實現與設計變得更加容易。也可以很容易的實現非常復雜的系統。