編寫了一段彙編,理論上是拷貝到sdram上面運作的,移植在思考這樣的一個問題,闆子的外接ram在沒有初始化之前是不能使用的,jlink是不能幫我們拷貝程式到sdram的,同時自己寫的隻是一個小小的程式,沒有必要大動幹戈用uboot,這樣的引導程式拷貝我們的小程式到sdram上面去,因而自己實作的拷貝,因為我的闆子外部ram的位址是0x30000000,這個位址必須要初始化之後才能使用。
大概的思路是這樣的,寫一個小程式,包含了拷貝動作的代碼,和需要拷貝的程式,一起燒寫到我們的nand flash(nand flash)啟動,注意要小于4K,然後我們的把需要執行的小程式拷貝到sdram上面去。
代碼如下。
.equ MEM_CTL_BASE,0x48000000
.equ SDRAM_BASE,0x30000000
.text
.global _start
_start:
bl disable_watch_dog @關閉watchdog
bl memsetup @設定儲存控制器
bl copy_steppingstone_to_sdrame @複制代碼到sdram
ldr pc,=on_sdram
on_sdram:
ldr sp,=0x34000000 @設定棧
bl main
halt_loop:
b halt_loop
……………………(後面的省略)
注意我們的拷貝是拷貝從0x00開始的4k的片内ram,就是自己把自己拷貝到SDRAM上面去,然後跳轉到SDRAM上面運作。
也就是說,同樣的程式,放在4k ram執行了一次,然後放在0x30000000又執行了一次,我對執行的正确度表示懷疑,因為,最起碼,放的地方不同,跳轉的地方也不同,程式還能正常運作嗎?
注意,在ARM指令中,一般的子函數的調用都是相對的跳轉,也就是說,我們的所有的代碼就是一大塊,這一塊無論你放在什麼地方,隻要你的PC隻想程式的開始地方,他就會一條一條的執行,碰到跳轉的時候,自動的找到目前位置的子函數的位置,這是怎麼實作的呢?——相對跳轉。
例如:
bl disable_watch_dog
在編譯的時候
錯誤的了解:首先編譯器計算出disable_watch_dog的位址,然後跳轉到上面運作,這樣顯然,我的程式編譯之後就不會再去編譯,當時程式放在不同的位址上面就不能運作了。
正确的了解:bl disable_watch_dog,編譯器計算目前的PC值,然後計算處目前的PC值和disable_watch_dog之間的距離,然後跳轉的位置是pc+offset,這個offset偏移量,不管你的程式放在哪裡都是不會變的,因而程式可以到處搬運。隻是要注意,這個offset隻是在正負32M範圍之内的。
是以說,即使我的程式最開始是準備到0x30000000上運作的,隻要裡面使用相對跳轉的指令,我把程式拷貝到0x0000照樣能夠運作。
然後在看一下絕對的跳轉,絕對的跳轉就是直接給pc指派,例如:
ldr pc,=0x34000000
也許,如果考慮的比較深入,有的人會問,既然這樣我們編譯之後連接配接還要指明一個-Ttext有什麼用,反正放在什麼地方執行都是一樣的,真的要用到絕對跳轉,注意一下就可以了。
使用-T,就是給每一條指令添加一個屬性,就是運作的位址,這個可以在elf檔案中看出來,這個運作的位址在相對跳轉的時候沒有什麼大用,但是在絕對跳轉的時候,你不可能記住或者運算某一個函數的位址,必須要借助lable,然後
ldr pc,=on_sdram
說的簡單一點,相對跳轉,要使用lable,然後計算lable與目前pc的差距,就可跳轉。
絕對跳轉的時候,首先可以直接指明一個值,其次,我如果想用lable呢,這個lable不是想放在什麼地方都可以的,于是就必須知道程式運作的地方,程式運作的地方并不是程式隻能在那裡運作,而是程式最終還是要到那裡去的,添加這個位址,便于我們的編譯器知道絕對跳轉的時候該如何跳轉。
不知道說的清楚不,個人了解,僅供參考。