;============================================================================<br />; Name : 44BINIT.S <br />; C start up codes <br />;============================================================================<br />INCLUDE option.inc<br />INCLUDE memcfg.inc<br />;============================================================================<br />;存储器空间<br />;GCS6 64M 16bit(8MB) DRAM/SDRAM(0xc000000-0xc7fffff)<br />;APP RAM=0xc000000~0xc7effff <br />;44BMON RAM=0xc7f0000-0xc7fffff<br />;STACK =0xc7ffa00 <br />;============================================================================<br />;中断控制预定义<br />INTPND EQU 0x01e00004<br />INTMOD EQU 0x01e00008<br />INTMSK EQU 0x01e0000c<br />I_ISPR EQU 0x01e00020<br />I_CMST EQU 0x01e0001c<br /><br />;============================================================================<br />;看门狗定时器预定义<br />WTCON EQU 0x01d30000<br /><br />;============================================================================<br />;系统时钟预定义<br />PLLCON EQU 0x01d80000<br />CLKCON EQU 0x01d80004<br />LOCKTIME EQU 0x01d8000c<br /> <br />;============================================================================<br />;存储器控制预定义<br />REFRESH EQU 0x01c80024<br /><br />;============================================================================<br />;BDMA目的寄存器<br />BDIDES0 EQU 0x1f80008<br />BDIDES1 EQU 0x1f80028<br /><br />;============================================================================<br />;预定义常数(常量)<br />USERMODE EQU 0x10<br />FIQMODE EQU 0x11<br />IRQMODE EQU 0x12<br />SVCMODE EQU 0x13<br />ABORTMODE EQU 0x17<br />UNDEFMODE EQU 0x1b<br />MODEMASK EQU 0x1f<br />NOINT EQU 0xc0<br />;============================================================================<br />;检查是否使用tasm.exe进行编译<br /> GBLL THUMBCODE<br /> [ {CONFIG} = 16 <br />THUMBCODE SETL {TRUE}<br /> CODE32<br /> | <br />THUMBCODE SETL {FALSE}<br /> ]<br /><br /> [ THUMBCODE<br /> CODE32 ;for start-up code for Thumb mode<br /> ]<br /><br />;向量宏定义<br /> MACRO<br />$HandlerLabel HANDLER $HandleLabel<br /><br />$HandlerLabel<br /> sub sp,sp,#4 ;decrement sp(to store jump address)<br /> stmfd sp!,{r0} ;PUSH the work register to stack(lr do not push because it return to original address)<br /> ldr r0,=$HandleLabel ;load the address of HandleXXX to r0<br /> ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX<br /> str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack<br /> ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)<br /> MEND<br /> <br />;HandlerFIQ HANDLER HandleFIQ <br /><br /> IMPORT Main ;The main entry of mon program <br /><br />;代码开始<br /> AREA Init,CODE,READONLY<br /> ENTRY <br />ResetEntry<br /> b ResetHandler ;for debug<br /> b HandlerUndef ;handlerUndef<br /> b HandlerSWI ;SWI interrupt handler<br /> b HandlerPabort ;handlerPAbort<br /> b HandlerDabort ;handlerDAbort<br /> b . ;handlerReserved<br /> b HandlerIRQ<br /> b HandlerFIQ<br />;IMPORTANT NOTE=======================================<br />;If the H/W vectored interrutp mode is enabled, The above two instructions should <br />;be changed like below, to work-around with H/W bug of S3C44B0X interrupt controller. <br />; b HandlerIRQ -> subs pc,lr,#4 <br />; b HandlerIRQ -> subs pc,lr,#4 <br />;========================================================================================================<br /><br />;中断向量表<br />VECTOR_BRANCH<br /> ldr pc,=HandlerEINT0 ;mGA 0x20 <br /> ldr pc,=HandlerEINT1 ; <br /> ldr pc,=HandlerEINT2 ;<br /> ldr pc,=HandlerEINT3 ;<br /> ldr pc,=HandlerEINT4567 ;<br /> ldr pc,=HandlerTICK ;mGA 0x34<br /> b .<br /> b .<br /> ldr pc,=HandlerZDMA0 ;mGB 0x40<br /> ldr pc,=HandlerZDMA1 ;<br /> ldr pc,=HandlerBDMA0 ;<br /> ldr pc,=HandlerBDMA1 ;<br /> ldr pc,=HandlerWDT ;<br /> ldr pc,=HandlerUERR01 ;mGB 0x54<br /> b .<br /> b .<br /> ldr pc,=HandlerTIMER0 ;mGC 0x60<br /> ldr pc,=HandlerTIMER1 ;<br /> ldr pc,=HandlerTIMER2 ;<br /> ldr pc,=HandlerTIMER3 ;<br /> ldr pc,=HandlerTIMER4 ;<br /> ldr pc,=HandlerTIMER5 ;mGC 0x74<br /> b .<br /> b .<br /> ldr pc,=HandlerURXD0 ;mGD 0x80<br /> ldr pc,=HandlerURXD1 ;<br /> ldr pc,=HandlerIIC ;<br /> ldr pc,=HandlerSIO ;<br /> ldr pc,=HandlerUTXD0 ;<br /> ldr pc,=HandlerUTXD1 ;mGD 0x94<br /> b .<br /> b .<br /> ldr pc,=HandlerRTC ;mGKA 0xa0<br /> b .<br /> b .<br /> b .<br /> b .<br /> b . ;mGKA<br /> b .<br /> b .<br /> ldr pc,=HandlerADC ;mGKB 0xc0<br /> b . ;<br /> b . ;<br /> b . ;<br /> b . ;<br /> b . ;mGKB<br /> b .<br /> b .<br /> ldr pc,=EnterPWDN ;0xe0=EnterPWDN<br /><br />;=========================================================================================================<br />;向量中断的处理方法 <br />;Example: HandlerADC HANDLE HandleADC 解为 <br />;HandlerADC ;HandlerADC为中断向量表的入口 <br />; sub sp,sp,#4 ;将sp减少一个字节,使其在堆栈高端留出存储返回地址,因为pc在寄存器组中的 <br />; ;的位置大于r0,出栈时装入的是栈的高端的内容 <br />; stmfd sp!,{r0} ;保存r0 <br />; ldr r0,=HandleADC ;装载中断处理函数的指针 <br />; ldr r0,[r0] ;装载中断处理函数的地址 <br />; str r0,[sp,#4] ;将中断处理函数的地址存入刚才预留的位置,r0的上面 <br />; ldmfd sp!,{r0,pc} ;出栈后,pc指向的既是中断处理函数的地址 <br />; <br />; INTCON^2 == 0时,vector table使能 <br />; 发生中断->HandlerADC->HandleADC(pISR_ADC,即:_ISR_STARTADDRESS+0x20); <br />; 若要在程序中处理此中断,只要将中断服务函数的指针赋给pISR_ADC,如:pISR_ADC = (int)ADCIsr <br />;=========================================================================================================<br /><br />;=========================================================================================================<br />;复位中断处理函数 <br />;=========================================================================================================<br />ResetHandler<br /> ldr r0,=WTCON ;禁止看门狗<br /> ldr r1,=0x0 <br /> str r1,[r0]<br /><br /> ldr r0,=INTMSK<br /> ldr r1,=0x07ffffff ;禁止所有中断<br /> str r1,[r0]<br /><br /> ;以下三段设置时钟控制寄存器<br /> ldr r0,=LOCKTIME<br /> ldr r1,=0xfff<br /> str r1,[r0]<br /><br /> [ PLLONSTART<br /> ldr r0,=PLLCON ;锁相环倍频设定<br /> ldr r1,=((M_DIV<<12)+(P_DIV<<4)+S_DIV) ;设定系统主时钟频率<br /> str r1,][r0]<br /> ]<br /><br /> ldr r0,=CLKCON <br /> ldr r1,=0x7ff8 ;所有功能单元块时钟使能<br /> str r1,[r0]<br /> <br />;====================================================<br />;change BDMACON reset value for BDMA <br />;==================================================== <br /> ldr r0,=BDIDES0 <br /> ldr r1,=0x40000000 ;BDIDESn reset value should be 0x40000000 <br /> str r1,[r0]<br /> ldr r0,=BDIDES1 <br /> ldr r1,=0x40000000 ;BDIDESn reset value should be 0x40000000 <br /> str r1,[r0]<br />;====================================================<br /> ;设定存储器控制寄存器 <br />;====================================================<br /> adr r0, ResetHandler<br /> ldr r1, =ResetHandler<br /> sub r0, r1, r0 <br /> ldr r1, =SMRDATA ;将定义的数据表格放进来(因为这个时候程序还是在FLASH里执行的,这个时候要从加载域中将数据表格提取出来)<br /> sub r0, r1, r0 <br /> ldmia r0, {r1-r13}<br /> ldr r0, =0x01c80000 ;BWSCON Address<br /> stmia r0, {r1-r13} <br /><br />;====================================================<br /> ;初始化堆栈 <br />;====================================================<br /> ldr sp, =SVCStack ;复位后位SVC模式<br /> bl InitStacks<br /><br />;====================================================<br /> ;设置中断处理 <br />;====================================================<br /> ldr r0,=HandleIRQ ;This routine is needed<br /> ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c<br /> str r1,[r0]<br /> <br /> <br />;========================================================<br />;========================================================<br />;注:以下这一小段代码还是在ROM中执行的,但这一小段代码却完成了非常重要的功能,完成的功能如下<br />;1:判断加载域和运行域是否相同,如果不同,那么要把"拷贝程序模板"事先复制到运行域中去,然后跳转到运行域,<br />;再把ROM中的代码拷贝到<br />;RAM中去,为什么要这样,因为ARM的程序在ROM中执行的时候,不能再读取ROM中的数据,然后写入到RAM中去,只能把完成拷贝功能<br />;的那一小部分代码先拷贝到RAM中去,然后跳转到RAM中,执行从ROM中读取数据,然后将读到的数据拷贝到RAM中去这样的操作。<br /><br />;====================================================<br /> ;拷贝并粘贴 RW data/zero initialized data <br />;====================================================<br /> adr r0, ResetEntry ;R0中装入ResetEntry,注意,adr这条指令是个伪指令,也即加载域首地址,理解这条指令很关键,弄不好要看汇编后的代码,。,,<br /> ldr r1, BaseOfROM ;R1中装入BaseOfROM,BaseOfROM为运行域首地址<br /> cmp r0, r1 ;比较R0和R1是否相等,也就是比较加载域地址和运行域地址是否相同<br /> ldreq r0, TopOfROM<br /> beq InitRamData ;如果相等,则跳转到InitRamData<br /> <br /> ;====================================================<br /> ;计算拷贝程序在flash中的实际位置 <br /> ;====================================================<br /> ldr r2, =CopyProcBeg ;将CopyProcBeg装入到R2,CopyProcBeg为代码拷贝的首地址<br /> sub r1, r2, r1 ; r1 = r2 - r1,这里因为CopyProcBeg标号和BaseOfROM标号有个偏差,而我们要把<br /> ;烧录到ROM中CopyProcBeg处的一段代码拷贝到BaseOfROM为起始地址处,但CopyProcBeg<br /> add r0, r0, r1 ;r0 = r0 + r1,这句话实际上是得出加载域中CopyProcBeg的地址<br /> ldr r3, =CopyProcEnd ;r3 = CopyProcEnd <br /> <br />;====================================================<br />;将拷贝程序复制到ram中 <br />;====================================================<br />0 <br /> ldmia r0!, {r4-r7} ;将加载域中的值装入到R4-R7,并且加载域地址指针自增<br /> stmia r2!, {r4-r7} ;将R4-7中的值装入到R2所指的一段内存处,并且运行域地址指针自增。<br /> cmp r2, r3 ;判断是否拷贝结束<br /> bcc %B0 <br /> <br />;====================================================<br />;开始用ram中的拷贝程序复本将所有剩下的代码复制到ram中 <br />;====================================================<br /> ldr r3, TopOfROM ;将RO段的数据长度装入到R3<br /> ldr pc, =CopyProcBeg ;将PC指针指向CopyProcBeg,注意这以后的程序就是在RAM中运行了<br /> <br />;=========================================================<br />;=========================================================<br /><br /><br />;=========================================================<br />;以下程序在RAM中执行了!<br />;=========================================================<br /><br />;=========================================================<br />;本段将代码由实际烧入的地址拷贝到ro-base所指定的位置 <br />;只拷贝CopyProcEnd以后的代码 <br />;这段代码是将RO段代码由加载域拷贝到运行域中去<br />;=========================================================<br />CopyProcBeg <br />0 <br /> ldmia r0!, {r4-r11} ;将加载域中的值装入到R4-R7,并且加载域地址指针自增<br /> stmia r2!, {r4-r11} ;将R4-7中的值装入到R2所指的一段内存处,并且运行域地址指针自增。<br /> cmp r2, r3 ;判断是否将RO段的代码完全从加载域拷贝到运行域,如果没拷贝完则继续拷贝<br /> bcc %B0 <br />CopyProcEnd<br /> ;此处则说明RO段代码已经拷贝完成,那么接下来要将RW段的数据从加载域拷贝到运行域<br /> sub r1, r2, r3 <br /> sub r0, r0, r1 ;这里应该是进行字节对齐的处理。以免少拷贝几个字节的东西。<br /> <br />;=========================================================<br />;这段代码是将RW段代码由加载域拷贝到运行域中去<br />;========================================================= <br />InitRamData <br /> ldr r2, BaseOfBSS ;RW段首地址<br /> ldr r3, BaseOfZero ;RW段长度<br />0<br /> cmp r2, r3 ;判断是否将RW段的代码完全从加载域拷贝到运行域,如果没拷贝完则继续拷贝<br /> ldrcc r1, [r0], #4 ;将R0所指单元的数据拷贝到R1中<br /> strcc r1, [r2], #4 ;将R1中的数据复制到R2所指单元中去<br /> bcc %B0 <br /> <br />;=========================================================<br />;这段代码是将ZI段数据清零<br />;=========================================================<br /> mov r0, #0 <br /> ldr r3, EndOfBSS ;将ZI段数据结束地址装入R3,用以判断ZI段是否清零结束<br />1 <br /> cmp r2, r3 ;判断ZI段是否结束,如果未结束,还要继续清零内存<br /> strcc r0, [r2], #4 ;将R2所指单元的内容清零 <br /> bcc %B1 <br /> <br />;=========================================================<br />;以下程序就是转入到MAIN标号处去了<br />;=========================================================<br /> [ :LNOT:THUMBCODE<br /> BL Main ;从汇编进入C语言代码空间,不要使用main()<br /> B . <br /> ]<br /><br /> [ THUMBCODE ;for start-up code for Thumb mode<br /> orr lr,pc,#1<br /> bx lr<br /> CODE16<br /> bl Main ;从汇编进入C语言代码空间,不要使用main()<br /> b .<br /> CODE32<br /> ]<br /> <br /> <br /> LTORG<br />;========================================================================================================<br />;中断向量表 ;<br />;Example: HandlerADC HANDLE HandleADC 解为 ;<br />;HandlerADC ;HandlerADC为中断向量表的入口 ;<br />; sub sp,sp,#4 ;将sp减少一个字节,使其在堆栈高端留出存储返回地址,因为pc在寄存器组中的 ;<br />; ;的位置大于r0,出栈时装入的是栈的高端的内容 ;<br />; stmfd sp!,{r0} ;保存r0 ;<br />; ldr r0,=HandleADC ;装载中断处理函数的指针 ;<br />; ldr r0,[r0] ;装载中断处理函数的地址 ;<br />; str r0,[sp,#4] ;将中断处理函数的地址存入刚才预留的位置,r0的上面 ;<br />; ldmfd sp!,{r0,pc} ;出栈后,pc指向的既是中断处理函数的地址 ;<br />; ;<br />; INTCON^2 == 0时,vector table使能 ;<br />; 发生中断->HandlerADC->HandleADC(pISR_ADC,即:_ISR_STARTADDRESS+0x20); ; <br />; 若要在程序中处理此中断,只要将中断服务函数的指针赋给pISR_ADC,如:pISR_ADC = (int)ADCIsr ;<br />;========================================================================================================<br />HandlerFIQ HANDLER HandleFIQ<br /><br />;HandlerFIQ<br />; sub sp,sp,#4 ;decrement sp(to store jump address)<br />; stmfd sp!,{r0} ;PUSH the work register to stack(lr do not push because it return to original address)<br />; ldr r0,=HandleFIQ ;load the address of HandleXXX to r0<br />; ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX<br />; str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack<br />; ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)<br /><br /><br />HandlerIRQ HANDLER HandleIRQ<br />HandlerUndef HANDLER HandleUndef<br />HandlerSWI HANDLER HandleSWI<br />HandlerDabort HANDLER HandleDabort<br />HandlerPabort HANDLER HandlePabort<br />HandlerADC HANDLER HandleADC<br />HandlerRTC HANDLER HandleRTC<br />HandlerUTXD1 HANDLER HandleUTXD1<br />HandlerUTXD0 HANDLER HandleUTXD0<br />HandlerSIO HANDLER HandleSIO<br />HandlerIIC HANDLER HandleIIC<br />HandlerURXD1 HANDLER HandleURXD1<br />HandlerURXD0 HANDLER HandleURXD0<br />HandlerTIMER5 HANDLER HandleTIMER5<br />HandlerTIMER4 HANDLER HandleTIMER4<br />HandlerTIMER3 HANDLER HandleTIMER3<br />HandlerTIMER2 HANDLER HandleTIMER2<br />HandlerTIMER1 HANDLER HandleTIMER1<br />HandlerTIMER0 HANDLER HandleTIMER0<br />HandlerUERR01 HANDLER HandleUERR01<br />HandlerWDT HANDLER HandleWDT<br />HandlerBDMA1 HANDLER HandleBDMA1<br />HandlerBDMA0 HANDLER HandleBDMA0<br />HandlerZDMA1 HANDLER HandleZDMA1<br />HandlerZDMA0 HANDLER HandleZDMA0<br />HandlerTICK HANDLER HandleTICK<br />HandlerEINT4567 HANDLER HandleEINT4567<br />HandlerEINT3 HANDLER HandleEINT3<br />HandlerEINT2 HANDLER HandleEINT2<br />HandlerEINT1 HANDLER HandleEINT1<br />HandlerEINT0 HANDLER HandleEINT0<br /><br />;===================================================================<br />IMPORT |Image$$RO$$Base| ; ROM code start <br />IMPORT |Image$$RO$$Limit| ; RAM data starts after ROM program<br />IMPORT |Image$$RW$$Base| ; Pre-initialised variables<br />IMPORT |Image$$ZI$$Base| ; uninitialised variables<br />IMPORT |Image$$ZI$$Limit| ; End of variable RAM space<br /><br />BaseOfROM DCD |Image$$RO$$Base|<br />TopOfROM DCD |Image$$RO$$Limit|<br />BaseOfBSS DCD |Image$$RW$$Base|<br />BaseOfZero DCD |Image$$ZI$$Base|<br />EndOfBSS DCD |Image$$ZI$$Limit|<br /><br />EXPORT GetBaseOfROM<br />EXPORT GetEndOfROM<br />EXPORT GetBaseOfBSS<br />EXPORT GetBaseOfZero<br />EXPORT GetEndOfBSS<br /> <br />GetBaseOfROM<br /> ldr r0, BaseOfROM<br /> mov pc, lr <br />GetEndOfROM<br /> ldr r0, TopOfROM<br /> mov pc, lr<br />GetBaseOfBSS<br /> ldr r0, BaseOfBSS<br /> mov pc, lr<br />GetBaseOfZero<br /> ldr r0, BaseOfZero<br /> mov pc, lr<br />GetEndOfBSS<br /> ldr r0, EndOfBSS<br /> mov pc, lr<br /><br />;==========================================================================<br />; 堆栈初始化功能<br />;==========================================================================<br />InitStacks<br /> ;Do not use DRAM,such as stmfd,ldmfd......<br /> ;SVCstack is initialized before<br /> ;Under toolkit ver 2.50, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'<br /> mrs r0,cpsr<br /> bic r0,r0,#MODEMASK<br /> orr r1,r0,#UNDEFMODE|NOINT<br /> msr cpsr_cxsf,r1 ;UndefMode<br /> ldr sp,=UndefStack<br /> <br /> orr r1,r0,#ABORTMODE|NOINT<br /> msr cpsr_cxsf,r1 ;AbortMode<br /> ldr sp,=AbortStack<br /><br /> orr r1,r0,#IRQMODE|NOINT<br /> msr cpsr_cxsf,r1 ;IRQMode<br /> ldr sp,=IRQStack<br /> <br /> orr r1,r0,#FIQMODE|NOINT<br /> msr cpsr_cxsf,r1 ;FIQMode<br /> ldr sp,=FIQStack<br /><br /> bic r0,r0,#MODEMASK|NOINT<br /> orr r1,r0,#SVCMODE<br /> msr cpsr_cxsf,r1 ;SVCMode<br /> ldr sp,=SVCStack<br /> ;USER mode is not initialized.<br /> mov pc,lr ;The LR register may be not valid for the mode changes.<br />;============================================================<br /><br /><br /><br />;============================================================<br />;非向量中断的处理 <br />;如果I_ISPC的使用不正确,此时I_ISPR可能为零 <br />;堆栈内容的变化 <br />; <br />;H sp |--| |--| |--| |--| sp |--| <br />; | | sp | | | | |ad|->pc | | <br />; | | | | |r9| |r9|->r9 | | <br />;L | | | | sp |r8| &nb
|