EasyARM2200开发板学习笔记:启动代码分析
;定义堆栈的大小<br />FIQ_STACK_LEGTH EQU 0<br />IRQ_STACK_LEGTH EQU 9*8 ;每层嵌套需要9个字堆栈,允许8层嵌套<br />ABT_STACK_LEGTH EQU 0<br />UND_STACK_LEGTH EQU 0<br /><br />;处理器模式常量定义<br />NoInt EQU 0x80 ;禁止IRQ中断<br />USR32Mode EQU 0x10 ;用户模式<br />SVC32Mode EQU 0x13 ;管理模式<br />SYS32Mode EQU 0x1f ;系统模式<br />IRQ32Mode EQU 0x12 ;中断模式<br />FIQ32Mode EQU 0x11 ;快速中断模式<br /><br />PINSEL2 EQU 0xE002C014<br />BCFG0 EQU 0xFFE00000<br />BCFG1 EQU 0xFFE00004<br />BCFG2 EQU 0xFFE00008<br />BCFG3 EQU 0xFFE0000C<br /><br />;引入的外部标号在这声明<br />IMPORT FIQ_Exception ;快速中断异常处理程序<br />IMPORT __main ;C语言主程序入口 <br />IMPORT TargetResetInit ;目标板基本初始化<br />IMPORT StackUsr ;用户模式栈<br />IMPORT bottom_of_heap ;用户模式堆<br />IMPORT SoftwareInterrupt ;软件中断处理程序<br /><br />;给外部使用的标号在这声明<br />EXPORT Reset<br />EXPORT __rt_div0<br />EXPORT __user_initial_stackheap<br /><br /> CODE32<br /><br /> AREA vectors,CODE,READONLY<br /> ENTRY<br />;中断向量表<br />Reset<br /> LDR PC, ResetAddr ;复位入口,程序在系统中执行的第一条指令<br /> LDR PC, UndefinedAddr ;未定义指令异常入口地址<br /> LDR PC, SWI_Addr ;软件中断入口地址<br /> LDR PC, PrefetchAddr ;取指令中止异常入口地址<br /> LDR PC, DataAbortAddr ;取数据中止异常入口地址<br /> DCD 0xb9205f80 ;保留向量,值是其它中断向量累加和的补码<br /> LDR PC, ;中断请求IRQ入口地址<br /> LDR PC, FIQ_Addr ;快速中断请求FIQ入口地址<br /><br />ResetAddr DCD ResetInit<br />UndefinedAddr DCD Undefined<br />SWI_Addr DCD SoftwareInterrupt<br />PrefetchAddr DCD PrefetchAbort<br />DataAbortAddr DCD DataAbort<br />Nouse DCD 0<br />IRQ_Addr DCD 0<br />FIQ_Addr DCD FIQ_Handler<br /><br />;未定义指令<br />Undefined<br /> B Undefined ;发生未定义指令异常时执行死循环<br /><br />;取指令中止<br />PrefetchAbort<br /> B PrefetchAbort ;发生取指令中止异常时执行死循环<br /><br />;取数据中止<br />DataAbort<br /> B DataAbort ;发生取数据中止异常时执行死循环<br /><br />;快速中断<br />FIQ_Handler<br /> STMFD SP!, {R0-R3, LR} ;现场保护,将R0-R3, LR入栈<br /> BL FIQ_Exception ;调用快速中断异常处理程序<br /> LDMFD SP!, {R0-R3, LR} ;异常中断返回<br /> SUBS PC, LR, #4 ;PC指向中断前没有被执行的指令<br /><br /><br />InitStack<br />;初始化堆栈<br /> MOV R0, LR<br /><br />;设置中断模式堆栈<br /> MSR CPSR_c, #0xd2 ;IRQ和FIQ禁止, 中断模式<br /> LDR SP, StackIrq ;设置中断模式堆栈指针,指向StackIrq<br />;设置快速中断模式堆栈<br /> MSR CPSR_c, #0xd1 ;IRQ和FIQ禁止, 快速中断模式<br /> LDR SP, StackFiq ;设置快速中断模式堆栈指针,指向StackFiq<br />;设置中止模式堆栈<br /> MSR CPSR_c, #0xd7 ;IRQ和FIQ禁止, 中止模式<br /> LDR SP, StackAbt ;设置中止模式堆栈指针,指向StackAbt<br />;设置未定义模式堆栈<br /> MSR CPSR_c, #0xdb ;IRQ和FIQ禁止, 未定义模式<br /> LDR SP, StackUnd ;设置未定义模式堆栈指针,指向StackUnd<br />;设置系统模式堆栈<br /> MSR CPSR_c, #0xdf ;IRQ和FIQ禁止, 系统模式<br /> LDR SP, =StackUsr ;设置系统模式堆栈指针,指向StackUsr<br /><br /> MOV PC, R0 ;返回<br /><br />ResetInit<br />;复位入口<br />;初始化外部总线控制器,根据目标板决定配置<br /><br /> LDR R0, =PINSEL2 ;将PINSEL2的地址赋给RO<br /> IF :DEF: EN_CRP ;判断是否有预定义EN_CRP宏<br /> LDR R1, =0x0f814910 ;PINSEL2.2=0, 禁止JTAG调试<br /> ELSE<br /> LDR R1, =0x0f814914 ;PINSEL2.2=1, 使能JTAG调试<br /> ENDIF<br /> STR R1, <br /><br /> LDR R0, =BCFG0 ;初始化存储器组0的配置寄存器<br /> LDR R1, =0x1000ffef<br /> STR R1, <br /><br /> LDR R0, =BCFG1 ;初始化存储器组1的配置寄存器<br /> LDR R1, =0x1000ffef<br /> STR R1, <br /><br />; LDR R0, =BCFG2 ;初始化存储器组2的配置寄存器<br />; LDR R1, =0x2000ffef<br />; STR R1, <br /><br />; LDR R0, =BCFG3 ;初始化存储器组3的配置寄存器<br />; LDR R1, =0x2000ffef<br />; STR R1, <br /> <br /> BL InitStack ;跳转到初始化堆栈代码段<br /> BL TargetResetInit ;跳转到目标板基本初始化<br /> <br /> B __main ;跳转到c语言入口<br /><br />__user_initial_stackheap ;库函数初始化堆和栈<br />MOV pc,lr<br /><br /><br />__rt_div0 ;整数除法除数为0错误处理函数<br />B __rt_div0<br /><br />StackIrq DCD IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4<br />StackFiq DCD FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4<br />StackAbt DCD AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4<br />StackUnd DCD UndtStackSpace + (UND_STACK_LEGTH - 1)* 4<br /><br /><br /> IF :DEF: EN_CRP<br /> IF . >= 0x1fc ;判断当前代码地址是否已超过0x1FC<br /> INFO 1,"The data at 0x000001fc must be 0x87654321.<br />
Please delete some source before this line."<br /> ENDIF<br />CrpData<br /> WHILE . < 0x1fc ;未到0x1FC则填充NOP指令<br /> NOP<br /> WEND<br />CrpData1<br /> DCD 0x87654321 ;在0x1FC处放置0x87654321,启动加密功能<br /> ENDIF<br /><br />;/* 分配堆栈空间 */<br /> AREA MyStacks, DATA, NOINIT, ALIGN=2<br />IrqStackSpace SPACE IRQ_STACK_LEGTH * 4 ;中断模式堆栈空间<br />FiqStackSpace SPACE FIQ_STACK_LEGTH * 4 ;快速中断模式堆栈空间<br />AbtStackSpace SPACE ABT_STACK_LEGTH * 4 ;中止义模式堆栈空间<br />UndtStackSpace SPACE UND_STACK_LEGTH * 4 ;未定义模式堆栈<br />END
EasyARM2200开发板学习笔记:代码镜像的分析
https://bbs.21ic.com/upfiles/img/20079/200793193410450.gif<br /><br /> 从上图可看出RO(Code+RO Data)段的大小是1544bytes,RW段的大小为0,ZI段的大小为1128bytes。Debug Image是给调试器用的,并没有加载到开发板存储中去,再因为ZI段是在程序运行时才在RAM中生成,所以真正加载到开发板中的大小只有1544bytes,这点也可以通过编译器输出BIN二进制文件的大小看出。<br /> 那么这些输出段加载到开发板存储时是怎么存放的呢?这要由连接器的连接类型来确定,连接类型分为Partial、Simple和Scattered三种,这里只介绍最后一种连接类型的加载方式,使用这种类型要用到scatter文件,以下是周立功开发板例子程序中附带的两个scatter文件,可以看出加载域都是在0x80000000处,所以加载到开发板中的RO段就从0x80000000开始放置。其中code存放在0x80000000~0x800005A3,大小刚好1444bytes,RO Data存放在0x800005A4~0x80000607,大小刚好100bytes。因为此例RW Data为0,所以在以下两种分散加载文件中,真正加载到开发板存储器中的区域是0x80000000~0x80000607。<br /><br />(左)<br />ROM_LOAD 0x80000000<br />{<br /> ROM_EXEC 0x80000000<br /> {<br /> Startup.o (vectors, +First)<br /> * (+RO)<br /> }<br /><br /> IRAM 0x40000000<br /> {<br /> Startup.o (+RW,+ZI)<br /> }<br /><br /> STACKS 0x40004000 UNINIT<br /> {<br /> stack.o (+ZI)<br /> }<br /><br /> ERAM 0x80040000<br /> {<br /> * (+RW,+ZI)<br /> }<br /><br /> HEAP +0 UNINIT<br /> {<br /> heap.o (+ZI)<br /> }<br />}<br /><br />(右)<br />ROM_LOAD 0x80000000<br />{<br /> ROM_EXEC 0x80000000<br /> {<br /> Startup.o (vectors, +First)<br /> * (+RO)<br /> }<br /><br /> IRAM 0x40000000<br /> {<br /> Startup.o (+RW,+ZI)<br /> }<br /><br /> STACKS 0x40004000 UNINIT<br /> {<br /> stack.o (+ZI)<br /> }<br /><br /> ERAM 0x81000000<br /> {<br /> * (+RW,+ZI)<br /> }<br /><br /> HEAP +0 UNINIT<br /> {<br /> heap.o (+ZI)<br /> }<br />}<br /><br /> 加载成功后,程序开始启动,启动过程中会对stack和heap进行初始化,先是给不同处理器模式的SP(R13)寄存器进行初始化,让SP都指向各自的stack区域。Stack区域在编译连接时根据上面的分散加载文件已经确定了存放位置和大小,下面左边是周立功EasyARM2200开发板的例子中初始化栈指针的代码。<br /><br />InitStack <br /> MOV R0, LR<br /><br />;设置管理模式的栈指针<br /> MSR CPSR_c, #0xd3<br /> LDR SP, StackSvc<br />;设置中断模式的栈指针<br /> MSR CPSR_c, #0xd2<br /> LDR SP, StackIrq<br />;设置快速中断模式的栈指针<br /> MSR CPSR_c, #0xd1<br /> LDR SP, StackFiq<br />;设置中止模式栈<br /> MSR CPSR_c, #0xd7<br /> LDR SP, StackAbt<br />;设置未定义模式的栈指针<br /> MSR CPSR_c, #0xdb<br /> LDR SP, StackUnd<br />;设置系统模式的栈指针<br /> MSR CPSR_c, #0xdf<br /> LDR SP, =StackUsr<br /><br /> MOV PC, R0<br /><br /> 那么上面这些栈指针所指向的栈空间的定义又在哪里呢?分析Startup.s发现下面的代码,再联系前面所提到的分散加载文件中的IRAM段,可以得出下面的SvcStackSpace对应的地址应该是0x40000000+RW size,因为Startup.s中没有RW段和其它ZI段,所以:<br />SvcStackSpace=0x40000000,StackSvc=0x3FFFFFFC<br />IrqStackSpace=0x40000000,StackIrq=0x400003FC<br />FiqStackSpace=0x40000400,StackFiq=0x400003FC<br />AbtStackSpace=0x40000400,StackAbt=0x400003FC<br />UndStackSpace=0x40000400,StackUnd=0x400003FC<br /> <br /> 还差一个系统模式的栈,这个栈的定义是在stack.s中,可以根据程序需要增加空间。根据分散加载文件中的STACKS段,可以得出StackUsr对应的地址是0x40004000,它的空间大小在这程序中定义为1bytes。<br /><br />;定义堆栈的大小<br />USR_STACK_LEGTH EQU 256<br />SVC_STACK_LEGTH EQU 0<br />FIQ_STACK_LEGTH EQU 0<br />IRQ_STACK_LEGTH EQU 256<br />ABT_STACK_LEGTH EQU 0<br />UND_STACK_LEGTH EQU 0<br /><br />……<br /><br />;指定不同处理器模式的堆栈指针<br />StackSvc DCD SvcStackSpace + (SVC_STACK_LEGTH - 1)* 4<br />StackIrq DCD IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4<br />StackFiq DCD FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4<br />StackAbt DCD AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4<br />StackUnd DCD UndStackSpace + (UND_STACK_LEGTH - 1)* 4<br /><br />……<br /><br />;分配堆栈空间<br /> AREA MyStacks, DATA, NOINIT, ALIGN=2<br />SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ;管理模式堆栈空间<br />IrqStackSpace SPACE IRQ_STACK_LEGTH * 4 ;中断模式堆栈空间<br />FiqStackSpace SPACE FIQ_STACK_LEGTH * 4 ;快速中断模式堆栈空间<br />AbtStackSpace SPACE ABT_STACK_LEGTH * 4 ;中止义模式堆栈空间<br />UndStackSpace SPACE UND_STACK_LEGTH * 4 ;未定义模式堆栈<br /><br /> 至此我们已经定义的栈空间大小是(256*4+1)=1025bytes,存储对齐后占用了1028bytes。而从上面生成Image的图中可以看出ZI段的大小是1128bytes,那么还有100bytes在哪定义,下面我们通过IDA反汇编来看看另外的ZI段放在什么地方,怎么定义的?<br /><br />ERAM:80040000 AREA ERAM, DATA<br />ERAM:80040000 ; ORG 0x80040000<br />ERAM:80040000 __libspace_start % 0x60 ;DATA XREF: ROM_EXEC:off_80000578o<br />ERAM:80040000 ;ROM_EXEC:80000600o<br />==========================================================================<br />HEAP:80040060 AREA HEAP, DATA<br />HEAP:80040060 ; ORG 0x80040060<br />HEAP:80040060 EXPORT bottom_of_heap<br />HEAP:80040060 bottom_of_heap % 1 ;DATA XREF: ROM_EXEC:off_80000100o<br />HEAP:80040061 ALIGN 4 ;4字节对齐<br /><br /> 可以看出库函数所需要的栈空间和由heap.s声明的堆空间加起来刚好100bytes。存放的位置也正符合上面左边的分散加载文件中ERAM段和HEAP段的定义。那么由heap.s声明的堆空间是在什么时候定义的呢?要不要对其初始化呢?中间还有加载域到运行域的复制,ZI段的清零等工作又是怎么进行的呢?请等下一个笔记《EasyARM2200开发板学习笔记:__main()和__rt_entry()》<br />什么开发环境?
PLL, 紧张中断,remap等都好像没看到吗?<br />路过,随便看看,哈哈。不好意思,还没有展开。
不好意思,还没有展开。EasyARM2200开发板学习笔记:目标板基本初始化
/***************************************************************<br />** 函数名称: InitialiseUART0<br />** 功能描述: 设置串口0 <br />** 输 入: bps:波特率<br />**<br />** 输 出: 无<br />** <br />** 全局变量: 无<br />** 调用模块: 无<br />**<br />** 作 者: 陈明计<br />** 日 期: 2004年2月2日<br />**-------------------------------------------------------------<br />** 修改人:<br />** 日 期:<br />**-------------------------------------------------------------<br />***************************************************************/<br />void InitialiseUART0(uint32 bps)<br />{ <br /> uint16 Fdiv;<br /> <br /> PINSEL0 = (PINSEL0 & 0xfffffff0) | 0x05; //选择管脚为UART0<br /><br /> U0LCR = 0x80; //允许访问分频因子寄存器<br /> Fdiv = (Fpclk / 16) / bps; //设置波特率<br /> U0DLM = Fdiv / 256; <br /> U0DLL = Fdiv % 256; <br /> U0LCR = 0x03; //禁止访问分频因子寄存器,且设置为8,1,n<br /> U0IER = 0x00; //禁止中断<br /> U0FCR = 0x00; //初始化FIFO<br />} <br /><br /><br /><br />/***************************************************************<br />** 函数名称: TargetResetInit<br />** 功能描述: 调用main函数前目标板初始化代码,根据需要改变,不能删除<br />** 输 入: 无<br />**<br />** 输 出: 无<br />** <br />** 全局变量: 无<br />** 调用模块: 无<br />**<br />** 作 者: 陈明计<br />** 日 期: 2004年2月2日<br />**-------------------------------------------------------------<br />** 修改人:<br />** 日 期:<br />**-------------------------------------------------------------<br />***************************************************************/<br />void TargetResetInit(void)<br />{<br />//判断是否在编译器Preprocessor选项卡中预定义了宏变量“__DEBUG”<br />#ifdef __DEBUG<br /> BCFG0 = 0x10000400;<br /> MEMMAP = 0x3; //用户外部存储器模式,中断向量从外部存储器重新映射<br />#endif<br /><br />//判断是否在编译器Preprocessor选项卡中预定义了宏变量“__OUT_CHIP”<br />#ifdef __OUT_CHIP<br />// BCFG0 = 0x10000400;<br /> BCFG1 = 0x10000400;<br /> MEMMAP = 0x3; //用户外部存储器模式,中断向量从外部存储器重新映射#endif<br /><br />//判断是否在编译器Preprocessor选项卡中预定义了宏变量“__IN_CHIP”<br />#ifdef __IN_CHIP <br /> BCFG0 = 0x10000400;<br /> MEMMAP = 0x1; //用户Flash模式,中断向量不重新映射<br />#endif<br /><br /> //引脚P0.0~P0.4设置为UART0和I2C<br /> PINSEL0 = (PINSEL0 & 0xFFFF0000) | 0x05 | 0x50;<br /><br />/* 设置系统各部分时钟 */<br /> PLLCON = 1;<br />#if (Fpclk / (Fcclk / 4)) == 1<br /> VPBDIV = 0; //VPB总线时钟为处理器时钟的1/4<br />#endif<br />#if (Fpclk / (Fcclk / 4)) == 2<br /> VPBDIV = 2; //VPB总线时钟为处理器时钟的1/2<br />#endif<br />#if (Fpclk / (Fcclk / 4)) == 4<br /> VPBDIV = 1; //VPC总线时钟与处理器时钟相同<br />#endif<br /><br />#if (Fcco / Fcclk) == 2<br /> PLLCFG = ((Fcclk / Fosc) - 1) | (0 << 5);<br />#endif<br />#if (Fcco / Fcclk) == 4<br /> PLLCFG = ((Fcclk / Fosc) - 1) | (1 << 5);<br />#endif<br />#if (Fcco / Fcclk) == 8<br /> PLLCFG = ((Fcclk / Fosc) - 1) | (2 << 5);<br />#endif<br />#if (Fcco / Fcclk) == 16<br /> PLLCFG = ((Fcclk / Fosc) - 1) | (3 << 5);<br />#endif<br /> PLLFEED = 0xaa;<br /> PLLFEED = 0x55;<br /> while((PLLSTAT & (1 << 10)) == 0); //确认PLL的锁定状态<br /> PLLCON = 3; //PLL使能关连接到处理器作为系统时钟源<br /> PLLFEED = 0xaa;<br /> PLLFEED = 0x55;<br /><br />/* 设置存储器加速模块 */<br /> MAMCR = 0; //MAM功能禁止<br />#if Fcclk < 20000000<br /> MAMTIM = 1; //MAM取指周期为1个cclk,实际上是关闭了MAM<br />#else<br />#if Fcclk < 40000000<br /> MAMTIM = 2; //MAM取指周期为2个cclk<br />#else<br /> MAMTIM = 3; //MAM取指周期为3个cclk<br />#endif<br />#endif<br /> MAMCR = 2; //MAM功能完全使能<br /><br />/* 设置串行口 */<br /> InitialiseUART0(115200);<br /><br />/* 设置实时时钟 */<br /> CCR = 1;<br /> PREINT = Fpclk / 32768 - 1;<br /> PREFRAC = Fpclk - (Fpclk / 32768) * 32768;<br /> YEAR = 2008;<br /> MONTH = 7;<br /> DOM = 17;<br /><br /> VICIntEnClr = 0xffffffff; //清零中断使能寄存器并禁止中断请求<br /> VICVectAddr = 0; //清零向量地址寄存器<br /> VICIntSelect = 0; //初始化所有中断请求输入类型为IRQ<br /> T0IR = 0xffffffff;<br /> T0TCR = 0X02;<br />}<br />周立功的源码,会被通缉的
周的网站上可下载,<br />产品都生产了,至今还不知道heap初始化是那一块,<br />有高手告我关于启动代码,
《ecos增值包》里包括了redboot、u-boot、bootrom等启动部分的源码,用GNU实现,内容更丰富。<br />关于EasyARM2200开发板,www.armecos.com免费下载里有很多试用程序,可以完成非常复杂的应用。<br /><br /><b>更多内容,详见:</b><br /><b>《培训系列“丛书”》</b><br /><b>www.armecos.com</b><br />-----------------------------------<br /><b>More details, see:</b><br /><b>《"Series Books" of Training》</b><br /><b>www.armecos.com</b>qqqq
qqqq....
感觉分析得还可以的.给你裤子!...
已经在:EasyARM2200开发板学习笔记:代码镜像的分析<br /> 这编**以前被加裤子了.<br /><br /> 2200感觉就是一个不成功的ARM7,带总线只能连PSRAM,还有速度也不快,干不了太多事情.我之前用这个东东也做了一款产品,没有过多长就替换成别的ARM了.《EasyARM2200开发板学习笔记:__main()和__rt_entry()》呢?
期待
页:
[1]