由ADS生成的代码的标号是以设置的RO为基准的,也就是说CopyProcBeg是RAM中的一个地址 。(这解释无敌了)boot烧在0位置 整个代码绝对的起始位置(绝对地址)都是以RO开始的 即entry位置开始,所有偏移都是相对于它的,而开始boot烧在0X0处却可运行是因为,搬运代码函数之前代码与实际用不到太多有实际作用的地址,可以用普通偏移解决,而JLINK仿真开始为止和设定位置相等这个设置对代码烧入FLASH以后的分布没有关系。只是把code和data分段了一下.
3楼: | >>参与讨论 |
作者: sklar 于 2007-4-26 16:54:00 发布:
呵呵,进来的都发表下看法吧 知道的说下,不清楚的也把自己的看法说说吧,大家交流啊,楼上的用什么ARM板?我用的是立YU泰的44B0 |
4楼: | >>参与讨论 |
作者: luhuaren 于 2007-4-26 17:15:00 发布:
re RO Base设置为0xc000000 RW Base设置为0xc5f0000,可是BIOS不是要放0X0000000的吗 注意:如果是用44B0,那么44B0上电复位后PC的值是0, AREA Init,CODE,READONLY ENTRY ResetEntry b ResetHandler ;for debug b HandlerUndef ;handlerUndef b HandlerSWI ;SWI interrupt handler b HandlerPabort ;handlerPAbort b HandlerDabort ;handlerDAbort b . ;handlerReserved b HandlerIRQ b HandlerFIQ 系统上电后第一条指令执行的是b ResetHandler (在0地址处)这是一条相对跳转指令,也就是说,这条指令和RO的设置无关 跳转到ResetHandler处,进行一些初始化动作后,就要进行代码拷贝,就是把FLASH里的代码拷贝到RO指定的地址处,代码拷贝是这样实现的: ;**************************************************** ;拷贝并粘贴 RW data/zero initialized data * ;**************************************************** adr r0, ResetEntry ldr r1,BaseOfROM cmp r0,r1 ldreq r0, TopOfROM beq InitRamData ;**************************************************** ;计算拷贝程序在FLASH中的实际位置 * ;**************************************************** ldr r2,=CopyProcBeg sub r1, r2, r1;r2-r1->r1 add r0, r0, r1 ldr r3,=CopyProcEnd ;**************************************************** ;将拷贝程序复制到ram中 * ;**************************************************** 0 ldmia r0!, {r4-r7} stmia r2!, {r4-r7} cmp r2, r3 bcc %B0 ;******************************************************** ;开始用ram中的拷贝程序复本将所有剩下的代码复制到ram中 * ;******************************************************** ldr r3, TopOfROM ;ldr pc, =CopyProcBeg ;装入绝对地址(指到RAM中去的) b CopyProcBeg ;******************************************************** ;本段将代码由实际烧入的地址拷贝到ro-base所指定的位置 * ;只拷贝CopyProcEnd以后的代码 ;******************************************************** CopyProcBeg 0 ldmia r0!, {r4-r11} stmia r2!, {r4-r11} cmp r2, r3 bcc %B0 CopyProcEnd sub r1, r2, r3 sub r0, r0, r1 InitRamData ldr r2, BaseOfBSS ldr r3, BaseOfZero 0 cmp r2, r3 ldrcc r1, [r0], #4 strcc r1, [r2], #4 bcc %B0 mov r0, #0 ldr r3, EndOfBSS 1 cmp r2, r3 strcc r0, [r2], #4 bcc %B1 ;=================================================================== adr r0, ResetEntry ldr r1,BaseOfROM cmp r0,r1 请注意这几条语句,尤其是adr r0, ResetEntry,这条语句当你反汇编后发现是一条这样的指令 ;[0xe24f0f5d] sub r0,pc,#0x174 ; #0xc008000 也是一条与位置无关的指令,ResetEntry的值同PC的值相关联, 当然,PC一上电的值为0,所以这里ResetEntry的值也为0,所以 ldr r1,BaseOfROM cmp r0,r1 比较的结果就是R0 != R1于是进行代码拷贝,将复制程序拷贝完后,就可以跳转到RAM中去,执 |
5楼: | >>参与讨论 |
作者: luhuaren 于 2007-4-26 17:20:00 发布:
RE 可以下在U-BOOT的源码看一下,感觉很多开发板上流行的BOOT代码都是从U-BOOT上改过来的 |
6楼: | >>参与讨论 |
作者: pigjiang 于 2007-4-27 8:46:00 发布:
有个疑问 IMPORT |Image$$RO$$Base| ; ROM code start IMPORT |Image$$RO$$Limit| ; RAM data starts after ROM program IMPORT |Image$$RW$$Base| ; Pre-initialised variables IMPORT |Image$$ZI$$Base| ; uninitialised variables IMPORT |Image$$ZI$$Limit| ; End of variable RAM space =============================================== 这几行的||里面的标号是从哪里获得的? 他们是不是就是设置linker的OUTPUT选项里面填入的RO和RW的值? |
7楼: | >>参与讨论 |
作者: wowow 于 2007-4-27 9:58:00 发布:
RO/RW RO/RW地址在debug/release设置不同的值,一个用于仿真器加载到ram运行,一个用于FLASH中运行。如果你用了中断,并且ARM不支持REMAP,调ram程序时FLASH里必须也烧进中断向量表。 |Image$$RO$$Base| 之类是linker生成的,但有些情况下不生成。最好自己读一读关于linker的pdf |
8楼: | >>参与讨论 |
作者: sklar 于 2007-4-27 12:28:00 发布:
to luhuaren 你的这些代码我在44Binit.S文件里没有,不过有点懂你说的意思了,ADS里设置的这些地址就是把代码考到SDRAM里的地址? adr r0, ResetEntry ldr r1,BaseOfROM cmp r0,r1 //??这里没怎么没说跳到哪里? |
9楼: | >>参与讨论 |
作者: luhuaren 于 2007-4-27 15:02:00 发布:
re 当然,PC一上电的值为0,所以这里ResetEntry的值也为0; 不好意思,这句话写的不对..........ResetEntry的值得应该是|Image$$RO$$Base| 如果RO的值和你程序烧录起始地址的值不同,(如:你设置的RO=0xc000000,注意这个地址是在指向RAM,而你烧录的代码是在0地址处),这样就需要你烧录在0地址开始处的一小部分启动代码把程序从烧录地址搬运到RO设置的地址中去,但要注意,连接器为你连接的地址是以RO为基准的,这样你可能会有个疑问,为什么程序的运行域是以RO(0xc000000)为基准,但处于FLASH(0地址开始)里的一小部分启动代码还能运行呢,这就是因为程序中用了与地址无关的指令,使得一上电,能够顺利的执行0地址处的启动代码 注意 ENTRY ResetEntry b ResetHandler ;for debug 这条指令并不是跳转到RO处,它还是跳到了FLASH里, 再注意以下几句 adr r0, ResetEntry 这里并不是把真正的ResetEntry的值装入了R0,其实装入R0的值是0,可以看看反汇编,你自然明白 ldr r1,BaseOfROM cmp r0,r1 想必应该可以理解了,如果再不理解,那建议多看看书. |
10楼: | >>参与讨论 |
作者: sklar 于 2007-4-27 16:09:00 发布:
收了 恩,还得多看了! |
11楼: | >>参与讨论 |
作者: 时宗 于 2007-4-27 19:21:00 发布:
参考一下CPU datasheet 以2410/2440为例:SDRAM 一般用的是CPU的BANK6和BANK7(各64M),从BANK0到BANK6正好是0X30000000也就是所谓的0地址ResetEntry。 |
12楼: | >>参与讨论 |
作者: luhuaren 于 2007-4-27 19:56:00 发布:
RE 没搞懂楼上的说的意思。 |
13楼: | >>参与讨论 |
作者: sklar 于 2007-4-27 21:22:00 发布:
11楼可以详细点吗 呵呵,11楼说的我也不明白! 期待详细点! |
14楼: | >>参与讨论 |
作者: pigjiang 于 2007-4-27 22:20:00 发布:
to luhuaren还有个疑问 ;**************************************************** ;计算拷贝程序在FLASH中的实际位置 * ;**************************************************** -->ldr r2,=CopyProcBeg sub r1, r2, r1;r2-r1->r1 add r0, r0, r1 ldr r3,=CopyProcEnd 如你所说,前面比较r0和r1结果自然是不等,所以直接运行到这里来了。 请问:CopyProcBeg 是44binit.s里面的一个标号,它所代表的地址到底应该是在FLASH里还是在ram里?如果在FLASH里,那么r2应该小于r1,因为r1=BaseOfROM,那么sub r1, r2, r1这个减法是不是有问题? 主要是觉得这个时候标号CopyProcBeg 应该是在FLASH里的某一个地址。 今天看了一天这段代码也没明白,谢谢指点! |
15楼: | >>参与讨论 |
作者: luhuaren 于 2007-4-27 22:51:00 发布:
RE ldr r2,=CopyProcBeg 注意用的是LDR指令 由ADS生成的代码的标号是以设置的RO为基准的,也就是说CopyProcBeg是RAM中的一个地址 。(这解释无敌了) 但是如果你用ADR r2,=CopyProcBeg 这条指令就不一样了,具体怎么不一样,看看指令的解释,但很多地方只是一笔带过,没有很详细的解释,我是看了汇编后代码才明白的 它会生成一条类似下面的指令 sub r0,pc,#0x174 ; #0xc008000 以上我理解的应该没有错误,因为我已经在板子上验证过。 在我不理解这些的时候,到网上搜索过很多资料,但是没有谁确切的解释过这些东东,后来等我弄明白了以后,在LINUX论坛上发现有讨论U-BOOT的帖子对这些做了很明确的解释。 为什么程序的运行域和加载域不同,但启动代码还能在加载域运行,并将加载域的代码拷贝到运行域中去,然后将PC指到运行域中去,在运行域中执行代码,可能是每一个初学者看启动代码时最难理解的地方。理解了这些,其他的,都相对好弄一些/ |
16楼: | >>参与讨论 |
作者: pigjiang 于 2007-4-28 11:09:00 发布:
谢谢luhuaren的解释。 还需进一步参透:) |
17楼: | >>参与讨论 |
作者: 瑶瑶 于 2007-9-3 10:08:11 发布:
可是为什么我把RObase的地址设置为0x0000时,运行程序时总是发生重启的现象的,都没有运行到我的应用程序,就连开发板中提供的ucos276版本的软件都会有这个问题, 不知道上面的大侠有没有遇到过这个问题,该如何解决?(改成0x0c008000就没有问题了)
|
18楼: | >>参与讨论 |
作者: saga 于 2008-4-16 18:54:06 发布:
to yaoyao 前面要留出0x8000的空间用来建立堆栈的(我觉得他说的不对,目前觉得不对,要是跑裸机RObase=0x0是没问题的(但是要注意把数据段搬到RAM中),要是操作系统定义在RObase=0x0c000000恐怕是不行) |