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