mini2440(3) 2440init.s代码关键字注解

时间:2022-05-09 01:03:17

暂未完成,进行中。。。

;=========================================

; 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.
;=========================================


1、GET伪操作

The GET directive includes a file within the file being assembled. The included file is assembled at the location of the GET directive. INCLUDEis a synonym for GET.

通过下面的GET伪操作,在此处包含了三个文件option.inc,memcfg.inc,2440addr.inc

在汇编语言源代码文件中,可以包含C预处理命令#include,如果文件中包含了#include预处理命令,在使用armasm汇编之前,需要先使用C预处理器对源代码文件进行处理

在option.inc中定义了:

_STACK_BASEADDRESSEQU 0x33ff8000

定义了堆栈的基地址


2、EQU伪操作

The EQU directive gives a symbolic name to a numeric constant(数字常量), a register-relative value or a program-relative value. *is a synonym for EQU. Use EQUto define constants. This is similar to the use of #defineto define a constant in C.


GET option.inc
GET memcfg.inc
GET 2440addr.inc

BIT_SELFREFRESH EQU (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

;定义不同处理器模式下堆栈的地址

UserStackEQU(_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 ~

3、GBLL 定义一个全局的逻辑变量,默认初始化为{FALSE},因此,此处的THUMBCODE默认初始化为{FALSE}

4、[|]分别表示IF,ELSE,ENDIF

5、{CONFIG}是预定义的变量,表示被编译指令的位数,ARM状态32位,THUMB状态16位

6、CODE32指示汇编器把下面的指令汇编成32位的ARM指令,armasm默认为32位

7、根据上面的3、4、5、6知识点,下面这段代码即是:

IF {CONFIG} = 16

THUMBCODE SETL {TRUE}

CODE32

ELSE

THUMBCODE SETL {FALSE}

ENDIF

先定义全局逻辑变量THUMBCODE,如果预定义变量{CONFIG}是16,则将THUMBCODE设置为{TRUE},

然后用CODE32指示汇编器将下面的代码编译成32位指令

;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
GBLL    THUMBCODE
[ {CONFIG} = 16
THUMBCODE SETL {TRUE}
CODE32
|
THUMBCODE SETL  {FALSE}
]


8、MACRO,MEXIT,MEND

声明一个汇编宏,MOV_PC_LR、MOVEQ_PC_LR、HANDLER都是定义的宏的名称

$HandlerLabel HANDLER $HandleLabel中,$HandlerLabel在宏被展开时,HandlerLabel被替换为相应的符号,在宏名之前的

$HandlerLabel通常是一个标号,宏名之后的$HandlerLabel参数为宏的参数,在宏被展开时替换成相应的参数,类似于函数中的形式参数,可以在

定义宏时为参数指定相应的默认值


MACRO
MOV_PC_LR
[ THUMBCODE
bx lr
|
mov pc,lr
]
MEND


MACRO
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND


27、此处定义的宏,展开后就是中断服务程序

HandlerFIQ      HANDLER HandleFIQ
HandlerIRQ      HANDLER HandleIRQ
HandlerUndef    HANDLER HandleUndef
HandlerSWI      HANDLER HandleSWI
HandlerDabort   HANDLER HandleDabort
HandlerPabort   HANDLER HandlePabort


给这个宏传递的参数是标号,就是地址,以HandleIRQ为例,

仔细看清楚,HANDLER之前的是HandlerLabel,之后的时HandleLabel,分别是Handler和Handle,

以此处为例,此处定义的是HandlerIRQ服务程序,

HandleIRQ中的值,在

  ; Setup IRQ handler
ldr r0,=HandleIRQ       ;This routine is needed
ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]

中进行了设置,将IsrIRQ的值设置为HandleIRQ地址中的值

但是其它情况下,各个HandleLable的值都未设置?


以HandleUndef为例时,此时符号HandleUndef表示的内存地址中尚未初始化

其实,HandleUndef这些符号的值,都是已经初始化的,在数据段RamData

中,指定了结构化内存表的初始地址,这些符号的值也就确定了

将HandleUndef扩展开:

HandlerUndef

subsp,sp,#4;decrement sp(to store jump address)
stmfdsp!,{r0};PUSH the work register to stack(lr does't push because it return to original address)
ldr    r0,=HandleUndef;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)

HandlerUndef是符号,表示B跳转指令的地址,

ldr    r0,=HandleUndef

ldr    r0,[r0]

地址HandleUndef中的值是在什么地方设置的呢?

在这个汇编语言文件中,似乎没有对HandleUndef等内存地址空间进行设置,只对ResetHandler和HandlerIRQ进行了设置,

其它的几个是在后面用到的时候再进行设置的


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 does't 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

9、IMPORT

声明一个在其它目标文件或者库中定义的外部标号名

10、Image$$RO$$Limit等这些符号变量都是链接器在链接时,自动生成的一些链接器符号变量,通过这些符号变量,我们可以获得image文件中各输出域的信息,在ADS1.2中,使用这些变量时,需要将符号变量使用"|"括起来:

|Image$$RO$$Base|:RO输出域运行时起始地址;

|Image$$RO$$Limit|:RO输出域运行时结束地址;

|Image$$RW$$Base|:RW输出域运行时起始地址;

|Image$$RW$$Limit|:RW输出域运行时结束地址;

|Image$$ZI$$Base|:ZI输出域运行时起始地址;

|Image$$ZI$$Limit|:ZI输出域运行时结束地址;


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

11、AREA 定义一个段,段的名称为Init,CODE表示这是一个代码段,READONLY表示该段是只读的

12、ENTRY为链接器指定程序的入口点

13、ASSERT 汇编时的断言,如果逻辑表达式为假,则汇编以一个错误终止

14、:DEF:ENDIAN_CHANGE表示,如果变量ENDIAN_CHANGE是定义过的,则返回真


AREA    Init,CODE,READONLY

ENTRY  //指定程序的入口

;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't be used here because the linker generates error.


15、ASSERT:DEF:ENDIAN_CHANGE  

表示如果变量ENDIAN_CHANGE已经定义过,则:DEF:ENDIAN_CHANGE返回真,汇编器继续汇编

查找头文件option.inc,ENDIAN_CHANGE是在这个文件中定义的:

GBLLENDIAN_CHANGE
ENDIAN_CHANGE SETL{FALSE}

ENDIAN_CHANGE的默认值是{FALSE}

16、因为ENDIAN_CHANGE是{FALSE},则编译指令bResetHandler,

该指令直接跳转到符号ResetHandler表示的地址处去执行,该指令也是这个程序执行时的第一条指令


ASSERT:DEF:ENDIAN_CHANGE  
[ ENDIAN_CHANGE
ASSERT  :DEF:ENTRY_BUS_WIDTH
[ ENTRY_BUS_WIDTH=32
bChangeBigEndian   ;DCD 0xea000007
]

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

[ ENTRY_BUS_WIDTH=8
streqr0,[r0,-r10,ror #1] ;DCD 0x070000ea
]
|
b ResetHandler//直接跳转到符号ResetHandler表示的地址处执行

]


bHandlerUndef;handler for Undefined mode
b HandlerSWI;handler for SWI interrupt
b HandlerPabort;handler for PAbort
b HandlerDabort;handler for DAbort
b . ;reserved  注意,点号表示当前地址,即一旦执行该指令,就会在此处无限循环,即CPU会死在此处
b HandlerIRQ;handler for IRQ interrupt
b HandlerFIQ;handler for FIQ interrupt

;@0x20
b EnterPWDN; Must be @0x20.
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


;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
tst r0,#0x8 ;SLEEP mode?
bne ENTER_SLEEP


ENTER_STOP
ldr r0,=REFRESH
ldr r3,[r0] ;r3=rREFRESH
mov r1, r3
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0] ;Enable SDRAM self-refresh


mov r1,#16 ;wait until self-refresh is issued. may not be needed.
0 subs r1,r1,#1
bne %B0


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


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


mov r1,#16 ;Wait until self-refresh is issued,which may not be needed.
0 subs r1,r1,#1
bne %B0


ldr r1,=MISCCR
ldr r0,[r1]
orr r0,r0,#(7<<17)  ;Set SCLK0=0, SCLK1=0, SCKE=0.
str r0,[r1]


ldr r0,=CLKCON; Enter sleep mode
str r2,[r0]


b . ;CPU will die here.


24、读取MISCCR寄存器中的值,是进入Sleep模式时设置的一些值,

BIC指令:The BIC(BIt Clear) instruction performs an AND operation on the bits in Rnwith the complements of the corresponding bits in the value of Operand2.

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]

25、设置了从Sleep中Wakeup之后的一些状态,然后开始设置Memory Control寄存器

BWSCON是:BUS WIDTH & WAIT CONTROL REGISTER

SMRDATA是本文件中定义的一个标号,是一段内存的起始地址,这段内存有13*4=52个字节

下面行中,行头的0表示什么意思呢?是局部标号

下面行中,%B0表示什么意思呢?是对局部标号的引用,B表示Backward

将SMRDATA开始的内存中的值,设置到BWSCON地址开始的寄存器中,共13个寄存器

;Set memory control registers
ldr r0,=SMRDATA
ldr r1,=BWSCON;BWSCON Address

addr2, r0, #52;End address of SMRDATA

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


此处是执行256减法运算,没什么特别的用处,纯粹是浪费CPU时间,等待其它的硬件完成操作

mov r1,#256
0 subs r1,r1,#1;1) wait until the SelfRefresh is released.
bne %B0


此处应该是恢复Sleep之前的状态,继续执行。。。

ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEEP wake-up
ldr r0,[r1]

mov pc,r0

此处的LTORG伪操作,只是instructs the assembler to assemble the current literal pool immediately,声明一个数据缓冲池(又称文字池)的开始,它跟其后的指令没有任何关系

LTORG


定义的宏HANDLER是汇编器在什么时候展开的?C语言中有预处理,将头文件、宏等进行处理,但是汇编器何时对宏进行处理呢?

但是应该可以确定,汇编器首先要将文件中的宏进行处理,然后再进行汇编

似乎可以理解为,C语言中,先进行预处理,然后在编译,而汇编语言中,将预处理和汇编都放在汇编器中进行处理?

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
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}

;=======
; ENTRY

;=======

17、该程序执行时,程序的第一条指令"ResetHandler",直接跳转到此处执行,因此这会是该程序执行时的第二条指令;

18、LDR R0,=WTCON指令中,LDR是伪指令,不是ARM指令LDR,此处的WTCON时一个label-expr,LDR伪指令的用法:

LDR{cond} register,=[expr|label-expr]

查找WTCON,是在2440addr.inc中定义的:

;=================
; WATCH DOG TIMER
;=================
WTCON EQU  0x53000000       ;Watch-dog timer mode
WTDAT EQU  0x53000004       ;Watch-dog timer data
WTCNT EQU  0x53000008       ;Eatch-dog timer count

此时发现,说WTCON是label-expr是错误的,它应该是expr,因为WTCON是用EQU定义的数字常量,而不表示地址,不是标号(表达式)

LDR R1,=0x0指令中,LDR也是伪指令,此处0x0就是数字常量,与指令ldrr0,=WTCON用法一致,这两条指令分别把0x53000000加载

到寄存器R0中,将0x0加载到寄存器R1中,STR R1,[R0]指令中,将寄存器R1中的值保存到R0中的值作为基址指向的内存处,此处是将R1

中的值0x0写到内存地址0x53000000处,查看S3C2440的DataSheet:

mini2440(3) 2440init.s代码关键字注解

地址0x53000000是Watchdog Timer的WTCON寄存器(Watchdog Timer控制寄存器)地址,此处即将0x0这个值写到WTCON寄存器中,

查看WTCON寄存器的信息:

mini2440(3) 2440init.s代码关键字注解

从这个表中我们就可以得到WTCON寄存器的所有位都写入0后Watchdog Timer的状态

禁止watchdog timer,因为此时watchdog timer还未初始化,当产生溢出导致系统复位、中断时会让CPU跑飞,因为此时中断向量表还未建立

ResetHandler
ldr r0,=WTCON       ;watch dog disable  第五位设置为0,禁止watchdog timer
ldr r1,=0x0
str r1,[r0]

19、查找2440addr.inc文件中:

INTMSK  EQU  0x4a000008    ;Interrupt mask control

0x4a000008的二进制:0100 1001 0000 0000 0000 0000 0000 1000

查找S3C2440的DataSheet,0x4a000008是:

mini2440(3) 2440init.s代码关键字注解

禁止所有的中断,因为此时中断向量表还未建立

ldrr0,=INTMSK
ldr r1,=0xffffffff  ;all interrupt disable
str r1,[r0]

关于INTSUBMSK:

INTSUBMSKEQU  0x4a00001c    ;Interrupt sub mask

由于S3C2440的外设中断源太多,INTMSK不够用,还需要INTSUBMSK来将剩余的中断源也禁止掉。

ldrr0,=INTSUBMSK
ldr r1,=0x3ff;all sub interrupt disable
str r1,[r0]

//这段代码不编译

[ {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]
]

20、查找文件2440addr.inc:

LOCKTIMEEQU  0x4c000000     ;PLL lock time counter

查找S3C2440的DataSheet,地址0x4c000000:

mini2440(3) 2440init.s代码关键字注解

设置LOCKTIME的时间为0xffffff

LOCKTIME中,0~15位是MPLL lock time count value,16~31位是UPLL lock time count value

;To reduce PLL lock time, adjust the LOCKTIME register.
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]

21、2440addr.inc中:

CLKDIVNEQU  0x4c000014     ;Clock divider control

option.inc中:

CLKDIV_VALEQU7

此处将值7写入到寄存器0x4c000014中,查找S3C2440的DataSheet:

CLKDIVN是Clock divider control register

将值7写入到寄存器CLKDIVN中,这个寄存器中,只有低,4位是有用的:

mini2440(3) 2440init.s代码关键字注解

低3位都设置为1,位0为1:PCLK是HCLK的一半;位1、2为11,HCKL是FCKL的三分之一,或者六分之一,

需要根据CAMDIVN[8]的值来决定


[ PLL_ON_START
; Added for confirm clock divide. for 2440.
; Setting value 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, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.
str r1,[r0]

22、S3C2440 Datasheet中对UPLL、MPLL配置的说明:

When you set MPLL&UPLL values, you have to set the UPLL value first and then the MPLL value. (Needs intervals
approximately 7 NOP)(Page 255/595)

;Configure 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 delay must be inserted for setting hardware be completed.
nop
nop
nop
nop
nop

nop


;Configure MPLL
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) 
str r1,[r0]
]


23、GSTATUS2:Reset status

低3位有效,分别表示power on reset,wakeup reset in sleep mode,watch dog reset

TST指令:The TSTinstruction performs a bitwise(按位、逐位) AND operation,指令的结果会更新条件标志,

此处如果是wakeup reset in sleep mode,则结果的位2应该是1,其它都是0,则Z不为0,因此是满足执行条件

NE的,跳转到WAKEUP_SLEEP处执行,如果不是从Sleep中恢复,则不满足NE条件,则跳过BNE WAKEUP_SLEEP

的指令,继续执行,执行标号StartPointAfterSleepWakeUp后的指令,也是要先设置Memory Control寄存器,

然后跳转到标号InitStacks中继续执行,需要注意的时,此处设置Memory Control寄存器竟然没有耗时等待?为什么?


;Check if the boot is caused by the wake-up from SLEEP mode.
ldr r1,=GSTATUS2  
ldr r0,[r1]
tst r0,#0x2
;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
bne WAKEUP_SLEEP


EXPORT StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp

;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
str r3, [r1], #4
cmp r2, r0
bne %B0

从此处跳转到InitStacks处执行
;Initialize stacks
bl InitStacks

25、从此处开始设置中断服务程序了,在此之前是使用BL指令跳转到InitStacks标号处执行,

设置了处理器的各个特权模式下的SP的值,即堆栈指针的值,也就相当于初始化了各个模式

下的堆栈

IsrIRQ是中断服务程序的起始符号,即地址,HandleIRQ是存放中断服务程序地址的内存单元的地址

; Setup IRQ handler
ldr r0,=HandleIRQ       ;This routine is needed
ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]

;If main() is used, the variable initialization will be done in __main().
 [ :LNOT:USE_MAIN
    ;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
]




   
    [ :LNOT:THUMBCODE
    bl Main        ;Don't use main() because ......
    b .                       
    ]


    [ THUMBCODE         ;for start-up code for Thumb mode
    orr lr,pc,#1
    bx lr
    CODE16
    bl Main        ;Don't use main() because ......
    b .
    CODE32
    ]



24、初始化堆栈

SVCstack是在什么地方初始化的?

MRS将CPSR或者SPSR中的值MOVE到通用寄存器中

MODEMASK是:MODEMASK    EQU0x1f

0x1F是1 1111,即低5位全为1,BIC指令即将寄存器

R0中的低5位清零

#UNDEFMODE|NOINT的值即0001 1011 | 1100 0000,

即1101 1011

总结可知,这一段中,前面的几句就是切换处理器的模式,模式切换完成后,在该模式下设置SP的值,

最后是用SVCStack的值设置SVC模式下SP的值,因为上电后就是SVC模式,最后设置SVC模式下SP

的值,就少一次切换,但是用户模式的没设置,因为此时一旦切换到用户模式,就无法切换到特权

模式了,SP设置完后,就返回原来的调用处

;function initializing stacks
InitStacks
;Don't use DRAM,such as stmfd,ldmfd......
;SVCstack is initialized before???什么地方初始化的?
;Under toolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#UNDEFMODE|NOINT
msr cpsr_cxsf,r1;UndefMode
ldr sp,=UndefStack; UndefStack=0x33FF_5C00


orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1;AbortMode
ldr sp,=AbortStack; AbortStack=0x33FF_6000


orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1;IRQMode
ldr sp,=IRQStack; IRQStack=0x33FF_7000


orr r1,r0,#FIQMODE|NOINT
msr cpsr_cxsf,r1;FIQMode
ldr sp,=FIQStack; FIQStack=0x33FF_8000


bic r0,r0,#MODEMASK|NOINT
orr r1,r0,#SVCMODE
msr cpsr_cxsf,r1;SVCMode
ldr sp,=SVCStack; SVCStack=0x33FF_5800


;USER mode has not be initialized.


mov pc,lr
;The LR register won't be valid if the current mode is not SVC mode.



;=====================================================================
; Clock division test
; Assemble code, because VSYNC time is very short
;=====================================================================
EXPORT CLKDIV124
EXPORT CLKDIV144

CLKDIV124

ldr     r0, = CLKDIVN
ldr     r1, = 0x3; 0x3 = 1:2:4
str     r1, [r0]
; wait until clock is stable
nop
nop
nop
nop
nop


ldr     r0, = REFRESH
ldr     r1, [r0]
bic r1, r1, #0xff
bic r1, r1, #(0x7<<8)
orr r1, r1, #0x470; REFCNT135
str     r1, [r0]
nop
nop
nop
nop
nop
mov     pc, lr


CLKDIV144
ldr     r0, = CLKDIVN
ldr     r1, = 0x4; 0x4 = 1:4:4
str     r1, [r0]
; wait until clock is stable
nop
nop
nop
nop
nop


ldr     r0, = REFRESH
ldr     r1, [r0]
bic r1, r1, #0xff
bic r1, r1, #(0x7<<8)
orr r1, r1, #0x630; REFCNT675 - 1520
str     r1, [r0]
nop
nop
nop
nop
nop
mov     pc, lr



在此处声明一个数据缓冲池
LTORG


SMRDATA DATA
; Memory configuration should be optimized for best performance
; The following parameter is not optimized.
; Memory access cycle parameter strategy
; 1) The memory settings is  safe parameters even at HCLK=75Mhz.
; 2) SDRAM refresh period is for HCLK<=75Mhz.

DCD (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
DCD ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))   ;GCS0
DCD ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))   ;GCS1
DCD ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))   ;GCS2
DCD ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))   ;GCS3
DCD ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))   ;GCS4
DCD ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))   ;GCS5
DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))    ;GCS6
DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))    ;GCS7
DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)

DCD 0x32    ;SCLK power saving mode, BANKSIZE 128M/128M

DCD 0x30    ;MRSR6 CL=3clk
DCD 0x30    ;MRSR7 CL=3clk


ALIGN


26、此处定义数据段,可读写,^是伪操作MAP,_ISR_STARTADDRESS是在option.inc中定义的数字常量:

_ISR_STARTADDRESSEQU 0x33ffff00

使用MAP伪指令,定义结构化内存表,首地址就是_ISR_STARTADDRESS,是0x33ffff00

#是伪操作FIELD,定义一个结构化内存表中的数据域,FIELD后面的值,表示本数据域在内存表中所占的字节数,

而FIELD之前的label,label的值为当前内存表的位置计数器{VAR}的值,label是数据域的标号


AREA RamData, DATA, READWRITE

^   _ISR_STARTADDRESS; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset #   4
HandleUndef #   4
HandleSWI #   4
HandlePabort    #   4
HandleDabort    #   4
HandleReserved  #   4
HandleIRQ #   4
HandleFIQ #   4


;Don't use the label 'IntVectorTable',
;The value of IntVectorTable is different with the address you think it may be.
;IntVectorTable
;@0x33FF_FF20
HandleEINT0 #   4
HandleEINT1 #   4
HandleEINT2 #   4
HandleEINT3 #   4
HandleEINT4_7 #   4
HandleEINT8_23 #   4
HandleCAM #   4; Added for 2440.
HandleBATFLT #   4
HandleTICK #   4
HandleWDT #   4
HandleTIMER0 #   4
HandleTIMER1 #   4
HandleTIMER2 #   4
HandleTIMER3 #   4
HandleTIMER4 #   4
HandleUART2   #   4
;@0x33FF_FF60
HandleLCD #   4
HandleDMA0 #   4
HandleDMA1 #   4
HandleDMA2 #   4
HandleDMA3 #   4
HandleMMC #   4
HandleSPI0 #   4
HandleUART1 #   4
HandleNFCON #   4; Added for 2440.
HandleUSBD #   4
HandleUSBH #   4
HandleIIC #   4
HandleUART0 #   4
HandleSPI1 #   4
HandleRTC #   4
HandleADC #   4

;@0x33FF_FFA0


END


问题列表:

1、CPU上电时,从地址0x0开始执行,那么b ResetHandler指令就应该位于地址0x0处:

如果是Nor Flash,Nor Flash映射的地址区间必须要从0x0开始,程序烧写到Nor Flash中时,也必须从0x0地址处开始烧写,烧写指令b ResetHandler到地址0x0处,这样上电后就可以直接执行;

如果是Nand Flash,Nor Flash的前4KB可以在上电时自动加载到Nand Flash控制器内的SRAM中执行,SRAM位于Nand Flash控制器中,而Nand Flash控制器又位于S3C2440片内,因此SRAM即S3C2440片内SRAM,这个SRAM的名字叫Stepping stone,此时该SRAM被映射到0x0地址,因此在烧写程序时,也必须将程序烧写到Nand Flash的前4KB中,b ResetHandler指令位于Nand Flash中将来被复制到SRAM中0x0地址的区域上;

问题是,Nor Flash中直接执行,Nand Flash中在S3C2440的片内SRAM上执行,如果加载时地址与运行时地址不一致,如何对程序进行重定位,在程序运行时将程序从加载地址搬到期望的运行时地址处执行?谁负责?


2、从b ResetHandler中开始执行时,为何disable watchdog timer?

当系统复位后,watchdog timer、中断等都要立刻禁止或者被初始化,否则当watchdog timer溢出产生的系统复位、引起中断、其它中断源产生中断时,CPU会进入一个未知的状态,出现程序跑飞等现象,因为此时中断向量表等还未初始化完毕


3、晶振、时钟问题,还没完全弄清楚?