ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx

上传人:b****0 文档编号:9363970 上传时间:2023-05-18 格式:DOCX 页数:28 大小:22.46KB
下载 相关 举报
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第1页
第1页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第2页
第2页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第3页
第3页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第4页
第4页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第5页
第5页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第6页
第6页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第7页
第7页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第8页
第8页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第9页
第9页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第10页
第10页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第11页
第11页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第12页
第12页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第13页
第13页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第14页
第14页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第15页
第15页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第16页
第16页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第17页
第17页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第18页
第18页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第19页
第19页 / 共28页
ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx_第20页
第20页 / 共28页
亲,该文档总共28页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx

《ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx》由会员分享,可在线阅读,更多相关《ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx(28页珍藏版)》请在冰点文库上搜索。

ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行.docx

ARM9启动代码裸机版所谓启动代码就是处理器在启动的时候执行

 

ARM9启动代码(裸机版)

所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初

始化处理器模式,设置堆栈,初始化变量等等。

由于以上的操作均与处理器体系

结构和系统配置密切相关,所以一般由汇编来编写。

在一般32位ARM应用系统中,软件大多数采用c语言进行编程,并且以嵌入式操作系统为开发平台,这样就大大提高了开发效率和软件性能。

为了能够进行系统初始化,通常采用一个汇编文件作启动代码。

它可以实现向量表定义、堆栈初始化、系统变量初始化、中断系统初始化、I/O初始化、地址重映射等操作。

启动代码是芯片复位后进入c语言的main函数前执行的一段代码,主要是为运行c语言程序提供基本运行环境。

在实际应用中,为提高系统的实时性,加快代码的执行速度,系统启动后

程序往往要被搬移到RAM中,因为RAM的存取速度要比ROM快得多,这样大大提升系统的性能。

启动程序要完成的任务包括:

硬件初始化,系统存储系统的配置,

复制二级中断向量表。

启动程序大概过程如下:

(1)系统硬件初始化

系统上电或复位后,程序从位于地址0x0的ResetExceptionVector处开

始执行,因此需要在这里放置bootloader的第一条指令:

bReset,跳转到标号为Reset处进行第一阶段的硬件初始化,主要内容为:

关看门狗定时器,关中断,初始化PLL和时钟,初始化存储器系统。

执行完以上程序后,系统进行堆栈和存

 

储器的初始化。

系统堆栈初始化取决于用户使用了哪些中断,以及系统需要处理哪些错误类型。

一般情况下,管理者堆栈必须设置,如果使用了IRQ中断,则IRQ堆栈也必须设置。

如果系统使用了外设,则需要设置相关的寄存器,以确定

其刷新频率、总线宽度等信息。

(2)代码复制到RAM中运行

因为嵌入式系统的代码通常都是固化在ROM或Flash中,上电后开始运行。

由于ROM和Flash的读取速度相对较慢,这样无疑会降低代码的执行速度和系统的运行效率。

因此,需要把系统的代码复制到RAM中运行。

(3)建立二级中断向量表

在ARM系统中,中断向量表位于0x0开始的地址处,意味着无论运行什么样的上层软件,一旦发生中断,程序就得到Flash存储器的中断向量表里去,降低系统的运行效率。

因此在RAM中建立自己的二级中断向量表,当中断发生后,程序直接从RAM中取中断向量进入中断子程序。

(4)MMU的应用

MMU是存储器管理单元的缩写,是用来管理虚拟内存系统的器件。

MMU完成

的两个主要功能是:

将虚地址转换成物理地址,控制存储器存取允许。

MMU关掉时,虚地址直接输出到物理地址总线。

由于跑的是裸机,没有用到操作系统,以下启动代码不包含MMU的应用。

 

@下面是对arm处理器模式寄存器对应的常数进行赋值,arm处理器有一个CPSR

寄存器,

@它的后五位决定了处理器处于哪个模式下。

可以看出常数的定义都不会超过后

5位的。

*/

 

@Pre-definedconstants

.equ

USERMODE,

0x10

.equ

FIQMODE,

0x11

.equ

IRQMODE,

0x12

.equ

SVCMODE,

0x13

.equ

ABORTMODE,

0x17

.equ

UNDEFMODE,

0x1b

.equ

MODEMASK,

0x1f

.equ

NOINT,

0xc0

 

@各个异常模式的堆栈

@Thelocationofstacks

 

.equ

_STACK_BASEADDRESS,0x33ff8000

.equ

_ISR_STARTADDRESS,0x31ffff00

.equ

UserStack,

(_STACK_BASEADDRESS-0x3800)@0x33ff4800~

.equ

SVCStack,

(_STACK_BASEADDRESS-0x2800)@0x33ff5800~

.equ

UndefStack,

(_STACK_BASEADDRESS-0x2400)@0x33ff5c00~

.equ

AbortStack,

(_STACK_BASEADDRESS-0x2000)@0x33ff6000~

.equ

IRQStack,

(_STACK_BASEADDRESS-0x1000)@0x33ff7000~

.equ

FIQStack,

(_STACK_BASEADDRESS-0x0)@0x33ff8000~

.equ

INTMSK,

0x4a000008@Interruptmaskcontrol

.equ

INTSUBMSK,0x4a00001c

@Interruptsubmask

.equ

INTOFFSET,0x4a000014

@Interruotrequestsourceoffset

 

.macro

 

HANDLERHandleLabel

 

subsp,sp,#4@decrementsp(tostorejumpaddress)

stmfdsp!

{r0}@PUSHtheworkregistertostack(lrdoes

notpushbecauseitreturntooriginaladdress)

ldrr0,=\HandleLabel@loadtheaddressofHandleXXXtor0

 

ldrr0,[r0]

 

@load

 

the

 

contents(service

 

routine

startaddress)ofHandleXXX

strr0,[sp,#4]

@storethecontents(ISR)

ofHandleXXXto

stack

ldmfdsp!

{r0,pc}

@POPtheworkregisterandpc(jumpto

ISR)

.endm

 

.externmain

 

.text

.global_start

_start:

@********************************************************************

@中断向量

@********************************************************************

bReset

 

@0x04:

未定义指令中止模式的向量地址bHandlerUndef

 

@0x08:

管理模式的向量地址,通过SWI指令进入此模式bHandlerSWI

 

@0x0c:

指令预取终止导致的异常的向量地址

bHandlerPrefetchAbort

 

@0x10:

数据访问终止导致的异常的向量地址

cHandlerDataAbort

 

@0x14:

保留

dHandlerNotUsed

 

@0x18:

中断模式的向量地址

eHandlerIRQ

 

@0x1c:

快中断模式的向量地址

fHandlerFIQ

 

Reset:

ldrsp,=4096

@设置栈指针,以下都是

C函数,调用前需

要设好栈

bldisable_watch_dog

@关闭

WATCHDOG,否则

CPU会不断重启

 

ldrr0,=INTMSK

ldrr1,=0xffffffff

strr1,[r0]

 

@allinterruptdisable

ldrr0,=INTSUBMSK

ldrr1,=0x7fff

strr1,[r0]

 

@allsubinterruptdisable

 

blclock_init

blmemsetup

 

@设置MPLL,改变FCLK、HCLK、PCLK

@设置存储控制器以使用SDRAM

bls3c2440_nand_init

 

ldrr0,=0x30000000

 

@1.

 

目标地址

 

=0x30000000,这是

 

SDRAM的起

始地址

movr1,#4096

@2.

源地址

=4096

,运行地址在

SDRAM中

的代码保存在NANDFlash4096地址开始处

movr2,#180*1024@3.复制长度

 

=16K

 

,对于本实验,这是

足够了

blCopyCode2SDRAM

@调用

C函数

CopyCode2SDRAM

blclean_bss

@清除bss段,未初始化或初值为

0的全局/静

态变量保存在bss段

 

bl

 

InitStacks

 

@initalthestack

@SetupIRQhandler

ldrr0,=HandleIRQ

ldrr1,=IsrIRQ

0x1c

strr1,[r0]@

 

@Thisroutineisneeded

@ifthereisnot'subspc,lr,#4'at0x18,

 

这三条语句很明显就是说明了,HandleIRQ

 

个中断向量

@的存储单元被赋上了

IsrIRQ

标号的地址,这样

发生

IRQ中

@断后就会直接去到二级表,去确认具体发生哪

个中断。

 

ldrpc,=on_sdram

 

@跳到

 

SDRAM中继续执行

on_sdram:

msrcpsr_c,#0x5f

ldrsp,=0x34000000

ldrlr,=halt_loop

ldrpc,=main

@设置I-bit=0,开

@设置栈指针,

@设置返回地址

@调用main函数

IRQ中断

halt_loop:

bhalt_loop

 

HandlerFIQ:

HANDLER

HandleFIQ

HandlerIRQ:

HANDLER

HandleIRQ

HandlerUndef:

HANDLER

HandleUndef

 

HandlerSWI:

HANDLERHandleSWI

HandlerDataAbort:

HANDLERHandleDabort

HandlerPrefetchAbort:

HANDLERHandlePabort

HandlerNotUsed:

b.

 

InitStacks:

@DonotuseDRAM,suchasstmfd,ldmfd......

@SVCstackisinitializedbefore

@Undertoolkitver2.5,'msrcpsr,r1'canbeusedinsteadof'msrcpsr_cxsf,r1'

mrsr0,cpsr

bicr0,r0,#MODEMASK

orrr1,r0,#UNDEFMODE|NOINT

msrcpsr_c,r1@UndefMode

ldrsp,=UndefStack@UndefStack=0x33FF_5C00

 

orrr1,r0,#ABORTMODE|NOINT

msrcpsr_c,r1@AbortMode

ldrsp,=AbortStack@AbortStack=0x33FF_6000

 

orrr1,r0,#IRQMODE|NOINT

msrcpsr_c,r1@IRQMode

ldrsp,=IRQStack@IRQStack=0x33FF_7000

 

orrr1,r0,#FIQMODE|NOINT

msrcpsr_c,r1@FIQMode

ldrsp,=FIQStack@FIQStack=0x33FF_8000

 

bicr0,r0,#MODEMASK|NOINT

orrr1,r0,#SVCMODE

msrcpsr_c,r1@SVCMode

ldrsp,=SVCStack@SVCStack=0x33FF_5800

 

@USERmodehasnotbeinitialized.

 

movpc,lr

 

@theLRregisterwillnotbevalidifthecurrentmodeisnotSVCmode.

 

IsrIRQ:

sublr,lr,#4@

stmfdsp!

{r0-r12,lr}@

 

计算返回地址

保存使用到的寄存器

subsp,sp,#4

@reservedforPC;

保留

pc寄存器的值

stmfdsp!

{r8-r9}

@把r8r9

按入堆栈

ldrlr,=int_return

@

 

设置调用

ISR即

EINT_Handle函数后

的返回地址

 

ldrr9,=INTOFFSET

ldrr9,[r9]

ldrr8,=HandleEINT0

 

@把中断偏移INTOFFSET的地址装入

@取出INTOFFSET单元里面的值给r9

@向量表的入口地址赋给r8

 

r9

 

里面

addr8,r8,r9,lsl#2

@求出具体中断向量的地址

ldrr8,[r8]

@中断向量里面存储的中断服务程序的入口地址

赋给

r8

strr8,[sp,#8]

@按入堆栈

ldmfdsp!

{r8-r9,pc}

@堆栈弹出,跳转到相应的中断服务程序

int_return:

ldmfdsp!

{

r0-r12,pc

}^@

中断返回,^表示将

spsr

的值复制到

cpsr

.align4

 

.section.data

 

.equHandleReset,(_ISR_STARTADDRESS+0x0)

.equHandleUndef,(_ISR_STARTADDRESS+0x4)

.equHandleSWI,(_ISR_STARTADDRESS+0x8)

.equHandlePabort,(_ISR_STARTADDRESS+0xc)

.equHandleDabort,(_ISR_STARTADDRESS+0x10)

.equHandleReserved,(_ISR_STARTADDRESS+0x14)

.equHandleIRQ,(_ISR_STARTADDRESS+0x18)

.equHandleFIQ,(_ISR_STARTADDRESS+0x1c)

 

@Donotusethelabel'IntVectorTable',

@ThevalueofIntVectorTableisdifferentwiththeaddressyouthinkitmaybe.

 

@IntVectorTable

@0x33FF_FF20

.equHandleEINT0,(_ISR_STARTADDRESS+0x20)

.equHandleEINT1,(_ISR_STARTADDRESS+0x24)

.equHandleEINT2,(_ISR_STARTADDRESS+0x28)

.equHandleEINT3,(_ISR_STARTADDRESS+0x2c)

 

.equ

HandleEINT4_7,

(_ISR_STARTADDRESS+0x30)

.equ

HandleEINT8_23,(_ISR_STARTADDRESS+0x34)

.equ

HandleCAM,

(_ISR_STARTADDRESS+0x38)@Addedfor2440.

.equHandleBATFLT,(_ISR_STARTADDRESS+0x3c)

.equ

HandleTICK,

(_ISR_STARTADDRESS+0x40)

.equ

HandleWDT,(_ISR_STARTADDRESS+0x44)

.equ

HandleTIMER0,(_ISR_STARTADDRESS+0x48)

.equHandleTIMER1,(_ISR_STARTADDRESS+0x4c)

.equHandleTIMER2,(_ISR_STARTADDRESS+0x50)

.equHandleTIMER3,(_ISR_STARTADDRESS+0x54)

.equHandleTIMER4,(_ISR_STARTADDRESS+0x58)

.equ

HandleUART2,(_ISR_STARTADDRESS+0x5c)

@0x33FF_FF60

.equ

HandleLCD,

(_ISR_STARTADDRESS+0x60)

.equ

HandleDMA0,

(_ISR_STARTADDRESS+0x64)

.equ

HandleDMA1,

(_ISR_STARTADDRESS+0x68)

.equ

HandleDMA2,

(_ISR_STARTADDRESS+0x6c)

.equ

HandleDMA3,

(_ISR_STARTADDRESS+0x70)

.equ

HandleMMC,(_ISR_STARTADDRESS+0x74)

.equ

HandleSPI0,

(_ISR_STARTADDRESS+0x78)

.equ

HandleUART1,(_ISR_STARTADDRESS+0x7c)

.equ

HandleNFCON,(_ISR_STARTADDRESS+0x80)@Addedfor2440.

.equ

HandleUSBD,

(_ISR_STARTADDRESS+0x84)

.equ

HandleUSBH,

(_ISR_STARTADDRESS+0x88)

.equ

HandleIIC,

(_ISR_STARTADDRESS+0x8c)

.equHandleUART0,(_ISR_STARTADDRESS+0x90)

.equ

HandleSPI1,

(_ISR_STARTADDRESS+0x94)

.equ

HandleRTC,

(_ISR_STARTADDRESS+0x98)

.equ

HandleADC,

(_ISR_STARTADDRESS+0x9c)

 

以下部分是我们bootloader中调用到的c程序部分,主要是完成:

关看门狗、初始化存储器、初始化时钟、从Nandflash将代码拷贝到SDRAM、初始化数据段。

/*

*关闭WATCHDOG,否则CPU会不断重启

*/

voiddisable_watch_dog(void)

{

WTCON=0;//关闭WATCHDOG很简单,往这个寄存器写0即可

}

 

#defineS3C2410_MPLL_200MHZ((0x5c<<12)|(0x04<<4)|(0x00))

#defineS3C2440_MPLL_200MHZ((0x5c<<12)|(0x01<<4)|(0x02))

/*

*对于MPLLCON寄存器,[19:

12]为MDIV,[9:

4]为PDIV,[1:

0]为SDIV

*有如下计算公式:

*S3C2410:

MPLL(FCLK)=(m*Fin)/(p*2^s)

*S3C2410:

MPLL(FCLK)=(2*m*Fin)/(p*2^s)

*其中:

m=MDIV+8,p=PDIV+2,s=SDIV

*对于本开发板,Fin=12MHz

*设置CLKDIVN,令分频比为:

FCLK:

HCLK:

PCLK=1:

2:

4,

*FCLK=200MHz,HCLK=100MHz,PCLK=50MHz

*/

voidclock_init(void)

{

//LOCKTIME=0x00ffffff;//使用默认值即可

CLKDIVN=0x03;//FCLK:

HCLK:

PCLK=1:

2:

4,

HDIVN=1,PDIVN=1

 

/*如果HDIVN非0,CPU的总线模式应该从“fastbusmode”变为

“asynchronousbusmode”*/

__asm__(

"mrcp15,0,r1,c1,c0,0\n"/*读出控制寄存器*/

"orrr1,r1,#0xc0000000\n"/*设置为“asynchronous

busmode”*/

"mcrp15,0,r1,c1,c0,0\n"/*写入控制寄存器*/

);

 

/*判断是S3C2410还是S3C2440*/

if((GSTATUS1==0x32410000)||(GSTATUS1==0x32410002))

{

MPLLCON=S3C2410_MPLL_200MHZ;/*现在,

FCLK=200MHz,HCLK=100MHz,PCLK=50MHz*/

}

else

{

MPLLCON=S3C2440_MPLL_200MHZ;/*现在,

FCLK=200MHz,HCLK=100MHz,PCLK=50MHz*/

}

}

 

//设置存储控制器以使用SDRAM

 

#defineMEM_CTL_BASE0x48000000//存储器控制器寄存器的起始地

 

#defineSDRAM_BASE0x30000000

 

voidmemsetup(void)

{

volatileunsignedlong*p=(volatileunsignedlong*)MEM_CTL_BASE;

 

/*

 

这个函数之所以这样赋值,而不是像前面的实验

 

(比如

 

mmu实验)那样将

配置值

*写在数组中,是因为要生成

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2