关于ARM loader的一些心得Word格式文档下载.docx

上传人:b****3 文档编号:17347470 上传时间:2022-12-01 格式:DOCX 页数:11 大小:25.04KB
下载 相关 举报
关于ARM loader的一些心得Word格式文档下载.docx_第1页
第1页 / 共11页
关于ARM loader的一些心得Word格式文档下载.docx_第2页
第2页 / 共11页
关于ARM loader的一些心得Word格式文档下载.docx_第3页
第3页 / 共11页
关于ARM loader的一些心得Word格式文档下载.docx_第4页
第4页 / 共11页
关于ARM loader的一些心得Word格式文档下载.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

关于ARM loader的一些心得Word格式文档下载.docx

《关于ARM loader的一些心得Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《关于ARM loader的一些心得Word格式文档下载.docx(11页珍藏版)》请在冰豆网上搜索。

关于ARM loader的一些心得Word格式文档下载.docx

变量的初始化.

变量的初始化是个什么样的概念呢?

举个简单的例子,如果你程序里有个变量这样定义(这是不可能避免的吧):

uchari=5;

main()

{

}

就是说,i这个变量,初始值是5,具体反映到硬件上面,就是说,i这个变量所对应的内存单元,它在相应程序要执行之前,这个内存单元里保存的数值应该是5.否则,这个内存单元保存的是上电时硬件随机产生的不确定数值.

自己来做变量初始化的工作,其实不是必要的,而仅仅是当使用的编译器是ADS,才是必要的.如果使用的是其他编译器,有可能不用做这步.譬如Keil的编译器在链接成最终代码时,会自动添加一段变量初始化的代码,而GCC编译器记得也是这样.现在用的编译器是ADS。

因此,很遗憾,loader又得复杂一点点了,新的列表如下:

3.在内存里建立异常中断向量表,并在loader实现查表功能

4.初始化变量

这四步做完,确实可以一马平川了,但如果你想独步天下,还需要做得更好.作为一个编程人员,通常都是完美主义者,偏执狂,所追求的是无止境的效率和自由,我想很少有人会拒绝耍一些提高程序效率的手段吧?

于是下面可以再多了一个步骤,但这个功能对KS8695来说其实不是必需的(因为KS8695用的是NORflash,允许单字节随机访问,代码可以在NORflash里执行,但对于别的ARM芯片,如果用的是NANDflash,由于不支持单字节读以及随机地址访问,则必须把代码拷贝到RAM里,从RAM里执行),只是让我们的代码跑得更快.这个功能是:

把代码在放在RAM里执行.

对于51核这些微控制器(题外话,广义嵌入式有两种,一种是MCU,Microcontrolunit,叫微控制器,特点是运算速度比较慢,偏重于对运算速度要求不高而用于逻辑控制的场合,另外的就是MPU,Microprocessunit,叫微处理器,特点是处理数据能力非常强,专用于对数据处理要求较高的场合)来说,由于它的应用场合往往对速度要求不高,因此,并没有设计成代码可以在RAM执行的结构,也就是说,对标准的51核来说,它的代码全部都是存放在ROM里,每个指令要执行时,先从ROM里取指(读取指令),然后解释执行.而ARM是微处理器,往往用于数据处理场合,对程序效率要求很敏感,因此ARM核都设计成可以从ROM里读取指令运行也可以从RAM里读取指令运行的结构,它的PC指针如果指向的地址是ROM范围内的地址,那么读取的指令就是ROM里的指令,如果指向的是RAM范围,那么读取的指令就是存放在RAM里的.众所周知,RAM的读取速度比FLASH快很多。

KS8695包括很多ARM核的MPU,他们的中断入口都是放在前端靠近0地址的地方,而中断处理往往是非常频繁的,这里的代码被访问率非常高,因此,如果能把中断处理甚至整个执行程序的代码都拷贝到RAM里并在RAM里执行,无疑会大大提高代码的执行效率.在通常的loader设计里,强烈建议至少把中断向量表相关拷贝到内存里,然后使用MMU或其他类型的映射功能,把内存里的中断向量表映射到0地址开头的地址。

ARM里要完成这项工作通常有两个步骤:

第一,把ROM里的代码拷贝到RAM里去,第二,把PC指针指向RAM里的相应地址,让代码从RAM里读取执行.第一步几乎所有的ARMloader都差不多,但读取的是norflash还是nandflash,还是有分别的,如果存放代码的是NORFLASH,可以以字节为单位拷贝代码放到RAM里,如果是nandflash,就要按flash的参数,以block为单位读取放到ram里去.而对于第二步,在上述做完拷贝后,直接把PC置成RAM里存放执行代码的所在地址就OK了。

最后步骤归纳如下:

5.拷贝代码到RAM里,让代码在RAM里执行

 

下面是loader的代码,已经包括了上面提到的步骤,另外还掺加了一些额外的硬件初始化步骤,注释已经够详细,不想再多说:

;

************************************************************************************************

Entry:

0x0000,0000

************************************************************************************************ 

INCLUDEmem.inc

INCLUDEcasia.inc

IMPORTMain

IMPORT|Image$$RO$$Base|;

/*RO代码段起始地址*/

IMPORT|Image$$RO$$Limit|;

/*RO代码段结束地址*/

IMPORT|Image$$RW$$Base|;

/*RW代码段起始地址*/

IMPORT|Image$$RW$$Limit|;

/*RW代码段结束地址*/

IMPORT|Image$$ZI$$Base|;

/*ZI代码段起始地址*/

IMPORT|Image$$ZI$$Limit|;

/*ZI代码段结束地址*/

关于各种模式处理的宏定义,因为进入各种模式时必须保存原现场(pc值及会被影响的寄存器),这保护工作对于所有模式都是一样的代码,因此用一宏定义代替。

MACRO

$HandlerLabelHANDLER$HandleLabel

$HandlerLabel

subsp,sp,#4;

decrementsp(tostorejumpaddress)

stmfdsp!

{r0};

PUSHtheworkregistertostack(lrdoesnotpushbecauseitreturntooriginaladdress)

ldrr0,=$HandleLabel;

loadtheaddressofHandleXXXtor0

ldrr0,[r0];

loadthecontents(serviceroutinestartaddress)ofHandleXXX

strr0,[sp,#4];

storethecontents(ISR)ofHandleXXXtostack

ldmfdsp!

{r0,pc};

POPtheworkregisterandpc(jumptoISR)

MEND

AREAInit,CODE,READONLY

ENTRY

Image$$RO$$BaseDCD|Image$$RO$$Base|

Image$$RO$$LimitDCD|Image$$RO$$Limit|

Image$$RW$$BaseDCD|Image$$RW$$Base|

Image$$RW$$LimitDCD|Image$$RW$$Limit|

Image$$ZI$$BaseDCD|Image$$ZI$$Base|

Image$$ZI$$LimitDCD|Image$$ZI$$Limit|

=======

ENTRY 

0地址开始的执行代码,应该是各种模式的跳转代码,包括中断跳转 

bResetHandler 

bHandlerUndef;

handlerforUndefinedmode

bHandlerSWI;

handlerforSWIinterrupt

bHandlerPabort;

handlerforPAbort

bHandlerDabort;

handlerforDAbort

b.;

reserved

bHandlerIRQ;

handlerforIRQinterrupt 

bHandlerFIQ;

handlerforFIQinterrupt

HandlerFIQHANDLERHandleFIQ;

这里的HANDLER为前面的MICRO宏定义

HandlerIRQHANDLERHandleIRQ

HandlerUndefHANDLERHandleUndef

HandlerSWIHANDLERHandleSWI

HandlerDabortHANDLERHandleDabort

HandlerPabortHANDLERHandlePabort 

中断向量表查表程序,下面的中断服务里会调用到。

ARM922T核的不是向量中断,也无法设置成向量中断模式,只能自己建立中断向量表,自己处理中断跳转 

IsrIRQ 

reservedforPC

{r8-r9} 

ldrr9,=REG_IRQ_PEND_PRIORITY 

ldrr9,[r9];

读取优先级最高的中断标志,看现在最需要处理的中断是哪个

ldrr8,=REG_INT_STATUS;

ldrr8,[r8];

读取所有的中断标志

andr9,r8,r9;

相与,结果存放在r9

ldrr8,=HandleCCR;

最开始的中断服务程序入口存放变量,其他的中断服务程序入口存放变量都是以这个为开始递增的

isrloop;

通过中断标志,计算该中断的服务程序入口

cmpr9,#0

beqisrquit;

如果为零表示中断已经撤销,退出

cmpr9,#1;

是否为1

beqisrcontinue;

是1则退出循环右移

movr9,r9,lsr#1;

r9右移1

addr8,r8,#4;

r8+4,每个中断服务程序入口地址占4个字节,因此每次要递增4个

bisrloop

isrcontinue 

获取相应的中断程序入口地址

strr8,[sp,#8]

{r8-r9,pc};

把中断程序入口地址置入pc,程序跳入对应的中断服务程序

isrquit

{r8-r9};

恢复r8跟r9

addsp,sp,#4;

恢复sp指针

subspc,r14,#4;

读取原先的pc值(保存在此模式下的r14)并返回,包括返回原先模式,这里必须要用subs指令,否则不能返回原工作模式

ResetHandler

第一步,最初的初始化程序开始,首先应该是关中断,关看门狗,因为看门狗跟中断在现阶段会给你带来不可预知的错误,完全没必要打开

特别留意的是,某些ARM核默认是开看门狗的,下面提到的上电后默认情况仅指KS8695这个CPU

ks8695的所有系统寄存器,都是位于0x03ffxxxx地址

LDRR1,=0x3ffe408;

关闭看门狗,默认已经关闭,可不做此步

LDRR0,=0xffffff00

STRR0,[R1]

LDRR1,=0x3ffe200;

定义中断模式,所有中断为IRQ中断,非FIQ类型,上电后默认为全IRQ,可不做此步

LDRR0,=0x00000000

LDRR1,=0x3ffe204;

禁止所有中断,免得中断对初始化工作造成影响,此步不做也行,默认上电后是禁止所有中断的

LDRR1,=0x3ff4000;

LDRR0,=0xD7F20008

LDRR1,=0x3ff4008;

LDRR0,=0x0

第二步初始化,先把flash映射到0~0x001fffff,初始化SDRAM,把SDRAM映射到0x02000000到0x027fffff

ks8695上电后默认仅有flash地址,无SDRAM,也没有给SDRAM分配地址,因此必须得初始化SDRAM并映射好,否则就没有RAM用

映射时映射的地址别覆盖掉系统寄存器区,也就是0x03ffxxxx区

LDRR1,=0x3ff4010;

FLASHBANK0控制寄存器,映射FLASH地址为0X00000000到0X001fffff,共2M大小,普通ROM模式 

LDRR0,=((0x1f:

SHL:

22)+(0:

12)+0x70);

末地址10位+首地址10位+其他参数

LDRR1,=0x3ff4038;

SDRAMRASCAS参数

LDRR0,=0x0000000a

LDRR1,=0x3ff403c;

SDRAM缓冲控制寄存器

LDRR0,=0x20033

LDRR1,=0x3ff4040;

SDRAM刷新参数

LDRR0,=0x00000168

LDRR1,=0x3ff4030;

SDRAMBANK0控制器寄存器,映射RAM地址为0x02000000到0x027fffff,2banks,32BIT,8M

LDRR0,=((0x27f:

22)+(0x200:

12)+0x0e);

第三步,把所有代码拷贝到SDRAM里去,注意,现阶段的SDRAM的访问地址是从0x02000000开始的

r0=sourceaddress

r1=targetaddress

r2=sourceendaddress

ldrr1,=0x02000000

ldrr0,=0x00000000 

ldrr2,=|Image$$ZI$$Base|;

计算flash区里需要拷贝到RAM的0地址开始的代码长度,也就是ro+rw那段

ldrr3,=|Image$$RW$$Base|

subr2,r2,r3;

rw段长度=zibase-rwbase

ldrr3,=|Image$$RO$$Limit|

addr2,r2,r3

copy_ro_loop

ldmiar0!

{r3-r10};

每次拷贝8个byte,依次放入r3到r10寄存器

stmiar1!

每次依次写入8个byte到目的地址

cmpr0,r2

blecopy_ro_loop;

少于或等于时都跳,大于时继续

第四步,下面准备重新把SDRAM映射到0~0x007f,ffff,8m,把flash映射到0x01000000~0x011f,ffff,2m

这步工作的好处是,映射内存到0地址后,这样无需使用MMU的映射

因为整个代码已经拷贝到SDRAM里,即使是发生中断,中断入口也是在SDRAM里,直接从SDRAM里执行代码,执行效率非常高

先把各个入口地址保存好,必须先把地址先存好在寄存器里,由于remap容易造成地址失效,如果不预先保存在寄存器

而是保存在flash存储或者sdram存储里,remap后地址变了,从存储器读取到的返回地址就不是计划中的地址了

ldrr3,=(remap_rom+0x02000000)

ldrr4,=(remap_ram+0x01000000)

ldrr2,=continue

把pc指向高端地址,也就是现在的SDRAM内存,跳到内存里,由于内存里已经有一份FLASH的完整拷贝,因此得以继续执行程序

这是因为下面要做flash的remap,必须先跳到内存里执行后面的代码,否则一remap,pc指向的下一指令就不存在,跑飞了

movpc,r3

下面这段代码其实已经是在SDRAM里执行,把FLASH地址映射到高端上去,好把低端地址腾出来给SDRAM用

remap_rom

FLASHBANK0控制寄存器,映射FLASH地址为0x0100,0000到0x011f,ffff,共2M大小,普通ROM模式 

LDRR0,=((0x11f:

22)+(0x100:

12)+0x70)

同理,必须跳回刚remap好的flash里继续执行代码,然后才能对SDRAM进行remap

movpc,r4;

这指令还是在SDRAM里执行,这指令的后面指令,已经是在FLASH里了

下面这段代码其实已经是在FLASH里执行 

remap_ram

SDRAMBANK0控制器寄存器,映射RAM地址为0x0000,0000到0x007f,ffff,2banks,32BIT,8M

LDRR0,=((0x7f:

22)+(0x0:

12)+0x0e)

STRR0,[R1] 

做完SDRAMremap后,就直接跳回低端地址执行,低端地址现在已经是SDRAM区了

movpc,r2;

这指令还是在flash里执行,这指令的后一指令,已经是在SDRAM里了

上面代码执行完后,下面的代码已经在RAM里执行了

因为上面的代码已经把SDRAM映射到0地址开始的地方,而此时的PC指针还是指向偏移0地址不远的地方,因此下一执行的指令地址还是在0地址不远的一个地方

此时,要执行的指令已经是在SDRAM的区域里了

continue

第五步,初始化各种模式所需要的堆栈,别忘了,经过上面几步映射后,我们的SDRAM有效范围是0~0x007f,ffff,定义的堆栈指针可不能超过这范围

而且也不能占据低地址0开始的一

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

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1