1. 程式人生 > >32位ARM暫存器是如何只傳遞8位、16位資料的——由uboot nand 操作想到的

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