目前Nios已經取消了Native尋址模式(即從設備到主設備寄存器直接映射),全部採用了Dynamic尋址模式,查找了目前存在的一些資料,尤其是某些教程,還在使用Native模式,對Dynamic動態模式避而不談,還有好多資料摸棱兩可,說的模模糊糊,感覺應該是沒喫透這個東西,要麼就是調試程序的使用使用固有的2或者4方法,其實爲什麼這麼做,可能也不知道。下面根據查詢官方手冊,給出我的理解。
以下所說的32bit,16bit表示的都是數據寬度。
所有的寄存器都是8bit的!!
在Master來看,一個地址只對應一個寄存器!!!
Avalon MM 的master是32bit寬度
動態地址對齊方式是將MM從設備的地址空間連續地映射到主設備空間。內存類型的從設備控制器應該採用這種方式。在這種方式下,主設備的每一次讀傳輸(或寫傳輸)對應從設備一次或多次讀傳輸(或寫傳輸)。譬如,主設備數據寬度爲32bit,從設備爲16bit,則主設備每發起一次讀傳輸,從設備將被讀兩次,用於返回32bit數據(由Avalon Interconnect Fabric邏輯插入狀態機實現,用戶無需關心具體實現),同理,每一次寫操作,從設備執行兩次寫入操作。Dynamic對齊方式數據寬度限定爲8*2^n次方,即只能爲8 16 32 64等值
Slave端的數據寬度
在軟件編程時,使用IOWR_32DIRECT(數據位寬爲32位)、IOWR_16DIRECT(數據位寬爲16位)、IOWR_8DIRECT(數據位寬爲8位)進行寫操作
在軟件編程時,使用IORD_32DIRECT(數據位寬爲32位)、IORD_16DIRECT(數據位寬爲16位)、IOWR_RDIRECT(數據位寬爲8位)進行寫操作IOWR_8DIRECT(基地址、地址偏移量、數據),地址偏移量 = 寄存器編號1
IOWR_16DIRECT(基地址、地址偏移量、數據),地址偏移量 = 寄存器編號2
IOWR_32DIRECT(基地址、地址偏移量、數據),地址偏移量 = 寄存器編號*4IORD_8DIRECT(基地址、地址偏移量),地址偏移量 = 寄存器編號1
IORD_16DIRECT(基地址、地址偏移量),地址偏移量 = 寄存器編號2
IORD_32DIRECT(基地址、地址偏移量),地址偏移量 = 寄存器編號*4
這裏引出個問題,這個乘1、2、4是怎麼來的?
8 bit
比如,外設中的數據長度爲256,數據寬度爲8bit。那麼在外設中的數據存放方式爲
地址 | 數據 (8bit) |
---|---|
0x00 | REG[0] |
0x01 | REG[1] |
0x02 | REG[2] |
… | REG[…] |
0xFF | REG[255] |
在Dynmatic動態尋址模式下,master讀入到Avalon MM 的時候是這樣的
地址 | 數據 (32-bit) |
---|---|
0x00 | REG[3] REG[2] REG[1] REG[0] |
0x04 | REG[7] REG[6] REG[5] REG[4] |
0x08 | REG[11] REG[10] REG[9] REG[8] |
… | REG[…] REG[…] REG[…] REG[…] |
0xFC | REG[255] REG[254] REG[253] REG[252] |
根據上面的表格,當採用指令IORD_32DIRECT(BASE,OFFSET)
的時候,讀出的數據是32bit的也就是是4個字節,或者稱爲4個寄存器。有如下規律:
IORD_32DIRECT(BASE,0) //得到第一組4個寄存器(0-3)數據
IORD_32DIRECT(BASE,4) //得到第二組4個寄存器(4-7)數據
如果要單獨讀取某一個寄存器,那麼就是用提供的API
IORD_8DIRECT(BASE,0) //得到第1個寄存器(0)數據
IORD_8DIRECT(BASE,1) //得到第2個寄存器(1)數據
這才解釋了上面引用的代碼IORD_8DIRECT(基地址、地址偏移量),地址偏移量 = 寄存器編號*1
這裏的1
是如何來的。
16bit
理解了8bit的之後,16bit數據就需要理解一下原始的數據存放方式中的地址,到底是不是所謂的寄存器地址了,之前說了,寄存器的數據寬度是8bit的,這個是永遠不會變化的,而且master看每個地址只有一個8bit字節。綜合這兩句話,可以知道,其實每個16bit的數據實際上是由兩個寄存器數據組成的,這樣我們就需要重新排列以下原始數據了。
外設中的數據長度爲128,數據寬度爲16bit。那麼在外設中的數據存放方式爲
外設上的地址 | 寄存器地址 | 數據 (16bit) |
---|---|---|
0x00 | 0x01-0x00 | REG[1] REG[0] |
0x01 | 0x03-0x02 | REG[3] REG[2] |
0x02 | 0x05-0x04 | REG[5] REG[4] |
… | 0x…-0x… | REG[…] REG[…] |
0x7F | 0x7F-0x7E | REG[255] REG[254] |
在Dynmatic動態尋址模式下,master讀入到Avalon MM 的時候是這樣的
地址 | 數據 (32-bit) |
---|---|
0x00 | REG[3] REG[2] REG[1] REG[0] |
0x04 | REG[7] REG[6] REG[5] REG[4] |
0x08 | REG[11] REG[10] REG[9] REG[8] |
… | REG[…] REG[…] REG[…] REG[…] |
0xFC | REG[255] REG[254] REG[253] REG[252] |
看沒看到,實際上和8bit的時候是一樣一樣的,這個也就是爲什麼說將Native尋址模式幹掉的原因了,因爲無論外部如何變化,採用動態尋址的模式,到內部的寄存器排列模式是一摸一樣的。這樣就理解了Altera的那句使用Dynamic更加便捷的原因了。
有代碼
IORD_32DIRECT(BASE,0) //得到第一組2個16bit 4個寄存器(0-3)數據
IORD_32DIRECT(BASE,4) //得到第二組2個16bit 4個寄存器(4-7)數據
同樣如果要單獨讀取某一個16bit數據(2個寄存器),那麼就是用提供的API
IORD_16DIRECT(BASE,0) //得到外設地址0x00上的1個16bit 2個寄存器(0-1)數據
IORD_16DIRECT(BASE,2) //得到外設地址0x01上的1個16bit 2個寄存器(2-3)數據
解釋了上面引用的代碼IORD_16DIRECT(基地址、地址偏移量),地址偏移量 = 寄存器編號*2
這裏的2
是如何來的。
總結起來就是這樣:
無論外部設備上的地址或者數據寬度如何變化,我(master)從AvalonMM總線上讀取過來的數據都是一片連續的由8bit寄存器組成的內存空間,具體表示的數據是多少位的,通過3種不同的API(8DIRECT、16DIRECT、32DIRECT)來去讀取或者截取就好了,只需要計算好響應的寄存器變量下表就完事兒。
32bit 和64 bit
這樣32bit和64bit,甚至更多,也就很好理解了。這裏面唯獨有一個特殊的就是32bit,因爲32bit是和master一樣的數據寬度,實際上無論是原來的靜態尋址Native模式還是Dynamic動態模式都無所謂了,可以採用原來的Native模式下的APIIORD(BASE, REGNUM)
,主意,這裏的REGNUM看樣子說的是寄存器,實際上這裏的寄存器是32bit的,也就是說是實際寄存器的4倍!!!就是因爲很容易混淆,所以我個人極力不推薦採用原始的API。
尾巴
最後附一個官方的新圖
實在不想吐槽官方,給的圖實在是看的不是通透,注意第二列 是Access,表示的是Master向Avalon MM總線第幾次訪問的次數!!!不是表示的偏移量!!!這個圖的意思就是如果Slave是8bit的數據寬度,那就訪問4次,得到全部32bit數據,如果是16bit,就訪問2次…根本不是表示數據地址排列的,也沒法指導怎麼寫API。