32位ARM暫存器是如何只傳遞8位、16位資料的——由uboot nand 操作想到的
uboot中可以通過指令對nand操作,以AM3359為例,假設讀取CS0連線的nand,讀取地址0處的資料:
指令暫存器地址 5000007c
地址暫存器地址 50000080
資料暫存器地址 50000084
mw memory write
md memory read
mw.b 寫入一個位元組 mw.w 寫2個位元組 mw.l 寫4個位元組
流程:寫入復位指令->寫入指令0->寫入地址0->寫入指令30->讀取資料
mw.b 5000007c ff //復位指令
mw.b 5000007c 0 //指令暫存器寫入0
mw.b 50000080 0 //寫入地址0,分5次寫入
mw.b 50000080 0
mw.b 50000080 0
mw.b 50000080 0
mw.b 50000080 0
mw.b 5000007c 30 //寫入指令0x30
md.b 50000084 1 //讀取資料暫存器中的資料
我們看到這裡全部使用的mw.b,也就是寫入一個位元組,暫存器是一個32位的暫存器,真的是寫入一個位元組就
傳送一個位元組,而不是傳送4個位元組?經過多次試驗,發現確實如此。那是如何做到的呢?
當你讀取這幾個暫存器的時候讀到全是ffffffff,也就是說寫入的資料傳送完之後立馬變為ff。那我們把上面的
mw.b 50000080 0往地址寫入資料,寫4次試試行不行,發現讀不到nand的資料。但是我把5次寫入地址改為:
mw.b 50000080 0
mw.l 50000080 0
發現可以正確讀到資料了,說明mw.l 50000080 0使32暫存器全為0後,地址暫存器向nand傳送了4個位元組的0。
同樣改為:
mw.b 50000080 0
mw.w 50000080 0
mw.w 50000080 0
也是成功的。
那md.b對應的uboot中的語句是 *((u_char *)addr) = (u_char)writeval,這句C語言轉換為組合語言就是
STRB R0,[R1]
R0儲存的是0x00000000,R1儲存的是0x50000080。STRB就是把R0的低8位00儲存到0x50000080暫存器
的低8位,高24位保持不變
同樣mw.w和mw.l也對應:
md.b *((u_char *)addr) = (u_char)writeval
STRB R0,[R1] 傳送低8位
md.w*((ushort *)addr) = (ushort)writevalSTRH R0,[R1] 傳送低16位
md.l*((ulong *)addr) = (ulong )writevalSTR R0,[R1] 傳送32位
GPMC的這三個指令、地址、資料暫存器還有一個比較特殊的功能,那就是隻向外傳送暫存器中被重新賦值的位。
也就是說,如果只改變低8位,那麼它只發送一個位元組;如果改變了低16位,那麼將分兩次傳送兩個自己;
32位全改變的話,將分4次傳送四個位元組。
另一類常見的暫存器一些配置暫存器,寫入資料之後暫存器值會保持。這樣的話我們也可以通過一個暫存器來
驗證mw.b w l的實際效果。
以0x50000090暫存器為例:
md.l 50000090 1
mw.b 50000090 55
md.l 50000090 1
mw.w 50000090 3333
md.l 50000090 1
mw.l 50000090 55555555
md.l 50000090 1