久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4455|回復: 0
打印 上一主題 下一主題
收起左側

ARM2440的啟動模式

[復制鏈接]
跳轉到指定樓層
樓主
ID:83710 發表于 2015-6-26 23:04 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
研究arm也有2個月了,現在才感覺理解了arm在Nand flash模式下的啟動過程,現在來這里記錄下來以表達我無比喜悅的心情。閑話少說,趁著還沒有忘記學習過程中的感受,直接進入正題。

大家都知道,arm在Nand flash啟動模式下啟動時系統會將Nand flash中的前4KB代碼拷貝到SRAM(也就是Steppingstone中),由SRAM配置中斷向量表和完成Nand flash訪問的必要初始化,然后將Nand flash中的全部程序代碼拷貝到SDRAM中,最后由SRAM跳轉到SDRAM,然后程序就正常執行了,這一過程看上去很簡單,但是真正理解這一過程還是不簡單的,盡管這樣,還是想告訴大家仔細理解還是比較容易理解這個過程的。如果您是ADS用戶,你省去了很多麻煩,但我不確定你省去的這些麻煩是否值得,這里介紹的是一種麻煩的方式,linux下的led程序。
代碼Head.s
  • .extern main
  • .text
  • .global _start
  • _start:
  •     b reset
  • reset:
  •     ldr sp,=4096
  •     bl disable_watch_dog
  •     bl clock_init
  •     bl memsetup
  •     bl copy_steppingstone_to_sdram
  •     ldr pc,=on_sdram
  • on_sdram:
  •     msr cpsr_c,#0xdf
  •     ldr sp,=0x34000000
  •     ldr lr,=halt_loop
  •     ldr pc,=Main
  • halt_loop:
  •     b halt_loop


我認為,最需要理解的就是這段代碼了。先簡單的解釋下這段代碼。
(1)由于arm執行reset之后pc會被清零,也就是reset中斷的中斷入口地址,因此,第一條指令就是b reset,跳轉到reset中斷處理函數。
(2)由于這里硬件配置都是C語言來完成的,而且我們的初始代碼比較小,完全不會超出4KB,因此可以在SRAM使用堆棧,故將SP設置為4096,以提供C運行環境
(3)接下來的3個bl分別完成了關閉看門夠定時器,配置時鐘信號和存儲器配置的工作,第四個bl是將SRAM的4KB空間內的代碼拷貝到了SDRAM中。
(4)接下來的ldr句將pc賦值為on_sdram的地址,實現了從SRAM到SDRAM的跳轉(下面會講為什么)
(5)on_sdram中切換到了了系統模式然后分配了系統模式堆棧,將鏈接寄存器設置為halt_loop然后就跳轉到了SDRAM中的Main
上面的解釋只是大體上說明了代碼的意思,但是初學者總會有個疑問就是為什么ldr pc,=on_sdram就實現了從SRAM到SDRAM的跳轉呢?我被這個問題困擾了很長時間,到今天才想明白了這個問題,問題的關鍵就是相對跳轉和絕對跳轉的問題。為了說明這個問題我先解釋一下bl指令跟ldr指令在執行過程中的區別。
B指令是相對跳轉指令,B 指令是最簡單的跳轉指令。一旦遇到一個 B 指令,ARM 處理器將立即跳轉到給定的目標地址,從那里繼續執行。注意存儲在跳轉指令中的實際值是相對當前PC 值的一個偏移量,而不是一個絕對地址,它的值由匯編器來計算(參考尋址方式中的相對尋址)。它是 24 位有符號數,左移兩位后有符號擴展為 32 位,表示的有效偏移為 26 位(前后32MB 的地址空間),同樣的,BL、BX都是相對跳轉。
LDR偽指令是將第二操作直接賦值給第一操作數,當執行ldr pc,=Main時是將Main的絕對地址賦值給了PC。
好了,知道這兩個指令的區別之后我們來看代碼是如何實現的從SRAM到SDRAM的跳轉,首先需要指出,2440的開發板有SRAM和SDRAM,SRAM是從地址0x00000000開始的4KB內存空間,SDRAM是從0x30000000開始的64M空間。
無論用ADS編譯還是用arm-linux-gcc編譯都會將代碼鏈接到0x30000000以后(也就是SDRAM中),ADS用戶可以通過查看ADS的工程配置,其中有項配置是RO起始地址是0x30000000,linux用戶在鏈接時需要用-T指定代碼的其實地址為0x30000000。
根據編譯原理,在鏈接階段程序中函數的地址就已經確定了,也就是說函數的實際地址都在0x30000000之后,而程序的入口函數也就是這里的_start的地址就是0x300000000,其他函數都會大于這個數。
但是由于arm上電后系統會將Nand flash的前4KB代碼拷貝到SRAM中,也就是_start函數開始的4KB指令將被拷貝到SRAM中執行,根據上例,在0x00000000處執行的指令就是“b reset”,由于b是相對跳轉,是在當前pc值的基礎上加減某個數而跳轉到將要執行的代碼處,因此,pc加減該數之后將到達reset函數的位置,故reset函數不能寫到4KB之外的空間中,否則arm的啟動將會失敗,同樣的,接下來的幾個bl都是執行的相對跳轉,所以都相對當前pc進行的跳轉,由于Nand flash總共只有64M的空間,所以相對跳轉是不可能會跳轉到SDRAM的,因為跳轉到SDRAM至少要發生0x30000000的跳轉,而這個相對位移遠遠大于64M。
而ldr pc,=Main是將Main函數的實際地址賦值給pc,而Main的實際地址是在0x30000000之后,這樣,就從SRAM跳轉到了SDRAM。
由于這個過程設計到了硬件格局和編譯原理,所以對一般人來講,理解起來確實比較困難,而且受本人水平限制,很多地方只能說是只可意會不可言傳,如果誤導了大家請大家諒解。當然如果看到這里還不能理解arm的啟動過程可以聯系QQ630905224來討論這個問題。下面是相關的其他代碼,我附在這里,2440addr.h沒有貼出,由于我也是使用arm自帶示例程序中的代碼,而且代碼有四千多行,多數地址是沒有用到的,如果有人需要就聯系我的QQ吧。其他的代碼如下
代碼Init.s
  • #include "2440addr.h"
  • void disable_watch_dog(void);
  • void clock_init(void);
  • void memsetup(void);
  • void copy_steppingstone_to_sdram(void);
  • void inituart(void);
  • void disable_watch_dog(void)
  • {
  •     rWTCON = 0;
  • }
  • void clock_init(void)
  • {
  •     rCLKDIVN  = 0x03;
  •     /*
  •      *如果HDIVN非0,CPU的總線模式應該從
  •      *“fast bus mode”變為“asynchronous
  •      *bus mode”
  •      */
  •     __asm__(
  •             "mrc    p15, 0, r1, c1, c0, 0\n"
  •             "orr    r1, r1, #0xc0000000\n"
  •             "mcr    p15, 0, r1, c1, c0, 0\n"
  •            );
  •     rMPLLCON = (92<<12)|(1<<4)|(2);
  •     //rMPLLCON =  ((0x5c<<12)|(0x01<<4)|(0x02));
  • }
  • void memsetup(void)
  • {
  •     volatile unsigned long *p = (volatile unsigned long *)0x48000000;
  •     /* 這個函數之所以這樣賦值,而不是像前面的實驗(比如mmu實驗)那樣將配置值
  •      * 寫在數組中,是因為要生成”位置無關的代碼”,使得這個函數可以在被復制到
  •      * SDRAM之前就可以在steppingstone中運行
  •      */
  •     /* 存儲控制器13個寄存器的值 */
  •     p[0] = 0x22011110;     //BWSCON
  •     p[1] = 0x00000700;     //BANKCON0
  •     p[2] = 0x00000700;     //BANKCON1
  •     p[3] = 0x00000700;     //BANKCON2
  •     p[4] = 0x00000700;     //BANKCON3
  •     p[5] = 0x00000700;     //BANKCON4
  •     p[6] = 0x00000700;     //BANKCON5
  •     p[7] = 0x00018005;     //BANKCON6
  •     p[8] = 0x00018005;     //BANKCON7
  •     /* REFRESH,
  •      * HCLK=12MHz:  0x008C07A3,
  •      * HCLK=100MHz: 0x008C04F4
  •      */
  •     p[9]  = 0x008C04F4;
  •     p[10] = 0x000000B1;     //BANKSIZE
  •     p[11] = 0x00000030;     //MRSRB6
  •     p[12] = 0x00000030;     //MRSRB7
  • }
  • void copy_steppingstone_to_sdram(void)
  • {
  •     unsigned int *pdwSrc  = (unsigned int *)0;
  •     unsigned int *pdwDest = (unsigned int *)0x30000000;
  •     while (pdwSrc < (unsigned int *)4096)
  •     {
  •         *pdwDest = *pdwSrc;
  •         pdwDest++;
  •         pdwSrc++;
  •     }
  • }

=======================================================================
一般而言,一個程序包括只讀的代碼段和可讀寫的數據段。在ARM的集成開發環境中,只讀的代碼段和常量被稱作RO段(ReadOnly)可讀寫的全局變量和靜態變量被稱作RW段(ReadWrite)RW段中要被初始化為零的變量被稱為ZI段(ZeroInit)。對于嵌入式系統而言,程序映象都是存儲在Flash存儲器等一些非易失性器件中的,而在運行時,程序中的RW段必須重新裝載到可讀寫的RAM中。這就涉及到程序的加載時域和運行時域。簡單來說,程序的加載時域就是指程序燒入Flash中的狀態,運行時域是指程序執行時的狀態對于比較簡單的情況,可以在ADS集成開發環境的ARM LINKER選項中指定RO BASE和RW BASE,告知連接器RO和RW的連接基地址對于復雜情況,如RO段被分成幾部分并映射到存儲空間的多個地方時,需要創建一個稱為“分布裝載描述文件”的文本文件,通知連接器把程序的某一部分連接在存儲器的某個地址空間。需要指出的是,分布裝載描述文件中的定義要按照系統重定向后的存儲器分布情況進行。在引導程序完成初始化的任務后,應該把主程序轉移到RAM中去運行,以加快系統的運行速度

            什么是arm的映像文件,arm映像文件其實就是可執行文件,包括bin或hex兩種格式,可以直接燒到rom里執行在axd調試過程中,我們調試的是axf文件,其實這也是一種映像文件,它只是在bin文件中加了一個文件頭和一些調試信息映像文件一般由域組成,域最多由三個輸出段組成(RO,RW,ZI)組成,輸出段又由輸入段組成。所謂域,指的就是整個bin映像文件所處在的區域,它又分為加載域和運行域加載域就是映像文件被靜態存放的工作區域,一般來說flash里的 整個bin文件所在的地址空間就是加載域,當然在程序一般都不會放在 flash里執行,一般都會搬到sdram里運行工作,它們在被搬到sdram里工作所處的地址空間就是運行域
        我們輸入的代碼,一般有代碼部分和數據部分,這就是所謂的輸入段,經過編譯后就變成了bin文件中ro段和rw段,還有所謂的zi段,這就是輸出段對于加載域中的輸出段,一般來說ro段后面緊跟著rw段,rw段后面緊跟著zi段。在運行域中這些輸出段并不連續,但rw和zi一定是連著的。zi段和rw段中的數據其實可以是rw屬性。

                | Image
RO

Base| |Image
RO

Limit| |Image
RW

Base| |Image
ZI

Base| |Image
ZI

Limit|這幾個變量是編譯器通知的,我們在 makefile文件中可以看到它們的值。它們指示了在運行域中各個輸出段所處的地址空間。
| Image
RO

Base| 就是ro段在運行域中的起始地址,|Image
RO

Limit| 是ro段在運行域中的截止地址。其它依次類推。我們可以在linker的output中指定,在 simple模式中,ro base對應的就是| Image
RO

Base|,rw base 對應的是|Image
RW

Base|,由于rw和zi相連,|Image
ZI

Base| 就等于|Image
ZI

limit| .其它的值都是編譯器自動計算出來的。


            下面是2410啟動代碼的搬運部分,我給出注釋
            BaseOfROM DCD |Image
RO

Base|
            TopOfROM DCD |Image
RO

Limit|
            BaseOfBSS DCD |Image
RW

Base|
            BaseOfZero DCD |Image
ZI

Base|
            EndOfBSS DCD |Image
ZI

Limit|
            adr r0, ResetEntry;    ResetEntry是復位運行時域的起始地址,在boot nand中一般是0
            ldr r2, BaseOfROM;
            cmp r0, r2
            ldreq r0, TopOfROM;TopOfROM=0x30001de0,代碼段地址的結束
            beq InitRam
            ldr r3, TopOfROM
            ;part 1,通過比較,將ro搬到sdram里,搬到的目的地址從 | Image
RO

Base| 開始,到|Image
RO

Limit|結束
            
            0
            ldmia r0!, {r4-r7}
            stmia r2!, {r4-r7}
            cmp r2, r3
            bcc %B0;
            
            ;part 2,搬rw段到sdram,目的地址從|Image
RW

Base| 開始,到|Image
ZI

Base|結束
            sub r2, r2, r3;r2=0
            sub r0, r0, r2   
            InitRam ;carry rw to baseofBSS
            ldr r2, BaseOfBSS ;TopOfROM=0x30001de0,baseofrw
            ldr r3, BaseOfZero ;BaseOfZero=0x30001de0
            0
            cmp r2, r3
            ldrcc r1, [r0], #4
            strcc r1, [r2], #4
            bcc %B0
            ;part 3,將sdram zi初始化為0,地址從|Image
ZI

Base|到|Image
ZI

Limit|
            mov r0, #0;init 0
            ldr r3, EndOfBSS;EndOfBSS=30001e40
            1
            cmp r2, r3
            strcc r0, [r2], #4
            bcc %B1



------------------------------------------------------------

一 概述

Scatter file (分散加載描述文件)用于armlink的輸入參數,他指定映像文件內部各區域的download與運行時位置。Armlink將會根據scatter file生成一些區域相關的符號,他們是全局的供用戶建立運行時環境時使用。(注意:當使用了scatter file 時將不會生成以下符號 Image
RW

Base, Image
RW

Limit, Image
RO

Base, Image
RO

Limit, Image
ZI

Base, and Image
ZI

Limit)


二 什么時候使用scatter file

       當然首要的條件是你在利用ADS進行項目開發,下面我們看看更具體的一些情況。
1 存在復雜的地址映射:例如代碼和數據需要分開放在在多個區域。
2 存在多種存儲器類型:例如包含 Flash,ROM,SDRAM,快速SRAM。我們根據代碼與數據的特性把他們放在不同的存儲器中,比如中斷處理部分放在快速SRAM內部來提高響應速度,而把不常用到的代碼放到速度比較慢的Flash內。
3 函數的地址固定定位:可以利用Scatter file實現把某個函數放在固定地址,而不管其應用程序是否已經改變或重新編譯。
4 利用符號確定堆與堆棧
5 內存映射的IO:采用scatter file可以實現把某個數據段放在精確的地指處。
因此對于嵌入式系統來說scatter file是必不可少的,因為嵌入式系統采用了ROM,RAM,和內存映射的IO。


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产精品777一区二区 | 国产91网址 | 国产又爽又黄的视频 | 亚洲欧美一区二区三区视频 | 黄色a视频 | 日韩精品国产精品 | 亚洲日韩中文字幕一区 | 国产精品久久国产精品 | www.色婷婷| 中文成人无字幕乱码精品 | 色悠悠久| 天堂一区二区三区 | 精品一区二区三区在线观看国产 | 国产91久久精品一区二区 | 亚洲精品在线播放 | 国产2区| 亚洲精品久久久久久宅男 | 亚洲一区二区在线 | 国产91 在线播放 | 91久久综合 | 中文字幕亚洲视频 | 狠狠的操| 亚洲h视频| 黄 色 毛片免费 | 国产午夜一级 | 亚洲日韩中文字幕一区 | 国产精品欧美一区二区三区不卡 | 亚洲精品在线视频 | 国产做a爱片久久毛片 | 欧美啪啪网站 | 精品久久久久久红码专区 | 国产中文字幕亚洲 | 久在线视频| 九九伊人sl水蜜桃色推荐 | 亚洲永久入口 | 中文字幕在线免费视频 | 日本一区二区三区四区 | 国产一区二区精品在线 | 精品国产免费一区二区三区五区 | 国产综合在线视频 | 国产性生活一级片 |