學(xué)習(xí)FPGA,筆者推崇的學(xué)習(xí)方法是先整體再局部。先對(duì)FPGA 有一個(gè)整體的認(rèn)識(shí),包括知道有哪些知識(shí)點(diǎn),這些知識(shí)點(diǎn)所處的位置和作用。然后在此基礎(chǔ)上再逐個(gè)突破。
FPGA知識(shí)大串講是一個(gè)系列文章,先概括性地將FPGA的知識(shí)點(diǎn)串聯(lián)起來(lái),使讀者對(duì)FPGA有一個(gè)整體的認(rèn)識(shí),為后續(xù)的各項(xiàng)學(xué)習(xí)打下堅(jiān)實(shí)基礎(chǔ)。
本系列文章由6篇文章組成。第一篇文章闡述大部分同學(xué)的學(xué)習(xí)誤區(qū)。第二篇文章,介紹了FPGA所有的知識(shí)點(diǎn),并將其串聯(lián)起來(lái)。剩下的4篇文章,是對(duì)所有知識(shí)的分別概述,其內(nèi)容包括:組合邏輯、D觸發(fā)器、時(shí)序邏輯和FPGA 時(shí)序。
首先我們看一下學(xué)習(xí)誤區(qū)。
第1節(jié) 誤區(qū)1:學(xué)習(xí)語(yǔ)法過(guò)多
大部分初學(xué)者最大的學(xué)習(xí)誤區(qū)就是花費(fèi)大量的時(shí)間用于VERILOG語(yǔ)法的語(yǔ)法,并作為學(xué)習(xí)的重點(diǎn)。
入門(mén)就看VERILOG,相信這是很多讀者入門(mén)FPGA的普遍做法,甚至,甚至部分同學(xué)花了幾個(gè)月時(shí)間用來(lái)學(xué)習(xí)語(yǔ)法。
但其實(shí)VERILOG 里面的語(yǔ)法百分之九十的是用來(lái)測(cè)試用的,設(shè)計(jì)僅僅用到其中10%的語(yǔ)法,而且設(shè)計(jì)語(yǔ)法非常之簡(jiǎn)單,大部分代碼是由一個(gè)一個(gè)always、assign和例化等組成的
上圖是實(shí)現(xiàn)FPGA例化功能的代碼,將模塊test_edge放到本模塊中來(lái),其作用類(lèi)似于C語(yǔ)言的函數(shù)調(diào)用,其語(yǔ)法亦相似,將接口信號(hào)一個(gè)一個(gè)關(guān)聯(lián)起來(lái)即可。還未掌握例化語(yǔ)法的讀者,可以自行查找相關(guān)知識(shí)。
FPGA的設(shè)計(jì),通過(guò)使用ALWAYS的格式來(lái)實(shí)現(xiàn)。ALWAYS格式有兩種,時(shí)序邏輯的ALWAYS和組合邏輯的ALWAYS,其結(jié)構(gòu)如下。
當(dāng)要實(shí)現(xiàn)不同功能時(shí),在ALWAYS格式里,添加if else,以及加減乘除、邏輯運(yùn)算等即可,如下面的代碼
?
?
?
上面實(shí)現(xiàn)串口接收功能、一個(gè)典型的FPGA代碼。第1至38行是接口、信號(hào)的定義,其他則是主體的設(shè)計(jì)部分。由上面代碼可以看出FPGA的代碼有以下幾個(gè)特點(diǎn)。
? FPGA代碼由多個(gè)結(jié)構(gòu)簡(jiǎn)單、相似的ALWAYS和ASSIGN組成的。本例中一共用到了8個(gè)ALWAYS語(yǔ)句和7個(gè)ASSIGN語(yǔ)句,除此之外沒(méi)有其他結(jié)構(gòu)。復(fù)雜點(diǎn)的FPGA代碼,亦僅是多了一個(gè)例化功能。
? 每個(gè)ALWAYS塊只用到簡(jiǎn)單的語(yǔ)法,均是由if else,以及加減乘除、邏輯判斷等基本操作。沒(méi)有復(fù)雜的東西,相信具有C語(yǔ)言基礎(chǔ)的讀者,一般能讀懂,或者能猜到大概功能。
? 除了第一個(gè)簡(jiǎn)單的ALWAYS之外,其他每個(gè)ALWAYS只設(shè)計(jì)一個(gè)信號(hào)。例如,第53至62行只設(shè)計(jì)cnt0,第92至98行只設(shè)計(jì)dout信號(hào)。這是至簡(jiǎn)設(shè)計(jì)法的一大特色,這樣的設(shè)計(jì)才符合硬件設(shè)計(jì)的特點(diǎn)。這不是沒(méi)有根據(jù)的,規(guī)范的企業(yè)如華為海思、中興等,均是如此風(fēng)格的代碼。
由此可見(jiàn),VERILOG語(yǔ)法是非常簡(jiǎn)單的。雖然語(yǔ)法簡(jiǎn)單,但如何通過(guò)簡(jiǎn)單的if else以及加減乘除,就實(shí)現(xiàn)強(qiáng)大的FPGA功能,這又很不簡(jiǎn)單,所以不同于學(xué)習(xí)C、C++等軟件語(yǔ)言,學(xué)習(xí)FPGA沒(méi)有必要花太多的精力于語(yǔ)法上,關(guān)鍵在于應(yīng)用。
第2節(jié) 誤區(qū)2:追求代碼精簡(jiǎn)
鉆研VERILOG語(yǔ)法,追求使用最少的代碼實(shí)現(xiàn)功能,這又是一個(gè)大誤區(qū)。
放在C、C++、JAVA等語(yǔ)言上,追求精簡(jiǎn)的代碼實(shí)現(xiàn),是一個(gè)正常的需求。但放在FPGA,則完全不是這回事。
衡量FPGA設(shè)計(jì)優(yōu)秀的標(biāo)準(zhǔn),不是看代碼量的多少,而是比較綜合出來(lái)的電路,它使用了多少資源,能夠支持的時(shí)鐘頻率高低等。
例如一個(gè)加法器,在200M的時(shí)鐘頻率下,可以直接使用“+”來(lái)實(shí)現(xiàn)。但假如要跑到300M或者更高頻率,業(yè)界會(huì)把該加法器拆分成多個(gè)邏輯門(mén),并且在邏輯門(mén)之間增加寄存器(即流水線(xiàn)設(shè)計(jì))。這樣設(shè)計(jì),代碼會(huì)由原來(lái)的1行,變成上百行,并且難以讀懂。雖然代碼量增加了,但電路卻更優(yōu)秀了。
總而言之,不要追求VERILOG代碼的精簡(jiǎn),而是追求電路的優(yōu)秀設(shè)計(jì),多學(xué)習(xí)流水線(xiàn)、資源換速度、速度換資源等設(shè)計(jì)方式,這才是好的FPGA學(xué)習(xí)方向。
第3節(jié) 誤區(qū)3:膚淺的實(shí)驗(yàn)
通過(guò)開(kāi)發(fā)板學(xué)習(xí)FPGA是一個(gè)較好的入門(mén)方法,例如MDY的ALTERA學(xué)習(xí)板MP801、XILINX學(xué)習(xí)板MP802,既有LED燈、數(shù)碼管、VGA等簡(jiǎn)單接口,還有SDRAM、DDR、千兆網(wǎng)等高級(jí)接口,其擁有大量免費(fèi)的學(xué)習(xí)資源,包括工程、視頻、文檔等,是學(xué)習(xí)FPGA非常好的方法。
但部分讀者拿到學(xué)習(xí)工程后,每個(gè)工程都是新建工程、編譯工程、上板、看現(xiàn)象,僅此而已。實(shí)驗(yàn)做了很多,設(shè)計(jì)能力卻提高得很慢。因?yàn)檫@里缺少關(guān)鍵的一步:自己去寫(xiě)代碼。
讀懂功能要求后,要親自去寫(xiě)一寫(xiě)代碼,邊寫(xiě)邊仿真,邊仿真邊修改。寫(xiě)不出來(lái)的時(shí)候,對(duì)著仿真波形多思考思考。通過(guò)這種方法,訓(xùn)練代碼設(shè)計(jì)能力、仿真調(diào)試能力,掌握MODELSIM等工具的使用。
代碼完成設(shè)計(jì)后,上板驗(yàn)證,這個(gè)時(shí)候現(xiàn)象大概率是不正確的,使用在線(xiàn)調(diào)試工具去定位問(wèn)題找到問(wèn)題。通過(guò)這種方法,訓(xùn)練定位問(wèn)題能力、解決問(wèn)題能力,掌握在線(xiàn)調(diào)試工具的使用。
最后,將自己設(shè)計(jì)的代碼,與開(kāi)發(fā)板的官方代碼對(duì)比,吸收好的方面,改進(jìn)自己的設(shè)計(jì)能力。
按照上面步驟,當(dāng)您親自完成一個(gè)功能設(shè)計(jì),獲得極大成就感和滿(mǎn)足感的同時(shí),設(shè)計(jì)能力也切實(shí)得到了提高,這樣幾個(gè)設(shè)計(jì)循環(huán)上來(lái),基本上就掌握FPGA設(shè)計(jì)了。
第4節(jié) 誤區(qū)5:軟件思維
VERILOG是硬件描述語(yǔ)言,它是對(duì)硬件的描述,而非軟件的設(shè)計(jì)。FPGA開(kāi)發(fā)本質(zhì)上是硬件的開(kāi)發(fā),與設(shè)計(jì)電路原理圖是相似的,因此要用硬件思維。而C、C++、JAVA等語(yǔ)言是軟件開(kāi)發(fā),使用的是軟件思維。
有C語(yǔ)言基礎(chǔ)的同學(xué),很容易按照軟件思維來(lái)進(jìn)行FPGA設(shè)計(jì),這是不正確的一種思想。那么,硬件思維和軟件思維本質(zhì)上有什么不同呢?
我們先看下軟件是如何設(shè)計(jì)的。
上面4行是軟件代碼,先讓a為1;然后讓b=a+1,即讓b為2;再讓a為2;最后c=a+2,即讓c為4。這有什么特色?
? 軟件代碼是一行一行順序執(zhí)行的;
? 軟件是一種過(guò)程設(shè)計(jì),是讓信號(hào)怎么做、怎么變的設(shè)計(jì)。
? 軟件考慮的是此時(shí)此刻,該信號(hào)要怎么做。
而硬件設(shè)計(jì)思維,我們可以通過(guò)MP801開(kāi)發(fā)板的電路設(shè)計(jì)為例進(jìn)行闡述。
假設(shè)我們要設(shè)計(jì)一款MP801開(kāi)發(fā)板,這個(gè)開(kāi)發(fā)板使用了多個(gè)元器件,例如有FPGA主芯片、AD、DA、數(shù)碼管、按鍵等。每個(gè)元器件都有它自己獨(dú)特的功能。
首先,每個(gè)元器件不一定有輸入,但一定會(huì)有輸出。例如,晶振輸出50M時(shí)鐘;當(dāng)按下按鍵時(shí),電平輸出為0,未按下時(shí)輸出為1;數(shù)碼管的輸出,則是顏色的發(fā)光狀態(tài)等。
其次,每個(gè)元器件通常都有一個(gè)數(shù)據(jù)手冊(cè),該手冊(cè)描述的是該元器件的輸出功能,即在什么樣情況下,會(huì)有怎么樣的輸出。以晶振為例,文檔一般會(huì)說(shuō)明電源電壓為多少,然后輸出50M的時(shí)鐘信號(hào)。再以AD9280為例,文檔會(huì)說(shuō)明輸入二進(jìn)制值為多少時(shí),輸出什么樣的電平,例如值為8’h00時(shí),輸出電壓為0V;值為8’hff時(shí),輸出電壓為5V等。
再次,您可以發(fā)現(xiàn),每個(gè)數(shù)據(jù)手冊(cè)一定會(huì)說(shuō)明清楚,在所有的情況下,輸出會(huì)有什么樣的變化。
最后,當(dāng)選中了元器件后,硬件工程師的工作,就是把它們正確地連起來(lái)。
當(dāng)電路板開(kāi)發(fā)并生產(chǎn)完成后,一通電,全部元器件都同時(shí)在工作。不存在說(shuō)某個(gè)元器件工作,另一個(gè)元器件不工作的情況(這里不工作是指不通電的情況,而不是不變化。事實(shí)上,不變化也是該元器件的一個(gè)輸出功能)。當(dāng)然,更不存在,此時(shí)元器件A工作,元器件B消失的情況,事實(shí)上,這些元器件是一直保持存在的。
上面就是硬件的設(shè)計(jì)過(guò)程,我們可以總結(jié)出硬件思維的特色。
? 硬件首先是描述一個(gè)“元器件”,它是什么,它有什么功能,即在什么情況下,有什么樣的輸出。軟件是讓它怎么做,過(guò)多久為1,過(guò)多久又為2等。這就是VERILOG這個(gè)硬件描述語(yǔ)言的特性,一個(gè)ALWAYS語(yǔ)句,就相當(dāng)于一個(gè)“元器件”,每個(gè)ALWAYS都是描述“元器件”(設(shè)計(jì)信號(hào))的變化情況。
? 描述一個(gè)“元器件”是什么時(shí),就要概括所有的情況,就如數(shù)據(jù)手冊(cè)般的清晰。對(duì)應(yīng)的是FPGA的ALWAYS語(yǔ)句,其設(shè)計(jì)的信號(hào),一定是所有條件if else下的變化。特別注意的是,不同于軟件只考慮此時(shí)此刻值為多少,硬件和FPGA考慮的是“整個(gè)電路生命周期”下的各種情況處理方式。
? 當(dāng)您選完了“元器件”后,就是把元器件連接起來(lái)。對(duì)應(yīng)FPGA,則是通過(guò)相同“信號(hào)名”來(lái)接各個(gè)部分連接起來(lái)。
? 最后,一通電,全部“元器件”都同時(shí)工作了。對(duì)應(yīng)FPGA,就是VERILOG代碼會(huì)綜合成電路網(wǎng)表,最終會(huì)下載到FPGA,像電路般全部同時(shí)運(yùn)行。ALWAYS設(shè)計(jì)的各種信號(hào)是一直物理存在的。
認(rèn)真體會(huì)軟件思維和硬件思維的異同,有助于我們更好更規(guī)范地進(jìn)行FPGA開(kāi)發(fā)。同時(shí),正確地理解硬件思維,對(duì)于一些錯(cuò)誤觀(guān)念和設(shè)計(jì)法,就有自己的判斷了。
例1:有部分讀者閱讀VERILOG代碼時(shí),會(huì)想當(dāng)然地認(rèn)為begin 里面代碼都是串行執(zhí)行的,例如下面的代碼,會(huì)認(rèn)為按順序從第2至11行順序地串行執(zhí)行。
?
從嚴(yán)格的意義上,筆者認(rèn)為“順序串行執(zhí)行”這個(gè)概念是不正確的,F(xiàn)PGA本身就沒(méi)有“執(zhí)行”的概念。由前面講述可知,ALWAYS僅是像數(shù)據(jù)手冊(cè)那樣,描述“元器件”cnt的功能,即描述cnt在所有情況下的變化情況。所以,正確的理解,應(yīng)當(dāng)是像讀“數(shù)據(jù)手冊(cè)”那般,“閱讀”cnt的功能。
例2:大家可以看出下面代碼,是按軟件思維,還是按硬件思維設(shè)計(jì)的呢?
不用理解上面代碼實(shí)現(xiàn)了什么功能,從風(fēng)格上就可以看出其是用軟件思維來(lái)設(shè)計(jì)的??梢圆孪肫鋵?xiě)代碼的過(guò)程,如先寫(xiě)第13行代碼,讓byte_satee加1;然后寫(xiě)第14至18行代碼,讓Pre_CMOS_iData變化,這怎么看起來(lái),都像是軟件的一種過(guò)程思維。其次,將多個(gè)信號(hào)放在一個(gè)ALWAYS中描述,就像將多個(gè)不同元器件都寫(xiě)在一個(gè)數(shù)據(jù)手冊(cè)上,必定是雜亂無(wú)章,講不清楚的。
比較規(guī)范的設(shè)計(jì)方法,推薦一個(gè)ALWAYS設(shè)計(jì)一個(gè)信號(hào),如下面代碼,就是實(shí)現(xiàn)了相似的功能。一個(gè)信號(hào)一個(gè)信號(hào)地描述設(shè)計(jì),長(zhǎng)期堅(jiān)持,必定能寫(xiě)出越來(lái)越優(yōu)秀的代碼。
審核編輯:湯梓紅
評(píng)論
查看更多