新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > S3C2440 2440init.s分析第二篇(一)

S3C2440 2440init.s分析第二篇(一)

作者: 時(shí)間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
S3C2440 2440init.s分析第二篇(一)
;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
; Configure memory, ISR ,stacks
; Initialize C-variables
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
;=========================================

;首先,啟動代碼定義了一些常量
GET option.inc
GET memcfg.inc
GET 2440addr.inc

BIT_SELFREFRESH EQU (1<<22)

;處理器模式常量
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK EQU 0x1f
NOINT EQU 0xc0

;定義處理器各模式下堆棧地址常量
UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~
SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~

;檢查在tasm.exe里是否設(shè)置了采用THUMB(16位)代碼(armasm -16 ...@ADS 1.0)
GBLL THUMBCODE ;定義THUMBCODE全局變量
[ {CONFIG} = 16 ;如果發(fā)現(xiàn)是才用16位代碼的話
THUMBCODE SETL {TRUE} ;把THUMBCODE設(shè)置為TURE
CODE32 ;把處理器從新設(shè)置成為ARM模式
| ;如果處理器現(xiàn)在就是ARM模式
THUMBCODE SETL {FALSE} ;把THUMBCODE設(shè)置為FALSE就行了
]

MACRO ;一個(gè)根據(jù)THUMBCODE把PC寄存的值保存到LR的宏
MOV_PC_LR
[ THUMBCODE
bx lr ;在ARM模式中要使用BX指令轉(zhuǎn)跳到THUMB指令,并轉(zhuǎn)換模式
|
mov pc,lr ;如果目標(biāo)地址也是ARM指令的話就采用這種方式
]
MEND

MACRO ;和上面的宏一樣,只是多了一個(gè)相等的條件
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND

;=======================================================================================
;下面這個(gè)宏是用于第一次查表過程的實(shí)現(xiàn)中斷向量的重定向,如果你比較細(xì)心的話就是發(fā)現(xiàn)
;在_ISR_STARTADDRESS=0x33FF_FF00里定義的第一級中斷向量表是采用型如Handle***的方式的.
;而在程序的ENTRY處(程序開始處)采用的是b Handler***的方式.
;在這里Handler***就是通過HANDLER這個(gè)宏和Handle***進(jìn)立聯(lián)系的.
;這種方式的優(yōu)點(diǎn)就是正真定義的向量數(shù)據(jù)在內(nèi)存空間里,而不是在ENTRY處的ROM(FLASH)空間里,
;這樣,我們就可以在程序里靈活的改動向量的數(shù)據(jù)了.
;========================================================================================

MACRO
$HandlerLabel HANDLER $HandleLabel

$HandlerLabel
sub sp,sp,#4 ;減少sp(用于存放轉(zhuǎn)跳地址)
stmfd sp!,{r0} ;把工作寄存器壓入棧(lr does not push because it return to original address)
ldr r0,=$HandleLabel;將HandleXXX的址址放入r0
ldr r0,[r0] ;把HandleXXX所指向的內(nèi)容(也就是中斷程序的入口)放入r0
str r0,[sp,#4] ;把中斷服務(wù)程序(ISR)壓入棧
ldmfd sp!,{r0,pc} ;用出棧的方式恢復(fù)r0的原值和為pc設(shè)定新值(也就完成了到ISR的轉(zhuǎn)跳)
MEND


;=========================================================================================
;在這里用IMPORT偽指令(和c語言的extren一樣)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...
;這些變量是通過ADS的工程設(shè)置里面設(shè)定的RO Base和RW Base設(shè)定的,
;最終由編譯腳本和連接程序?qū)氤绦?
;那為什么要引入這玩意呢,最簡單的用處是可以根據(jù)它們拷貝自已
;==========================================================================================
IMPORT |Image$$RO$$Base| ; ROM code(也就是代碼)的開始地址
IMPORT |Image$$RO$$Limit| ; ROM code的結(jié)束地址 (=ROM data的開始地址)
IMPORT |Image$$RW$$Base| ; 要初始化的RAM的開始地址
IMPORT |Image$$ZI$$Base| ; area(需要清零的RAM區(qū)域)的開始地址
IMPORT |Image$$ZI$$Limit| ; area的結(jié)束地址

;這里引入一些在其它文件中實(shí)現(xiàn)在函數(shù),包括為我們所熟知的main函數(shù)
IMPORT MMU_SetAsyncBusMode
IMPORT MMU_SetFastBusMode ;hzh

IMPORT Main ; The main entry of mon program

;從這里開始就是正真的代碼入口了!
AREA Init,CODE,READONLY ;這表明下面的是一個(gè)名為Init的代碼段

ENTRY ;定義程序的入口(調(diào)試用)

EXPORT __ENTRY ;導(dǎo)出符號_ENTRY,但在那用到就還沒查明
__ENTRY
ResetEntry
;1)The code, which converts to Big-endian, should be in little endian code.
;2)The following little endian code will be compiled in Big-Endian mode.
; The code byte order should be changed as the memory bus width.
;3)The pseudo instruction,DCD can not be used here because the linker generates error.
ASSERT :DEF:ENDIAN_CHANGE
[ ENDIAN_CHANGE ;下面是大小端的一個(gè)判斷,在Option.inc里已經(jīng)設(shè)為FALSE
ASSERT :DEF:ENTRY_BUS_WIDTH
[ ENTRY_BUS_WIDTH=32
b ChangeBigEndian ;DCD 0xea000007
]

[ ENTRY_BUS_WIDTH=16
andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
]

[ ENTRY_BUS_WIDTH=8
streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
]
|
b ResetHandler ;設(shè)成FALSE的話就來到這了,轉(zhuǎn)跳到復(fù)位程序入口
]
b HandlerUndef ;轉(zhuǎn)跳到Undefined mode程序入口
b HandlerSWI ;轉(zhuǎn)跳到SWI 中斷程序入口
b HandlerPabort ;轉(zhuǎn)跳到PAbort(指令異常)程序入口
b HandlerDabort ;轉(zhuǎn)跳到DAbort(數(shù)據(jù)異常)程序入口
b . ;保留
b HandlerIRQ ;轉(zhuǎn)跳到IRQ 中斷程序入口
b HandlerFIQ ;轉(zhuǎn)跳到FIQ 中斷程序入口

;@0x20
b EnterPWDN ; Must be @0x20.

;==================================================================================
;下面是改變大小端的程序,這里采用直接定義機(jī)器碼的方式,至說為什么這么做就得問三星了
;反正我們程序里這段代碼也不會去執(zhí)行,不用去管它
;==================================================================================
ChangeBigEndian
;@0x24
[ ENTRY_BUS_WIDTH=32
DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0
DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian
DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0
]
[ ENTRY_BUS_WIDTH=16
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
]
[ ENTRY_BUS_WIDTH=8
DCD 0x100f11ee
DCD 0x800080e3
DCD 0x100f01ee
]
DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both endian mode.
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
b ResetHandler

;如上所說,這里采用HANDLER宏去建立Hander***和Handle***之間的聯(lián)系
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort

;===================================================================================
;呵呵,來了來了.好戲來了,這一段程序就是用來進(jìn)行第二次查表的過程了.
;如果說第一次查表是由硬件來完成的,那這一次查表就是由軟件來實(shí)現(xiàn)的了.
;為什么要查兩次表??
;沒有辦法,ARM把所有的中斷都?xì)w納成一個(gè)IRQ中斷異常和一個(gè)FIRQ中斷異常
;第一次查表主要是查出是什么異常,可我們總要知道是這個(gè)中斷異常中的什么中斷呀!
;沒辦法了,再查一次表唄!
;===================================================================================
IsrIRQ
sub sp,sp,#4 ;給PC寄存器保留
stmfd sp!,{r8-r9} ;把r8-r9壓入棧

ldr r9,=INTOFFSET ;把INTOFFSET的地址裝入r9
ldr r9,[r9] ;把INTOFFSET的值裝入r9
ldr r8,=HandleEINT0 ;這就是我們第二個(gè)中斷向量表的入口的,先裝入r8
;===================================================================================
;哈哈,這查表方法夠好了吧,r8(入口)+index*4(別望了一條指令是4 bytes的喔),
;這不就是我們要找的那一項(xiàng)了嗎.找到了表項(xiàng),下一步做什么?肯定先裝入了!
;==================================================================================
add r8,r8,r9,lsl #2
ldr r8,[r8] ;裝入中斷服務(wù)程序的入口
str r8,[sp,#8] ;把入口也入棧,準(zhǔn)備用舊招
ldmfd sp!,{r8-r9,pc} ;施招,彈出棧,哈哈,順便把r8彈出到PC,O了,跳轉(zhuǎn)成功!


LTORG ;聲明文字池,因?yàn)槲覀冇昧薼dr偽指令


;==============================================================================
; ENTRY(好了,我們的CPU要在這復(fù)位了.)
;==============================================================================
ResetHandler
ldr r0,=WTCON ;1.關(guān)看門狗
ldr r1,=0x0
str r1,[r0]

ldr r0,=INTMSK
ldr r1,=0xffffffff ;2.關(guān)中斷
str r1,[r0]

ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;3.關(guān)子中斷
str r1,[r0]

[ {FALSE} ;4.得有些表示了,該點(diǎn)點(diǎn)LED燈了,不過被FALSE掉了.
;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
; Led_Display
ldr r0,=GPFCON
ldr r1,=0x5500
str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0x10
str r1,[r0]
]

;5.為了減少PLL的lock time, 調(diào)整LOCKTIME寄存器.
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]

[ PLL_ON_START ;6.下面就來設(shè)置PLL了,你的板快不快就看這了!!
; Added for confirm clock divide. for 2440.
; 設(shè)定Fclk:Hclk:Pclk
ldr r0,=CLKDIVN
ldr r1,=CLKDIV_VAL ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4,
str r1,[r0] ; 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.

;===============================================================================
;MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 都在4K代碼以上,
;如果你想你編譯出來的程序能在NAND上運(yùn)行的話,就不要在這調(diào)用這兩函數(shù)了.
;如果你不要求的話,你就用把.啥事沒有.
;為什么是4K,問三星吧,就提供4K的內(nèi)部SRAM,要是提供400K多好呀.
;好了,好了,4K就4K吧,不能用這兩函數(shù),自己寫還不行嗎,下面的代碼這這么來了,
;實(shí)現(xiàn)和上面兩函數(shù)一樣的功能.
;===============================================================================
; [ CLKDIV_VAL>1 ; 意思是 Fclk:Hclk 不是 1:1.
; bl MMU_SetAsyncBusMode
; |
; bl MMU_SetFastBusMode ; default value.
; ]

[ CLKDIV_VAL>1 ; 意思是 Fclk:Hclk 不是 1:1.
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
|
mrc p15,0,r0,c1,c0,0
bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
mcr p15,0,r0,c1,c0,0
]

;配置 UPLL
ldr r0,=UPLLCON
ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)
str r1,[r0]
nop ; Caution: After UPLL setting, at least 7-clocks
nop ; delay must be inserted for setting hardware be completed.
nop
nop
nop
nop
nop
;配置 MPLL 一定要使最后的頻率為16.9344MHz,不然你甭想用USB接口了,哈哈.
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)
str r1,[r0]
]

;檢查是否從SLEEP模式中恢復(fù)
ldr r1,=GSTATUS2
ldr r0,[r1]
tst r0,#0x2
;如果是從SLEEP模式中恢復(fù), 轉(zhuǎn)跳到SLEEP_WAKEUP.
bne WAKEUP_SLEEP

EXPORT StartPointAfterSleepWakeUp ;導(dǎo)出符號StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp

;===============================================================================
;設(shè)置內(nèi)存控制器等寄存器的值,因?yàn)檫@些寄存器是連續(xù)排列的,所以采用如下辦法對這些
;寄存器進(jìn)行連續(xù)設(shè)置.其中用到了SMRDATA的數(shù)據(jù),這在代碼后面有定義
;===============================================================================
;ldr r0,=SMRDATA
adrl r0, SMRDATA ;be careful!, hzh
ldr r1,=BWSCON ;BWSCON 地址
add r2, r0, #52 ;SMRDATA數(shù)據(jù)的結(jié)束地址,共有52字節(jié)的數(shù)據(jù)

0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0

;================================================================================
;如果 EINT0 產(chǎn)生(這中斷就是我們按鍵產(chǎn)生的), 就清除SDRAM ,不過好像沒人會在這個(gè)時(shí)候按
;================================================================================
; check if EIN0 button is pressed

ldr r0,=GPFCON
ldr r1,=0x0
str r1,[r0]
ldr r0,=GPFUP
ldr r1,=0xff
str r1,[r0]

ldr r1,=GPFDAT
ldr r0,[r1]
bic r0,r0,#(0x1e<<1) ; bit clear
tst r0,#0x1
bne %F1 ;如果沒有按,就跳到后面的1標(biāo)號處



; 這就是清零內(nèi)存的代碼

ldr r0,=GPFCON
ldr r1,=0x55aa
str r1,[r0]
; ldr r0,=GPFUP
; ldr r1,=0xff
; str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0x0
str r1,[r0] ;LED=****

mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0

ldr r9,=0x4000000 ;64MB
ldr r0,=0x30000000
0
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0

;到這就結(jié)束了.

1
bl InitStacks ;初始化堆棧
;bl Led_Test ;又是LED,注掉了

;=======================================================================
; 哈哈,下面又有看頭了,這個(gè)初始化程序好像被名曰hzh的高手改過
; 能在NOR NAND 還有內(nèi)存中運(yùn)行,當(dāng)然了,在內(nèi)存中運(yùn)行最簡單了.
; 在NOR NAND中運(yùn)行的話都要先把自己拷到內(nèi)存中.
; 此外,還記得上面提到的|Image$$RO$$Base|,|Image$$RO$$Limit|...嗎?
; 這就是拷貝的依據(jù)了!!!
;=========================================================================
ldr r0, =BWSCON
ldr r0, [r0]
ands r0, r0, #6 ;OM[1:0] != 0, 從NOR FLash啟動或直接在內(nèi)存運(yùn)行
bne copy_proc_beg ;不讀取NAND FLASH
adr r0, ResetEntry ;OM[1:0] == 0, 否則,為從NAND FLash啟動
cmp r0, #0 ;再比較入口是否為0地址處
;==========================================================================
;如果不是,則表示主板設(shè)置了從NAND啟動,但這個(gè)程序由于其它原因,
;并沒有從NAND從啟動,這種情況最有可能的原因就是用仿真器.
;==========================================================================
bne copy_proc_beg ;這種情況也不讀取NAND FLASH.
;nop
;===========================================================
nand_boot_beg ;這一段代碼完成從NAND讀代碼到RAM
mov r5, #NFCONF ;首先設(shè)定NAND的一些控制寄存器
;set timing value
ldr r0, =(7<<12)|(7<<8)|(7<<4)
str r0, [r5]
;enable control
ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
str r0, [r5, #4]

bl ReadNandID ;按著讀取NAND的ID號,結(jié)果保存在r5里
mov r6, #0 ;r6設(shè)初值0.
ldr r0, =0xec73 ;期望的NAND ID號
cmp r5, r0 ;這里進(jìn)行比較
beq %F1 ;相等的話就跳到下一個(gè)1標(biāo)號處
ldr r0, =0xec75 ;這是另一個(gè)期望值
cmp r5, r0
beq %F1 ;相等的話就跳到下一個(gè)1標(biāo)號處
mov r6, #1 ;不相等了,設(shè)置r6=1.
1
bl ReadNandStatus ;讀取NAND狀態(tài),結(jié)果放在r1里

mov r8, #0 ;r8設(shè)初值0,意義為頁號
ldr r9, =ResetEntry ;r9設(shè)初值為初始化程序入口地址
;=========================================================================
; 注意,在這里使用的是ldr偽指令,而不是上面用的adr偽指令,它加載的是ResetEntry
; 的決對地址,也就是我們期望的RAM中的地址,在這里,它和|Image$$RO$$Base|一樣
; 也就是說,我如我們編譯程序時(shí)RO BASE指定的地址在RAM里,而把生成的文件拷到
; NAND里運(yùn)行,由ldr加載的r9的值還是定位在內(nèi)存.
;=========================================================================
2
ands r0, r8, #0x1f ;凡r8為0x1f(32)的整數(shù)倍-1,eq有效,ne無效
bne %F3 ;這句的意思是對每個(gè)塊(32頁)進(jìn)行檢錯(cuò)
mov r0, r8 ;r8->r0
bl CheckBadBlk ;檢查NAND的壞區(qū)
cmp r0, #0 ;比較r0和0
addne r8, r8, #32 ;存在壞塊的話就跳過這個(gè)壞塊
bne %F4 ;沒有的話就跳到標(biāo)號4處
3
mov r0, r8 ;當(dāng)前頁號->r0
mov r1, r9 ;當(dāng)前目標(biāo)地址->r1
bl ReadNandPage ;讀取該頁的NAND數(shù)據(jù)到RAM
add r9, r9, #512 ;每一頁的大小是512Bytes
add r8, r8, #1 ;r8指向下一頁
4
cmp r8, #256 ;比較是否讀完256頁即128KBytes
bcc %B2 ;如果r8小于256(沒讀完),就返回前面的標(biāo)號2處

mov r5, #NFCONF ;DsNandFlash
ldr r0, [r5, #4]
bic r0, r0, #1
str r0, [r5, #4]
ldr pc, =copy_proc_beg ;調(diào)用copy_proc_beg
;===========================================================
copy_proc_beg
adr r0, ResetEntry ;ResetEntry值->r0
ldr r2, BaseOfROM ;BaseOfROM值(后面有定義)->r2
cmp r0, r2 ;比較r0和r2
ldreq r0, TopOfROM ;如果相等的話(在內(nèi)存運(yùn)行),TopOfROM->r0
beq InitRam ;同時(shí)跳到InitRam

;=========================================================
;下面這個(gè)是針對代碼在NOR FLASH時(shí)的拷貝方法
;功能為把從ResetEntry起,TopOfROM-BaseOfROM大小的數(shù)據(jù)拷到BaseOfROM
;TopOfROM和BaseOfROM為|Image$$RO$$Limit|和|Image$$RO$$Base|
;|Image$$RO$$Limit|和|Image$$RO$$Base|由連接器生成
;為生成的代碼的代碼段運(yùn)行時(shí)的起啟和終止地址
;BaseOfBSS和BaseOfZero為|Image$$RW$$Base|和|Image$$ZI$$Base|
;|Image$$RW$$Base|和|Image$$ZI$$Base|也是由連接器生成
;兩者之間就是初始化數(shù)據(jù)的存放地放
;=======================================================

ldr r3, TopOfROM
0
ldmia r0!, {r4-r7}
stmia r2!, {r4-r7}
cmp r2, r3
bcc %B0

sub r2, r2, r3 ;r2=BaseOfROM-TopOfROM=(-)代碼長度
sub r0, r0, r2 ;r0=ResetEntry-(-)代碼長度=ResetEntry+代碼長度

InitRam
ldr r2, BaseOfBSS ;BaseOfBSS->r2
ldr r3, BaseOfZero ;BaseOfZero->r3
0
cmp r2, r3 ;比較BaseOfBSS和BaseOfZero
ldrcc r1, [r0], #4 ;要是r21 ; means Fclk:Hclk is not 1:1.
; bl MMU_SetAsyncBusMode
; |
; bl MMU_SetFastBusMode ; default value.
; ]

;bl Led_Test

;===========================================================
; 進(jìn)入C語言前的最后一步了,就是把我們用說查二級向量表
; 的中斷例程安裝到一級向量表(異常向量表)里.
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there is not subs pc,lr,#4 at 0x18, 0x1c
str r1,[r0]

; ;Copy and paste RW data/zero initialized data
; ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
; ldr r1, =|Image$$RW$$Base| ; and RAM copy
; ldr r3, =|Image$$ZI$$Base|
;
; ;Zero init base => top of initialised data
; cmp r0, r1 ; Check that they are different
; beq %F2
;1
; cmp r1, r3 ; Copy init data
; ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
; strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
; bcc %B1
;2
; ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
; mov r2, #0
;3
; cmp r3, r1 ; Zero init
; strcc r2, [r3], #4
; bcc %B3



關(guān)鍵詞: S3C24402440init.

評論


技術(shù)專區(qū)

關(guān)閉