您的当前位置:首页正文

实验一 ARM汇编程序的编写以及启动代码的分析

2022-05-26 来源:步旅网
实验 ARM汇编程序的编写以及启动代码的分析

一、实验目的:

练习ARM汇编程序的编写,对提供的程序的启动代码进行分析,了解S3C2410初始化过程, 初始化代码主要是包含在start.s中。

二、实验原理:

启动程序要完成的任务包括:硬件初始化,系统存储系统的配置,复制二级中断向量表。

启动程序过程

● 系统硬件初始化

系统上电或复位后,程序从位于地址0x0的Reset Exception Vector处开始执行,因此需要在这里放置Bootloader的第一条指令:b ResetHandler,跳转到标号为ResetHandler处进行第一阶段的硬件初始化,执行完,系统进行堆栈和存储器的初始化。使用了外设,则需要设置相关的寄存器,确定其刷新频率、总线宽度等信息。

● 代码段复制到RAM中运行

需要把系统的代码复制到RAM中运行。映像文件内部共有三种输出段:RO段、RW段和ZI段。ARMLink同时还产生了这三种输出段的起始和终止定位信息:Image$$RO$$Base、Image$$RO$$Limit、Image$$RW$$Base、Image$RW$Limit、Image$ZI$Base和Image$$ZI$$Limit。可以在程序中使用这些定位信息。将ROM中的代码和数据搬移到RAM中。

● 建立二级中断向量表

在ARM系统中,中断向量表位于0X0开始的地址处,意味着无论运行什么样的上层软件,一旦发生中断,程序就得到Flash存储器中的中断向量表里去,降低系统的运行效率。因此在RAM中建立自己的二级中断向量表,当中断发生后,程序直接从RAM中取中断向量进入中断子程序。尤其是在中断频繁发生的系统里,这种方法可以大大提高系统的运行效率。

三、实验内容:

1.运行一个简单的串口程序,单步执行初始化代码,观察寄存器变化。 2.分析系统上电后的初始化工作包括哪些内容。

3.分析中断的处理过程,包括中断向量表的建立、中断源的识别及中断IRQ服务程序是如何进入的。

4.分析应用程序的结构。

四、实验代码:

在系统上电后,初始化部分的工作注意包含以下部分: 1、 关看门狗定时器

2、 屏蔽所有中断

3、 设置CPU时钟频率。

4、 设置存储器控制寄存器,对外部存储器的参数进行设置。 5、 初始化各模式下的堆栈

6、 建立IRQ中断的总的入口地址 7、 初始化应用程序的执行环境 8、 跳入Main函数,进入C程序

;========================================= ; NAME: 2410INIT.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,POWER_OFF mode ;=========================================

GET option.s ;GET相当INCLUDE 将一个源文件包含到当前源文件,这里表示包含

option.s,并在当前位置进行汇编

BIT_SELFREFRESH EQU (1<<22) ;定义了一些符号常量

;ARM异常模式的定义

;SDRAM/DRAM 刷新控制器 bit22 REFMD位 0:CBR/AUTO REFRESH 1:SHIF REFRESH ;下面是对arm处理器模式寄存器对应值的常数定义,arm处理器中有一个CPSR程序状 ;态寄存器,CPSR后五位决定目前的处理器模式。 ;Pre-defined constants USERMODE FIQMODE IRQMODE SVCMODE

EQU EQU EQU EQU

0x10 ;用户模式

0x11 ;FIQ快速中断模式 0x12 ;中断模式 0x13 ;管理模式

GET memcfg.s GET 2410addr.s

ABORTMODE EQU UNDEFMODE EQU MODEMASK EQU NOINT

EQU

0x17 ;中止模式 0x1b ;未定义指令模式 0x1f ;系统模式

0xc0 ;禁止IRQ和FIQ中断

;ARM各异常模式堆栈,定义各模式堆栈地址 ;_STACK_BASEADDRESS在option.s中, ;The location of stacks

_STACK_BASEADDRESS EQU (SDRAM_END-0x8000) UserStack 堆栈

SVCStack EQU (_STACK_BASEADDRESS-0x2800) 管理模式堆栈 4k UndefStack

EQU (_STACK_BASEADDRESS-0x2400)

;0x33ff5c00 ~0x3ff57ff ; ;0x33ff5800 ~0x3ff47ff ;

;0x33ff8000

;0x33ff4800 ~ ; 用户模式

EQU (_STACK_BASEADDRESS-0x3800)

未定义指令模式堆栈 1k AbortStack

EQU (_STACK_BASEADDRESS-0x2000)

;0x33ff6000 ~0x3ff5bff ;

中止模式堆栈 1k

IRQStack EQU (_STACK_BASEADDRESS-0x1000) 中断模式堆栈 4k

FIQStack EQU (_STACK_BASEADDRESS-0x0) 快速中断模式堆栈 4k ;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. 检查是否是用tasm.exe进行16位编译

GBLL THUMBCODE ;声明一个全局变量 并初始化为{FALSE}

;0x33ff8000 ~0x33ff6fff ; ;0x33ff7000 ~0x3ff5fff ;

[ {CONFIG} = 16 ;if config=16这里表示用16位编译方式

THUMBCODE SETL {TRUE} ;SETL 给全局变量赋值,设置THUMBCODE 为 true 式

| ; |=ELSE | 等同 ELSE

;设置THUMBCODE 为 false,THUMBCODE=FALSE ;endif ] 等同 ENDIF

CODE32

;CODE32表明一下操作都在ARM状态,转入32位编译模

THUMBCODE SETL {FALSE}

]

;宏定义MOV_PC_LR

MACRO ;MACRO 定义宏,宏定义开始

MOV_PC_LR ;宏将被下面定义部分展开,宏名 MOV_PC_LR

[ THUMBCODE

;if THUMBCODE=true

;THUMBCODE 模式上返回ARM状态 ;else

bx lr

|

mov pc,lr ;ARM状态下返回

MACRO

;宏定义开始

;宏名为MOVEQ_PC_LR,与上面部分相同 ;if THUMBCODE=true

;EQ 相等 则跳转回ARM状态 ;else

]

;end if ;宏结束

MEND

MOVEQ_PC_LR

[ THUMBCODE

bxeq lr |

moveq pc,lr

;宏定义-进入异常流程 ;HANDLER-宏的名称 ;$HandleLabel-宏的参数

]

;同上位置相同部分,不同的是如果相等才跳回ARM状态

;end if ;宏结束

MEND

;这个宏的作用是把各个中断程序的地址装入当前的PC,2410有两种装断模式:一种是没有

;中断向量表,一种是使用中断向量表的

;使用中断向量表只能是IRQ方式,当使用中断向量表的时候,中断发生时由2410的中断控 ;制器自动跳转到 ;相应的位置。

;注意下面这段宏定义程序

;下面包含的HandlerXXX HANDLER HandleXXX将都被下面这段程序展开

;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首 ;地址。每个字,即4字节

;空间都有一个标号,以Handle***命名。

;在向量中断模式下使用“加载程序”来执行中断服务程序。

;向量中断模式和非向量中断模式的区别是: 向量中断模式是当cpu读取位于0x18处的IR ;Q中断指令的时候,系统自动读取对应于该中断源确定地址上的指令取代0x18处的指令, ;通过跳转指令系统就直接跳转到对应地址

;函数中 节省了中断处理时间提高了中断处理速度标 例如 ADC中断的向量地址为0xC0, ;在0xC0处放如下代码:

;ldr PC,=HandlerADC 当ADC中断产生的时候系统会自动跳转到HandlerADC函数中 ;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将int ;errupt pending寄存器中对应标志位置位 ;然后跳转到位于0x18处的统一中断;函数中

;该函数通过读取interrupt pending寄存器中对应标志位来判断中断源,并根据优先级关系 ;再跳到;对应中断源的处理代码中

;大致作用是把宏的第一个参数$HandlerLabel转变为一个标号,然后让程序跳转到第二个参 ;数$HandleLabel(为一个地址)对应的值的地址去。

;所以,通过上面的分析可以看出,$HandlerLabel HANDLER $HandleLabel是让PC跳转到$H ;andleLabel中存放的地址执行。

MACRO

;宏定义

$HandlerLabel HANDLER $HandleLabel ;宏名字叫HANDLER,$HandleLabel是

;行参,定义了一个标号$HandlerLabel,展开时可替换成相应的符号 $HandlerLabel

sub sp,sp,#4 stmfd

;sp-sp-4,空出的空间用于存放跳转地址

sp!,{r0} ;sp=sp-4,并将r0入栈

;获取存放跳转地址的标号HandleLabel到r0 ;将HandleLabel中存放的跳转地址送给r0 ;将r0存放到sp+4的地方,

;弹出栈顶2个字,分别保存到r0和pc中,系统将跳

ldr r0,=$HandleLabel ldr r0,[r0] str r0,[sp,#4] ldmfd sp!,{r0,pc}

;转到对应中断处理函数,由上r0和pc都没变,但程序已跳转 MEND ;宏定义结束 ;连接器生成的输出段相关的符号

;引入连接器生成的映象文件的各个部分地址。

;OR-只读区域、RW-读写区域、ZI-初始化为0的区域。

IMPORT |Image$$RO$$Limit|

; End of ROM code (=start of ROM data) ,RO结束

;地址+1

IMPORT |Image$$RW$$Base| IMPORT |Image$$ZI$$Base| IMPORT |Image$$ZI$$Limit|

; Base of RAM to initialise,RW起始 ; Base and limit of area,RW段结束+1 ; to zero initialise,ZI段起始地址

; 引入外部函数Main,进入C程序。

IMPORT Main ; The main entry of mon program ;IMPORT LEDTEST

;定义ARM汇编程序段,段名为SelfBoot,程序段为只读的代码段。 AREA SelfBoot,CODE,READONLY

;Selfboot初始化程序

;板子上电和复位后程序开始从位于0x0处开始执行,硬件刚刚上电复位后程序从这里开始 ;执行跳转到标为ResetHandler处执行

;DCD用于分配一段字内存单片,并用后面的伪指令初始化,分配字节由expr 个数决定 ;程序入口地址

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.

ASSERT :DEF:ENDIAN_CHANGE ;ASSERT 断言错误伪指令,这里表示是否定;3)The pseudo instruction,DCD can't be used here because the linker generates error.

义过ENDIAN_CHANGE

[ ENDIAN_CHANGE ;如果定义了ENDIAN_CHANGE

ASSERT :DEF:ENTRY_BUS_WIDTH ;这里表示是否定义过ENTRY_BUS_WIDTH

[ ENTRY_BUS_WIDTH=32 ;if ENTRY_BUS_WIDTH=32

b

ChangeBigEndian ;DCD 0xea000007,跳转到ChangeBigEndian,

;执行DCD 0xea000007 改变大小端数据模式

]

;end if

[ ENTRY_BUS_WIDTH=16 ;if ENTRY_BUS_WIDTH=16

andeq

r14,r7,r0,lsl #20

; DCD 0x0007ea00,标志状态寄存器CPSR的Z

;=1时,r14=r7+r0逻辑左移20位,执行DCD 0x0007ea00改变大小端模式

]

;end if

;if ENTRY_BUS_WIDTH=8

[ ENTRY_BUS_WIDTH=8

streq

r0,[r0,-r10,ror #1] ; DCD 0x070000e,当标志状态寄存器CPSR的Z

;=1时„,执行DCD 0x070000ea 改变大小端模式 ]

;end if

| ;ELSE 即如果没定义 ENDIAN_CHANGE b

]

ResetHandler

;复位处理模式

b b b b b

HandlerUndef ;handler for Undefined mode 处理为定义模式

处理软中断模式

处理终止程序访问终止模

HandlerSWI ;handler for SWI interrupt HandlerPabort

;handler for PAbort

HandlerDabort .

;handler for DAbort

处理数据访问终止模式 保留,\".\"代表指令的地

;reserved

址 ,即表示进行死循环

;@0x20

b

\"@\" 存储区位置计数器的当前值 ;进入掉电模式,见下面的标号

b b

HandlerIRQ HandlerFIQ

;handler for IRQ interrupt 处理中断模式 ;handler for FIQ interrupt 处理快速中断模式

EnterPWDN

ChangeBigEndian ;上面提到的ChangeBigEndian,改变大小端数据模式 ;@0x24

[ ENTRY_BUS_WIDTH=32 DCD 0xee110f10

;if ENTRY_BUS_WIDTH=32

;0xee110f10 => mrc p15,0,r0,c1,c0,0

DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian DCD 0xee010f10 ]

[ ENTRY_BUS_WIDTH=16 DCD 0x0f10ee11 DCD 0x0080e380 DCD 0x0f10ee01 ]

[ ENTRY_BUS_WIDTH=8 DCD 0x100f11ee

;if ENTRY_BUS_WIDTH=8

;if ENTRY_BUS_WIDTH=16 ;0xee010f10 => mcr p15,0,r0,c1,c0,0

DCD 0x800080e3 DCD 0x100f01ee

]

;swinv 0xffffff is similar with NOP and run well in both endian

DCD 0xffffffff

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. ;进入掉电模式功能

; 1. SDRAM 必须在自刷新模式.

; 2. 所有中断必须屏蔽 for SDRAM/DRAM self-refresh. ; 3. LCD 关闭for SDRAM/DRAM self-refresh. ; 4. The I-cache 可能需要开启.

; 5. The location of the following code may have not to be changed. ;void EnterPWDN(int CLKCON); ;进入掉电模式 EnterPWDN mov r2,r0

tst r0,#0x8

;r2=rCLKCON CLKCON[3]掉电模式控制位 0:关闭 1:进入掉电模式

; POWER_OFF mode?判断POWER_OFF 是否为0 。r0和

#0X8相与,更新CPSR位

ENTER_STOP ;不进入掉电模式

ldr r0,=REFRESH

;0x48000024 ;DRAM/SDRAM refresh DRAM/SDRAM 刷新控

bne ENTER_POWER_OFF ;NE 不相等(则表示power_off不为O) 标志位Z=0

制器,刷新DRAM/SDRAM

ldr r3,[r0]

;r3=rREFRESH

;r1=r3

mov r1, r3

orr r1, r1, #BIT_SELFREFRESH ;BIT_SELFREFRESH EQU (1<<22) bit22 TREFMD位

0:CBR/AUTO REFRESH 1:SHIF REFRESH

str r1, [r0]

;R1->[R0] Enable SDRAM self-refresh

;%B是向后搜索局部标号, %F是向前搜索局部标号。

mov r1,#16

;延时 wait until self-refresh is issued. may not be

needed. 0

subs r1,r1,#1 bne %B0

;enter STOP mode. CLKCON ;Clock generator control

;0为局部标号(延时)

ldr r0,=CLKCON

0

str r2,[r0]

mov r1,#32

subs r1,r1,#1 bne %B0

;1)延时 wait until the STOP mode is in effect.

;2) Or wait here until the CPU&Peripherals will be turned-off

; Entering POWER_OFF mode, only the reset by wake-up is available.

ENTER_POWER_OFF

;NOTE. 0

ldr r1,=MISCCR ; ;Miscellaneous control,混杂控制模式 ldr r0,[r1]

orr r0,r0,#(7<<17) ;Make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L during mov r1,#16

;Wait until self-refresh is issued,which may not be needed.

;延时

;1) rGSTATUS3 should have the return address after wake-up from POWER_OFF mode.

ldr r0,=REFRESH ldr r1,[r0]

;r1=rREFRESH

;进入掉电模式

ldr r0,=REFRESH str r3,[r0]

MOV_PC_LR ;调用宏MOV_PC_LR

;exit from SDRAM self refresh mode.

orr r1, r1, #BIT_SELFREFRESH str r1, [r0]

;Enable SDRAM self-refresh

subs r1,r1,#1 bne %B0

;boot-up

str r0,[r1]

ldr r0,=CLKCON str r2,[r0]

;CPU will die here. \".\"当前指令的地址 CPU死在这

b .

WAKEUP_POWER_OFF ;掉电唤醒

;Release SCLKn after wake-up from the POWER_OFF mode. ldr r1,=MISCCR ;Miscellaneous control,混杂模式 ldr r0,[r1]

bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:L->H str r0,[r1]

;Set memory control registers

ldr r0,=SMRDATA

;BWSCON Address 起始位置 依次为BANKCON0 BANKCON1

ldr r1,=BWSCON

BANKCON2 ........

add r2, r0, #52

;End address of SMRDATA

0

ldr r3, [r0], #4

;读取R0地址的数据到R3 R0=R0+4 读取SMRDATA 数组

(BWSCON BANKCON0 ....)的值

str r3, [r1], #4

;读取R3的数据到 R1地址内存中 R1=R1+4 赋给BWSON

BANKCON0 ....寄存器 0

mov r1,#256 subs r1,r1,#1

;1) wait until the SelfRefresh is released. ;延时

cmp r2, r0

;判断是否赋完值

bne %B0

bne %B0

ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after POWER_OFF

wake-up

ldr r0,[r1]

;Saved data0(32-bit) before entering POWER_OFF mode,在进

;入掉电模式之前(POWER=OFFMODE),保存data0

LTORG ;文字池, 声明一个数据缓冲池的开始 mov pc,r0

;下面是具体的中断处理函数跳转的宏,通过上面的$HandlerLabel的宏定义展开后跳转到对 ;应的中断处理;函数(对于向量中断)

HandlerFIQ HANDLER HandleFIQ ;调用宏HANDLER

HandlerIRQ HANDLER HandleIRQ ;HandlerIRQ 行号 HANDLER 宏名 ;HandleIRQ 导入的形参

HandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabort HandlerPabort HANDLER HandlePabort

;下面这段程序是用来处理非向量中断,具体判断I_ISPR中各位是否置1 ,置1表示目前此 ;中断等待响应(每次只能有一位置1),

;从最高优先级中断位开始判断,检测到等待服务中断就将pc置为中断服务函数首地址

IsrIRQ ;IRQ模式中断(片内外设中断 引脚中断)

sub sp,sp,#4

; reserved for PC,中断分发例程入口地址预留栈空间,预留

;pc返回指针的存储位置

stmfd

sp!,{r8-r9}

;将R8~R9 放入堆栈

;INTOFFSET寄存器各位表明发生了应该调用那个中断子程序。 ;不过这个寄存器只能用在IRQ中断模式。

ldr r9,=INTOFFSET ;中断请求源偏移寄存器 ldr r9,[r9] ;r9中存放INTOFFSET的内容

ldr r8,=HandleEINT0 ; 取EINT0的地址,即IRQ 中断首址 add r8,r8,r9,lsl #2

;r8=r8+ r9<<2 r9<<2(乘4),4字节对齐

ldr r8,[r8] str r8,[sp,#8]

;取[r8]地址的数据放入R8,加载中断服务函数地址到r8 ;将R8中的数据放入[sp+8]的地址中,保存到sp,作为新的

;PC

;=================================== ; ENTRY

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

ldmfd

sp!,{r8-r9,pc} ;将堆栈内空恢复到 R8 R9 PC,跳转到新的PC运行

;板子上电和复位后 程序开始从位于0x0执行,b ResetHandler 程序从跳转到这 ;里执行

;板子上电复位后 执行几个步骤。 ;1.禁止看门狗 屏蔽所有中断

;初始化程序入口指令

ResetHandler ;复位处理程式

ldr r0,=WTCON ; watch dog disable 关闭看门狗 ldr r1,=0x0

str r1,[r0] ;r1->[r0] 禁止看门狗

ldr r0, =0x300 ldr r1, [r0] b

%B1

;1 ; ;

ldr r0,=INTMSK ldr r1,=0xffffffff

;all interrupt disable,关中断,全部置1

str r1,[r0] ;r1->[r0] 禁止所有中断

ldr r0,=INTSUBMSK ldr r1,=0x7ff str r1,[r0]

;all sub interrupt disable, 关所有子中断

;测试外部LED等

[ {FALSE}

;if

; rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);

; Led_Display

ldr r0,=GPFCON ;F口控制寄存器 ldr r1,=0x5500 str r1,[r0]

ldr r0,=GPFDAT ;F口数据寄存器 ldr r1,=0x10 str r1,[r0] ]

;2.根据工作频率设置pll ,设置ARM主时钟频率 ;计算公式

;Fpllo=(m*Fin)/(p*2^s) ;m=MDIV+8,p=PDIV+2,s=SDIV ;Fpllo必须大于20Mhz小于66Mhz ;Fpllo*2^s必须小于170Mhz

;To reduce PLL lock time, adjust the LOCKTIME register.

ldr r0,=LOCKTIME ldr r1,=0xffffff str r1,[r0]

;Check if the boot is caused by the wake-up from POWER_OFF mode. ldr r1,=GSTATUS2 ; GSTATUS2 复位状态寄存器 ldr r0,[r1] tst r0,#0x2

;判断R0 的第二位是否为0

[ PLL_ON_START

;Configure MPLL

ldr r0,=MPLLCON

ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=12MHz,Fout=50MHz str r1,[r0] ]

;In case of the wake-up from POWER_OFF mode, go to POWER_OFF_WAKEUP ;handler.

EXPORT StartPointAfterPowerOffWakeUp ;声明全局函数 nop;bne WAKEUP_POWER_OFF

StartPointAfterPowerOffWakeUp

;3.置存储相关寄存器的程序

;设置存储器控制寄存器。

;是设置SDRAM,flash ROM 存储器连接和工作时序的程序,片选定义的程序 ;SMRDATA map在下面的程序中定义

;Set memory control registers

ldr r0,=SMRDATA

ldr r1,=BWSCON ;BWSCON Address ;BWSCON Address 起始位置依次为BANKCON0

;BANKCON1 BANKCON2 ........

add r2, r0, #52

;End address of SMRDATA 一共13个寄存器

0

ldr r3, [r0], #4 ;读取R0地址的数据到R3,R0=R0+4 读取SMRDATA 数组 (BWSCON

BANKCON0 ....)的值

str r3, [r1], #4 ;读取R3的数据到 R1地址内存中 R1=R1+4 赋给BWSON

BANKCON0 ....寄存器

cmp r2, r0

bne %B0 ;禁止Icache和Dcache,禁止MMU ;IMPORT MMU_DisableICache

;bl MMU_DisableICache ;

;IMPORT MMU_DisableDCache

;bl MMU_DisableDCache ; ;IMPORT MMU_InvalidateICache ;bl MMU_InvalidateICache ;

;IMPORT MMU_DisableMMU

;bl MMU_DisableMMU ;

;初始化堆栈 ;Initialize stacks

bl

InitStacks

;4.建立IRQ中断 ; 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]

;5.复制和初始化RW和ZI区域

adr r0, ResetEntry ;adr也是取值,但这时程序在哪运行就取那时的地址 ldr r2, BaseOfROM cmp r0, r2 ldreq

r0, TopOfROM

beq InitRam ldr r3, TopOfROM

;将RO区域的代码copy到RW域中并且将ZI区域初始化为0。

;6.将数据段拷贝到ram中 将零初始化数据段清零,跳入C语言的main函数执行到这步结束bootloader初步引导结束

0

ldmia stmia

r0!, {r4-r7} r2!, {r4-r7}

cmp r2, r3 bcc %B0

sub r2, r2, r3 sub r0, r0, r2

InitRam ;将RW内容从FLASH拷贝到SDRAM 0

cmp r2, r3

;copy 初始化代码

ldr r2, BaseOfBSS ldr r3, BaseOfZero

ldrcc r1, [r0], #4 ;没有设置C标志位的时候执行,即无符号数小于 strcc r1, [r2], #4 bcc %B0

;ZI段全部清零 1

[ :LNOT:THUMBCODE

bl

Main

;将THUMBCODE 做逻辑非操作

mov r0, #0 ;初始化ZI区域为0 ldr r3, EndOfBSS

cmp r2, r3 strcc r0, [r2], #4 bcc %B1

; Don't use main() because ...... 转入C程序

;bl LEDTEST ]

[ THUMBCODE ;for start-up code for Thumb mode ]

orr lr,pc,#1 bx lr CODE16 bl b

Main .

; Don't use main() because ...... 转入C程序

b

. ;死循环

CODE32

;堆栈初始化

;这是上面提到的对存储寄存器初始化的数据map ;function initializing stacks InitStacks

orr r1,r0,#IRQMODE|NOINT msr cpsr_cxsf,r1 ldr sp,=IRQStack

;IRQMode

;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 ;r0<-cpsr

bic r0,r0,#MODEMASK ;MODEMASK=0x1f 清除CPSR中的PSR位(5bit) orr r1,r0,#UNDEFMODE|NOINT ;NOINT=0XC0 禁止IRQ和FIQ中断 msr cpsr_cxsf,r1

;UndefMode cpsr_cxsf<-r1

ldr sp,=UndefStack

orr r1,r0,#ABORTMODE|NOINT msr cpsr_cxsf,r1

;AbortMode

ldr sp,=AbortStack

bic r0,r0,#MODEMASK|NOINT orr r1,r0,#SVCMODE msr cpsr_cxsf,r1

;SVCMode

orr r1,r0,#FIQMODE|NOINT msr cpsr_cxsf,r1 ldr sp,=FIQStack

;FIQMode

ldr sp,=SVCStack

;USER mode has not be initialized. 用户模式不初始化堆栈

mov pc,lr

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

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)) ; BWSCON=0x2211D110定义BWSCON

DCD

((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ;GCS0 BANK0CON=0x0700定义BANKCON0,下同

DCD

((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1 BANKCON1=0x7FFC

DCD

((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2 BANKCON2=0x0700

DCD

((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3 BANKCON3=0x0700

DCD

((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4 BANKCON4=0x0700

DCD

((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5 BANKCON5=0x0700 ; ;

;这里将中断异常向量建立在sdram中 ;可读写的数据段

AREA RamData, DATA, READWRITE ;异常中断向量(矢量)

ALIGN ;通过添加补丁字节使当前位置满足一定的对齐方式,声明字对齐 DCD 0x30 ;MRSR6 CL=3clk ;Mode register set for SDRAM DCD 0x30 ;MRSR7 ;Mode register set for SDRAM DCD 0x20 ;MRSR6 CL=2clk DCD 0x20 ;MRSR7

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

DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6 BANKCON6=0x18005 DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7 BANKCON7=0x18005 DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) ;REFR

ESH ;REFRESH=0x008E0459 DRAM/SDRAM refresh 设置刷新周期

^ _ISR_STARTADDRESS

^=MAP:定义一个结构化的内存表(storage map)的首地址,地址为0x33ff8000

HandleReset # 4 ; #--Field:定义一个结构化内存表中的数据域,该域为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

HandleEINT0 # 4 HandleEINT1 # 4 HandleEINT2 # 4 HandleEINT3 # 4 HandleEINT4_7

# 4

HandleEINT8_23 # 4 HandleRSV6 # 4 HandleBATFLT # 4 HandleTICK HandleWDT HandleTIMER0 HandleTIMER1 HandleTIMER2 HandleTIMER3 HandleTIMER4 HandleUART2 HandleLCD

# 4 # 4 # 4 # 4 # 4 # 4 # 4 # 4 # 4

HandleDMA0 # 4 HandleDMA1 HandleDMA2

# 4 # 4

HandleDMA3 HandleMMC HandleSPI0

# 4 # 4 # 4 # 4 # 4 # 4 # 4

HandleUART1 HandleRSV24 HandleUSBD HandleUSBH

HandleIIC # 4 HandleUART0 HandleSPI1 HandleRTC HandleADC

END

IRQ中断执行步骤:当出现一个IRQ中断时,首先执行b HandlerIRQ ,这是中断的入口指令,紧接着跳到标号为HandlerIRQ的语句上,即HandlerIRQ HANDLER HandleIRQ,根据上面的HANDLER宏定义,程序被这样执行 HandlerIRQ

sub sp,sp,#4 ;decrement sp(to store jump address) stmfd

sp!,{r0} ;PUSH the work register to stack

# 4 # 4 # 4 # 4

ldr r0,= HandleIRQ;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)

这样执行仍然缺一个参数HandleIRQ,根据程序最后的中断向量表对其的定义HandleIRQ # 4 将其放入,但是这只是地址,需要确定的指向某个地方,否则就是空的,所以,在上电后执行这几行语句后,HandleIRQ变成了IsrIRQ的地址

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对应的程序。即以下程序: IsrIRQ

sub sp,sp,#4 ; stmfd

sp!,{r8-r9} ;

ldr r9,=INTOFFSET ldr r9,[r9];

ldr r8,=HandleEINT0; add r8,r8,r9,lsl #2;r8=r8+r9*4 ldr r8,[r8]; str r8,[sp,#8]; ldmfd

sp!,{r8-r9,pc};

执行完上面程序后,中断源就被判别出来,其对应的中断服务程序入口地址就被装载到PC里面,开始执行该中断服务程序。

五、实验总结:

在本次试验中主要是对S3C2410 启动代码进行了分析,理解s3c2410的启动过程的执行顺序,了解S3C2410初始化过程。对以后arm硬件程序的编写奠定了基础。

因篇幅问题不能全部显示,请点此查看更多更全内容