在网上转的,搜集起来,下非有必要检查的时分便利点。
s3c2440发动文件剖析
s3c2440发动文件剖析
;=========================================
; [url=URL]NAME[/url]: 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) ;bit[22]=1,others=0(把1左移22位)
;Pre-defined constants ;体系的作业形式设定
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK EQU 0x1f
NOINT EQU 0xc0
;The location of stacks ;体系的仓库空间设定
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 ~
;arm处理器有两种作业状况 1.arm:32位 这种作业状况下碑文字对准的arm指令 2.Thumb:16位这种作业状
;态碑文半字对准的Thumb指令
;我们处理器分为16位 32位两种作业状况 程序的编译器也是分16位和32两种编译办法 所以下面的程序用
;于根据处理器作业状况确认编译器编译办法
;code16伪指令指示汇编编译器后边的指令为16位的thumb指令
;code32伪指令指示汇编编译器后边的指令为32位的arm指令
;这段是为了一致现在的处理器作业状况和软件编译办法(16位编译环境运用tasm.exe编译
;Check if tasm.exe(armasm -16 …@ADS 1.0) is used.
GBLL THUMBCODE ;界说一个全局变量
[ {CONFIG} = 16 ;if config==16 这儿一共你的现在处于抢先地16位编译办法
THUMBCODE SETL {TRUE} ;设置THUMBCODE 为 true一共告知体系当时想用thumb,但实践发动时不可,只能发动后再跳
; ][|]一共if else endif
CODE32 ;发动时强制运用32位编译形式
|
THUMBCODE SETL {FALSE} ;假如体系要求是ARM指令,则直接设置THUMBCODE 为 false 阐明当时的是32位编译形式
]
MACRO ;宏界说
MOV_PC_LR
[ THUMBCODE
bx lr
|
mov pc,lr
]
MEND
MACRO
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr ;持平Z=1,则跳转
|
moveq pc,lr
]
MEND
;留意下面这段程序是个宏界说 很多人对这段程序不理解 我再次着重这是一个宏界说 所以我们要留意了
;下面包含的HandlerXXX HANDLER HandleXXX将都被下面这段程序打开
;这段程序用于把中止服务程序的首地址装载到pc中,有人称之为“加载程序”。
;本初始化程序界说了一个数据区(在文件最终),34个字空间,寄存相应中止服务程序的首地址。每个字
;空间都有一个标号,以Handle***命名。
;在向量中止形式下运用“加载程序”来碑文中止服务程序。
;这儿就有必要讲一下向量中止形式和非向量中止形式的概念
;向量中止形式是当cpu读取坐落0x18处的IRQ中止指令的时分,体系主动读取对应于该中止源确认地址上的;
;指令替代0x18处的指令,经过跳转指令体系就直接跳转到对应地址
;函数中 节省了中止处理时刻提高了中止处理速度标 例如 ADC中止的向量地址为0xC0,则在0xC0处放如下
;代码:ldr PC,=HandlerADC 当ADC中止产生的时分体系会
;主动跳转到HandlerADC函数中
;非向量中止形式处理办法是一种传统的中止处理办法,当体系产生中止的时分,体系将interrupt
;pending寄存器中对应标志方位位 然后跳转到坐落0x18处的一致中止
;函数中 该函数经过读取interrupt pending寄存器中对应标志位 来判别中止源 并根据优先级联系再跳到
;对应中止源的处理代码中
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr doest push because it return to original address)
ldr r0,=$HandleLabel;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
;将$HandleLabel地址空间中的数据给PC,中止服务程序的进口
IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
IMPORT |Image$$RW$$Base| ; Base of RAM to initialise
IMPORT |Image$$ZI$$Base| ; Base and limit of area
IMPORT |Image$$ZI$$Limit| ; to zero initialise
IMPORT Main
;导入要用到的字符常量
AREA Init,CODE,READONLY
;异常中止矢量表(每个表项占4个字节) 下面是中止向量表 一旦体系运转时有中止产生 即便移植了操作
;体系 如linux 处理器现已把操控权交给了操作体系 一旦产生中止 处理器仍是会跳转到从0x0开端
;中止向量表中某个中止表项(根据中止类型)开端碑文
;详细中止向量布局请参阅s3c44b0 spec 例如 adc中止向量为 0x000000c0下面对应表中第49项方位向量地址0x0+4*(49-1)=0x000000c0
ENTRY
;板子上电和复位后 程序开端从坐落0x0处开端碑文硬件刚刚上电复位后 程序从这儿开端碑文跳转到标
;为ResetHandler处碑文
;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 cant be used here because the linker generates error.
;条件编译,在编译成机器码前就设定好
ASSERT :DEF:ENDIAN_CHANGE ;判别ENDIAN_CHANGE是否已界说
[ ENDIAN_CHANGE ;假如现已界说了ENDIAN_CHANGE,则判别,here is FALSE
ASSERT :DEF:ENTRY_BUS_WIDTH ;判别ENTRY_BUS_WIDTH是否已界说
][ ENTRY_BUS_WIDTH=32 ;假如现已界说了ENTRY_BUS_WIDTH,则判别是不是为32
b ChangeBigEndian ;DCD 0xea000007
]
;在bigendian中,地址为A的字单元包含字节单元A,A+1,A+2,A+3,字节单元由高位到低位为A,A+1,A+2,A+3
; 地址为A的字单元包含半字单元A,A+2,半字单元由高位到低位为A,A+2
[ ENTRY_BUS_WIDTH=16
andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00 也是b ChangeBigEndian指令,仅仅我们总线不一样而取机器码的次序不一样
] ;先取低位->高位 上述指令是经过机器码装换而来的
[ ENTRY_BUS_WIDTH=8
streq r0,][r0,-r10,ror #1] ;DCD 0x070000ea 也是b ChangeBigEndian指令,仅仅我们总线不一样而取机器码的次序不一样
]
|
b ResetHandler ;//here is the first instrument 0x00
]
b HandlerUndef ;handler for Undefined mode ;0x04
b HandlerSWI ;handler for SWI interrupt ;0x08
b HandlerPabort ;handler for PAbort ;0x0c
b HandlerDabort ;handler for DAbort ;0x10
b . ;reserved ;0x14
b HandlerIRQ ;handler for IRQ interrupt ;0x18
b HandlerFIQ ;handler for FIQ interrupt ;0x1c
;@0x20
b EnterPWDN ; Must be @0x20.
;经过设置CP15的C1的位7,设置存储格局为Bigendian,三种总线办法
ChangeBigEndian ;//here ENTRY_BUS_WIDTH=16
;@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
;对存储器操控寄存器操作,指定内存形式为Big-endian
;我们刚开端CPU都是依照32位总线的指令格局运转的,假如选用其他的话,CPU别不了,有必要转化
;但当体系初始化好今后,则CPU能主动识别
]
[ ENTRY_BUS_WIDTH=16
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
;我们选用Big-endian形式,选用16位总线时,物理地址的高位和数据的位置对应
;所以指令的机器码也相应的凹凸对调
]
[ 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
;Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.
; 4. The I-cache may have to be turned on.
; 5. The location of the following code may have not to be changed.
;void EnterPWDN(int CLKCON);
EnterPWDN
mov r2,r0 ;r2=rCLKCON 保存原始数据 0x4c00000c 使能各模块的时钟输入
tst r0,#0x8 ;测验bit[3] SLEEP mode? 1=>sleep
bne ENTER_SLEEP ;C=0,即TST成果非0,bit[3]=1
;//进入PWDN后假如不是sleep则进入stop
;//进入Stop mode
ENTER_STOP
ldr r0,=REFRESH ;0x48000024 DRAM/SDRAM refresh config
ldr r3,[r0] ;r3=rREFRESH
mov r1, r3
orr r1, r1, #BIT_SELFREFRESH ;Enable SDRAM self-refresh
str r1, [r0] ;Enable SDRAM self-refresh
;//Enable SDRAM self-refresh
mov r1,#16 ;wait until self-refresh is issued. may not be needed.
0 subs r1,r1,#1
bne %B0
;//wait 16 fclks for self-refresh
ldr r0,=CLKCON ;enter STOP mode.
str r2,[r0]
;//??????????????
mov r1,#32
0 subs r1,r1,#1 ;1) wait until the STOP mode is in effect.
bne %B0 ;2) Or wait here until the CPU&Peripherals will be turned-off
;Entering SLEEP mode, only the reset by wake-up is available.
ldr r0,=REFRESH ;exit from SDRAM self refresh mode.
str r3,[r0]
MOV_PC_LR ;back to main process
ENTER_SLEEP
;NOTE.
;1) rGSTATUS3 should have the return address after wake-up from SLEEP mode.
ldr r0,=REFRESH
ldr r1,[r0] ;r1=rREFRESH
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0] ;Enable SDRAM self-refresh
;//Enable SDRAM self-refresh
mov r1,#16 ;Wait until self-refresh is issued,which may not be needed.
0 subs r1,r1,#1
bne %B0
;//Wait until self-refresh is issued,which may not be needed
ldr r1,=MISCCR ;IO register
ldr r0,[r1]
orr r0,r0,#(7<<17) ;Set SCLK0=1, SCLK1=1, SCKE=1.
str r0,[r1]
ldr r0,=CLKCON ; Enter sleep mode
str r2,[r0]
b . ;CPU will die here.
;//进入Sleep Mode,1)设置SDRAM为self-refresh
;// 2)设置MISCCR bit[17] 1:sclk0=sclk 0:sclk0=0
;// bit[18] 1:sclk1=sclk 0:sclk1=0
;// bit[19] 1:Self refresh retain enable
;// 0:Self refresh retain disable
;// When 1, After wake-up from sleep, The self-refresh will be retained.
WAKEUP_SLEEP
;Release SCLKn after wake-up from the SLEEP mode.
ldr r1,=MISCCR
ldr r0,[r1]
bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
str r0,[r1]
;//设置MISCCR
;Set memory control registers
ldr r0,=SMRDATA
ldr r1,=BWSCON ;BWSCON Address ;//总线宽度和等候操控寄存器
add r2, r0, #52 ;End address of SMRDATA
0
ldr r3, [r0], #4 ;数据处理后R0自加4,[R0]->R3,R0+4->R0
str r3, [r1], #4
cmp r2, r0
bne %B0
;//设置一切的memory control register,他的初始地址为BWSCON,初始化
;//数据在以SMRDATA为开端的存储区
mov r1,#256
0 subs r1,r1,#1 ;1) wait until the SelfRefresh is released.
bne %B0
;//1) wait until the SelfRefresh is released.
ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEEP wake-up
ldr r0,[r1]
mov pc,r0
;//跳出Sleep Mode,进入Sleep状况前的PC
;//异常中止宏调用
LTORG
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET ;地址为0x4a000014的空间存着中止的偏移
ldr r9,[r9] ;I_ISR
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
;//外部中止号判别,经过中止服务程序进口地址存储器的地址偏移确认
;//PC=[HandleEINT0+][INTOFFSET]]
;=======
; ENTRY
;扳子上电和复位后 程序开端从坐落0x0碑文b ResetHandler 程序从跳转到这儿碑文
;板子上电复位后 碑文几个过程这儿经过标号在注释中加1,2,3….怂恿 标号一共碑文次序
;1.制止看门狗 屏蔽一切中止
;=======
ResetHandler
;//1.制止看门狗 屏蔽一切中止
ldr r0,=WTCON ;watch dog disable
ldr r1,=0x0
str r1,[r0]
ldr r0,=INTMSK
ldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x3ff ;all sub interrupt disable
str r1,[r0]
[ {FALSE}
;//rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
;//Led_Display
ldr r0,=GPFCON ;//F-IO In/Out config 10 10 10 10 00 00 00 00
ldr r1,=0x5500 ;//00 = Input 01 = Output
str r1,][r0] ;//10 = EINT[0] 11 = Reserved
ldr r0,=GPFDAT ;//F-IO data register
ldr r1,=0x10
str r1,[r0]
]