1. 程式人生 > >FPGA燒錄基礎知識

FPGA燒錄基礎知識

JTAG下載方式:即生成sof檔案或者轉換的.jic可以通過JTAG方式下載。是直接將程式檔案下載到FPGA裡面,由於FPGA是SRAM結構,掉電後程序消失。

AS下載方式:   即生成pof檔案,通過Activeserial programming方式下載。是將程式下載到配置晶片裡面(一般使用EPCS4/EPCS16/EPCS64,我們EP4CE6開發板使用的是EPCS4,我們EP4CE10開發板使用的是EPCS16),然後配置晶片自動載入到FPGA裡面,掉電後程序不消失。一般使用JTAG做除錯和下載。另外AS下載完成後,需要掉電,然後拔掉AS下載器,然後重新上電,程式才能執行。

 

EPCS:序列儲存器,NiosII 不能直接從EPCS中執行程式,它實際上是執行EPCS控制器的片內ROM中的程式碼(即Bootloader),把EPCS中的程式搬到RAM中執行。FPGA配置資料和NiosII程式都存放在EPCS器件中。FPGA配置資料放在最前面,程式放在後面,程式可能有多個段,每個段前面都插有一個“程式記錄”。一個“程式記錄”由2個32位的資料構成,一個是32位的整數,另一個是32位的地址,分別用於表示程式段本身的長度和程式段的執行時地址。這個“程式記錄”用於幫助Bootloader把各個程式段搬到程式執行時真正的位置。

Nios II Cache

經常有人反映說自己寫的程式碼無法正常工作,然後晒出自己的程式碼來。經過對使用者程式碼的分析可以知道,他們都是參考了網路上流傳的比較系統的兩份資料的方式,採用直接地址對映,即用指標的方式來直接操作外設裡面的暫存器。這樣操作在不帶Cache的NIOS II版本中能夠很好的奏效,例如NIOS II的e版本和s版本,但是在f版本中,為了增強NIOS II處理器的效能,加入了資料cache和指令cache。如果使用者使用帶cache的CPU,卻還是像之前那樣,直接使用指標對映暫存器地址的方式,就會出現很多時候,我們希望寫入的資料並沒有直接寫入到外設IP的暫存器中,而是寫入到了cache中,即外設IP中並未立即寫入我們希望寫入的值,也就不會執行相應的操作了。(關於CACHE是個啥東西,這裡不做專門講解,有興趣的請自行查閱相關資料)。那麼為什麼明明是要寫入到外設IP暫存器中的資料,卻寫入到了cache中呢?這是因為,NIOS II e和s版有31位的地址線,f版本有32位地址線,但是這第32位地址線恰恰就是用來選擇cache的,當地32位地址線為0的時候,選擇cache,當第32位地址線為1的時候,就旁路/遮蔽cache,也就是說,當我們還是繼續使用指標對映的方式操作外設暫存器,假設暫存器的地址為0x00000001,那麼在帶有cache的系統中,該地址實際是對映到了cache中,而真正的暫存器地址應該是0x10000001,因為要想定址到實際的暫存器地址,必須遮蔽cache,即需要地址的最高位為1。所以,如果我們還是用指標直接操作0x00000001這個地址,當然資料不會傳入實際的暫存器中,所以無法生效。那麼怎麼解決呢,個人觀點還是使用Altera 官方提供的HAL庫,如io.h這個檔案裡,提供了很多讀寫函式:

IORD_32DIRECT(BASE, OFFSET)       //從某地址讀出32位的資料

IORD_16DIRECT(BASE, OFFSET)       //從某地址讀出16位的資料

IORD_8DIRECT(BASE, OFFSET)         //從某地址讀出8位的資料

 

IOWR_32DIRECT(BASE, OFFSET, DATA)   //向某地址寫入32位的資料

IOWR_16DIRECT(BASE, OFFSET, DATA)   //向某地址寫入16位的資料

IOWR_8DIRECT(BASE, OFFSET, DATA)      //向某地址寫入8位的資料

 

IORD(BASE, REGNUM)                        //從某地址按照CPU資料位寬(32)讀出資料

IOWR(BASE, REGNUM, DATA) //向某地址按照CPU資料位寬(32)寫入的資料

 

這些函式在使用的時候,會自動遮蔽CACHE,另外,針對每個特定的IP,Altera也都提供了相應的驅動檔案,如PIO核,提供的驅動標頭檔案名叫“altera_avalon_pio_regs.h”,在這裡面定義了對PIO外設IP進行讀寫和控制的所有驅動函式,這些函式也都是自動遮蔽了CACHE的。而且,使用這個函式,能夠方便的在各種NIOS II 版本的CPU之間移植,而不用擔心CACHE的問題。所以,個人強烈推薦使用官方庫進行IP核的使用。如果使用者執意要堅持自己的觀點,使用指標直接對映,那麼請在定義指標的時候,將地址最高位置為1,例如, PIO_LED的地址為0x00000001,那麼使用者定義該地址指標時,請用#define PIO_LED (0x00000001 | 0x80000000),或者#define PIO_LED (PIO_LED_BASE | 0x80000000),其中PIO_LED_BASE在system.h標頭檔案中定義。這樣再操作就不會有問題了。