NIOS開發(fā)結(jié)構(gòu)基礎(chǔ)介紹
我們使用VHDL語言,根據(jù)FPGA管腳與數(shù)碼管和按鍵管腳的連接,通過一系列的語句控制管腳電平的高低,從而讓FPGA實現(xiàn)數(shù)碼管顯示功能??梢?,對于比較簡單的功能實現(xiàn),可以像這個例子中那樣,直接控制最底層資源,甚至對每個管腳在每個時刻的電平輸出了如指掌。
但是,如果設(shè)計稍顯復(fù)雜,那么對底層細節(jié)的過多關(guān)注就會成為一種累贅。
試想我們平時在電腦上編寫C程序,比如在顯示器上輸出一行字,我們只用一句printf()即可完成,至于打印命令怎么傳到顯示芯片上,哪個芯片管腳怎么 變化,又怎么傳到顯示器上輸出,諸如此類涉及底層硬件的問題,我們沒必要關(guān)注太多。于是,我們把用printf()這類高級語言描述設(shè)計邏輯的工作稱為軟 件設(shè)計。顯然,軟件只是一種抽象的看不見摸不著的東西,它的結(jié)構(gòu)接近于人類思維邏輯。無論軟件再怎樣構(gòu)思精妙,只有在硬件上才能體現(xiàn)出實際效果。
做計算機開發(fā)應(yīng)用程序的時候,硬件是現(xiàn)成的,軟硬件之間的橋梁早就由操作系統(tǒng)給你搭好了,我們只需專心完成軟件的構(gòu)思和設(shè)計就OK。
顯而易見,軟硬件的分工會給電子設(shè)計帶來極大的方便,自然有人把這種分工方式引進FPGA設(shè)計領(lǐng)域,琢磨著怎么在小小的FPGA上也搞個軟硬件協(xié)同設(shè)計,負責(zé)硬件設(shè)計的和負責(zé)軟件的各司其職,最后pia一整合,效率倍增。
來看看nios是怎么做的。拿出DE2開發(fā)板,上面很多外設(shè)接口和與之連接的芯片,那是硬件,中間有一塊大的CycloneII芯片,里面是空的,等著我 們編寫程序下載到里面運行,前篇文章我們用最原始的方法寫了個數(shù)碼管控制器,這次我們換種方法,同樣是數(shù)碼管控制器,用軟硬件協(xié)同設(shè)計來完成。
跟計算機對比,硬件我們有了,軟件就用C語言來寫,但是nios系統(tǒng)可沒提供WinXP,也就是說軟件和硬件之間的那座橋還得自己解決。
看上圖,這座橋分為3個層次:硬件控制層,設(shè)備驅(qū)動層,硬件抽象層(簡稱HAL)。既然是軟硬件的過渡部分,那么這3層的設(shè)計需要對硬件和軟件都有一定程度的了解,姑且稱之為“軟硬件混雜設(shè)計”吧。
每一層所要完成的任務(wù),就是整合和簡化硬件操作細節(jié),整合,再整合,使其一目了然。
1> 硬件控制層
與硬件直接打交道的是硬件控制層。
上面提到,搭“橋”的目的是讓軟件設(shè)計人員可以完全忽略硬件操作細節(jié),因此,我們希望所有的硬件細節(jié)都能在這層解決,并向設(shè)備驅(qū)動層提供整齊的“接口”。之前的例子可看作硬件控制器的雛形,但還缺少與設(shè)備驅(qū)動層的接口。
何為“整齊”呢?比如說,設(shè)計數(shù)碼管控制器,我想讓它顯示數(shù)字“5”,最好的方法是,我將數(shù)據(jù)“5”和表示“顯示”的命令從設(shè)備驅(qū)動層傳給硬件控制層,直 接告訴它:我要“數(shù)碼管”“顯示”“5”。至于要控制哪個管腳電平高低才能顯示“5”,全由硬件控制層負責(zé)。
類似這樣分工合作的例子在日常生活中屢見不鮮。比如說,郵局要將一封信送給家住A小區(qū)的張三,郵遞員把信放入A小區(qū)的信箱,小區(qū)物業(yè)再去確認張三的具體住處,把信最終送到張三手中。
類比可見,郵局相當于設(shè)備驅(qū)動,物業(yè)相當于硬件管理器,張三則是具體的硬件,郵局和物業(yè)之間的接口是物業(yè)提供的信箱,設(shè)備驅(qū)動和硬件管理層之間的接口,我們稱之為“寄存器”,同樣由硬件管理層提供,“寄存器”是兩層之間得以明確分工和相互聯(lián)系的關(guān)鍵。
設(shè)備驅(qū)動開發(fā)人員眼中的硬件就是一組寄存器的抽象,通過讀寫寄存器間接控制硬件行為。
那么,在數(shù)碼管控制器里加入一個數(shù)據(jù)寄存器和一個命令寄存器:
data_reg存儲待顯示的數(shù)據(jù),cmd_reg為‘1’時顯示,為‘0’時清空。
2> Avalon總線
你可能會說,這有什么?在每個硬件管理器和設(shè)備驅(qū)動之間都建立一個通道唄。這是最直接的辦法,但顯然不是最好的辦法。試想,城市為什么要建高速公路呢?多 修幾十根羊腸小道不也一樣能跑車嗎?有人回答:為了收養(yǎng)路費唄。$%@! 小路上開車,速度慢且不說,管理協(xié)調(diào)是個大問題,是一條大公路容易管理,還是幾十根羊腸容易理順?
好了,回到正題,nios系統(tǒng)需要一條“高速公路”,稱為“總線”,“總線仲裁器”則行使“交通管理局”的角色,控制數(shù)據(jù)的進出,并為每個硬件提供一個進 出“高速公路”的接口,用“地址”來標識這個接口的位置。nios采用的是Avalon總線,它有著一套接口規(guī)范:
同步時鐘 clk
片選信號 chipselect
地址 address
讀請求 read
讀傳輸 readdata
寫請求 write
寫傳輸 writedata
這些是比較重要的接口信號,其它的不一一列舉了。硬件控制器要接入總線,必須遵循接口規(guī)范,就像高速公路出口必須擺個收費站一樣。
那么在數(shù)碼管控制器里加入Avalon總線信號:
既然加入了兩個寄存器和avalon信號,就需要對硬件邏輯進行必要改動,大致過程是,當chipselect和write有效時,將 write_data賦給address對應(yīng)的寄存器;當chipselect和write有效時,將address對應(yīng)寄存器的值賦給 read_data。另外,根據(jù)這兩個寄存器的內(nèi)容決定數(shù)碼管輸出信號oSEG0。代碼不貼出來了,具體見工程壓縮包。
3> 設(shè)備驅(qū)動程序
其實,“總線仲裁器”也可看作一種硬件控制器,只不過它管的不是具體的硬件,而是負責(zé)數(shù)據(jù)的傳輸。那么它也有自己的設(shè)備驅(qū)動,封裝了總線操作的細節(jié)。既然總線是現(xiàn)成的,我們秉承“拿來主義”的原則,甭管它怎么實現(xiàn)的,會用就行。
例如,數(shù)碼管設(shè)備驅(qū)動要把數(shù)據(jù)“5”和“顯示”命令傳給數(shù)碼管控制器,設(shè)計兩個函數(shù),由于數(shù)據(jù)和命令的傳遞必須經(jīng)過總線,那么需調(diào)用總線驅(qū)動函數(shù)IOWR(基地址, 偏移量, 數(shù)據(jù)),另外,讀取寄存器用到IORD(基地址, 偏移量),這兩個函數(shù)在io.h>里。
io.h>的路徑是..alterakits ios2_60componentsaltera_nios2HALinc。
至此,“橋”搭完。
函數(shù)功能從字面上很好理解。剛才定義兩個寄存器時,data_reg在前面,所以偏移量是0,cmd_reg在后面,偏移量是1。××_REG_MSK稱 為掩碼,avalon總線數(shù)據(jù)接口共32位,但我們設(shè)計的data_reg位寬是3,cmd_reg位寬為1,掩碼的作用在于告知寄存器寬度,知道就行, 實際上用不著。××_REG_OFST是寄存器內(nèi)的偏移量,這里同樣用不著,先寫上吧。
OK,我們的數(shù)碼管設(shè)備驅(qū)動文件正式出爐了,看看是不是簡潔明了很多???
4> 硬件抽象層(HAL)
設(shè)備驅(qū)動程序封裝的僅僅是對某個寄存器的一次讀寫操作,功能單一,需要在硬件抽象層再做一次封裝。
直接將這些函數(shù)列出來,一目了然,不作多余的解釋了。
評論