S3c2410軟件調試總結(一)
我的硬件平臺主要是 S3c2410 + FPGA(cyclone EP1C6),出于成本的考慮,我買了一塊2410的核心板,然后自己畫了一塊底板,主要的模塊有:
S3c2410 ARM920 CORE RISC CPU
EP1C6 Altera cyclone series Fpga
AT89S52 atmel 51
RTL8019as 10M.network device
Sdram x2 total: 64M byte
K9F5608 Nand flash 32M byte
AM29LV160D x2 NOR flash total: 4M byte
64LV25616 SRAM 512K byte
UDA1341 IIS Interface
24C256 EEPROM
USB Host 1, Dev 1
SD interface
UART x2
ADS下C語言的入口方式和ROM鏡像文件的生成
這部分介紹下ADS下如何生成可以運行的ROM鏡像文件,我們知道當程序下載到flash中運行的時候,對于RW、ZI數據就存在著兩個環境,一個load環境,一個是exec環境,有時候由于速度的需要RO數據也要重新加載,那么對RO數據也是有兩個環境。編譯器產生ROM鏡像文件時候,這三塊數據的存放依次為RO、RW、ZI,并且地址空間時連續的。但是到了運行的時候,RW數據必須被拷貝到SDRAM(SRAM)中以支持讀寫,這就是我們所謂的運行環境。那么就要有一段代碼去完成這個任務,在本章中我們介紹如何生成這段代碼。
玩過2410的朋友都知道2410初始化代碼中有一段搬運RW和ZI初始化的代碼,沒錯,它確實能夠在一定程度上完成上面所說的任務,只要我們在生成二進制可執行代碼的時候在編譯器鏈接項的地方填寫正確的RO&RW地址,(比如RO = 0, RW = 0x30000000), 那么將程序下到 NOR flash的零地址并從nor flash啟動,啟動代碼會將RW&ZI數據弄到0x30000000,程序就能跑起來了。
但是各位有沒有想過,怎么把RO代碼弄到SDRAM中(有時候這是必須的,比方后面我將提到用nor flash的bootloader燒寫nor flash)?如果直接設RO=0x30000000,那么這段代碼下載到0地址肯定跑不起來,除非是ROPI,這個要求就高了。這里我們有必要從介紹ADS中規定的C語言入口開始,ADS中從初始化匯編代碼跳到main函數有兩種方式,main和__main:
1,在__main入口的模式下,匯編代碼的指令為 b __main, 編譯器在跳轉到main之前還要作一系列的工作,這其中就包括對運行環境的初始化,在<ADS COMPILE GUIDE>中提到: copies nonroot(RO&RW) execution regions from load addr to exec addr, and Zeros ZI region. 借助編譯器,我們就可以定義更為復雜的運行環境,這里要用到scatter文件(.scf),比如我們要的目標運行環境是:將啟動代碼以外的所有代碼都 拷貝到SDRAM的初始地址中運行,比且把RW段設在0x30800000,那么對應的scf文件如下:
FLASH 0x0 0x200000
{
EXEC1 0x0 0x200000
{
2410init.o(Init, +First)
__main.o(+RO) ; copy code
* (Region$$Table) ; RO/RW addresses to copy
* (ZISection$$Table) ; ZI addresses to zero
}
EXEC2 0x30000000 0x00800000
{
*(+RO)
}
SDRAM 0x30800000 0x00800000
{
*(+RW,+ZI)
}
}
;Sections named Region$$Table and ZISection$$Table which contain the addresses of the code/data to be copied.
當然,在這種模式下,有些入口函數必須自己重定義,比如__user_initial_stackheap,具體參見ADS文檔。
2, main入口模式即簡單的跳轉,這里起始不用“main”這個名字也無所謂。那么編譯器不會作任何的初始化,所有運行環境的建立都要* 我們自己,這就是大家看到的那段搬運代碼存在的理由。但是它實現一些簡單的運行環境是可取的,如果用scf定義的復雜環境,雖然我 相信是可以做到的,但是可能會比較麻煩。我還沒深究。
另外,這里提一下semihost,因為我們在看ADS的東西的時候經常出現這個詞,我也一直受其困擾。這里我簡單說一下自己的見解,semihost 僅僅是一種調試手段,它的機理就是利用MULTI_IDE等工具捕捉目標環境運行過程中產生的值為0x123456的SWI中斷,然后向上位機的ADS 軟件發送對應的調試信息。對于我們最后的應用代碼來說,都是nonsemihost類型的。如果我們在調試中使用semihost,那么只要在最后重定義 ADS中的一些使用到的庫函數(比如fputc),代碼就可以從semihost向nonsemihost的類型轉變。不過到目前為止,我還沒體會到semihost的威力。
2410啟動代碼分析
這一章主要對目前廣泛流行的2410啟動代碼進行分析:S3C2410的初始化代碼主要涉及到對系統主要模塊的配置、運行環境的建立、系統時鐘、MMU等模塊的配置,下面按執行順序依次都各個部分進行分析:
程序入口:(ResetHandler)
在程序一開始,首先進行的一些操作主要保證初始化程序能夠順利的運行, 因此主要包括關閉WDT、中斷,配置鎖相環等。
配置memory接口
memory接口是確保數據訪問正確的基本保障,此處主要配置SFR寄存器中0x48000000開始的memory接口寄存器組, 確保每個bank的位寬、訪問類型(waitable)以及時序參數正確。如果沒有特別的要求,一般來說時序參數使用默認值即可。
初始化堆棧
ARM有6種運行模式,必須為每一種模式提供獨立的堆?臻g,在堆棧設置之前是不能進行C函數的調用的。ARM的堆棧模式 是從高地址遞減的,我的所有代碼統一將堆棧的首地址設在0x33ff8000處,往低依次為FIQ、IRQ、Abort、Undef、SVC,其中
SVC和User模式不予區分。堆棧大小一般可在頭文件或者當前文件中修改。
運行空間的初始化
這段代碼主要完成兩個功能,一是將RW數據搬運到RW空間(我們生成ROM鏡像時,RW數據是跟在RO數據之后的),二是 初始化ZI數據段。當然,這段代碼存在的前提是代碼的運行環境只是標準的兩段式:一段RO空間和一段RW空間;并且在C程序
入口時沒有調用編譯器的鏈接庫(__main)。后者已經提供相應的功能,并且支持更加復雜的運行環境定義(使用SCF文件),
(關于這一點,我在介紹ADS中C代碼的啟動模式時已經詳細介紹)。
__rt_lib_init
在ADS1.2的環境中,如果在C入口沒有調用編譯器的鏈接庫(__main),那么在C程序一開始要調用該函數以初始化運行時的函數庫,以保證對ADS提供的某些庫函數能夠正常調用。從這個函數開始,我們已經在C語言環境下了。
MMU初始化
文章來源于領測軟件測試網 http://www.kjueaiud.com/