;/* ; * File : start.S ; * This file is part of RT-Thread RTOS ; * COPYRIGHT (C) 2006, RT-Thread Development Team ; * ; * This program is free software; you can redistribute it and/or modify ; * it under the terms of the GNU General Public License as published by ; * the Free Software Foundation; either version 2 of the License, or ; * (at your option) any later version. ; * ; * This program is distributed in the hope that it will be useful, ; * but WITHOUT ANY WARRANTY; without even the implied warranty of ; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; * GNU General Public License for more details. ; * ; * You should have received a copy of the GNU General Public License along ; * with this program; if not, write to the Free Software Foundation, Inc., ; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ; * ; * Change Logs: ; * Date Author Notes ; * 2011-01-13 weety first version ; */ #define S_FRAME_SIZE (18*4) ;72 ;#define S_SPSR (17*4) ;SPSR ;#define S_CPSR (16*4) ;CPSR #define S_PC (15*4) ;R15 ;#define S_LR (14*4) ;R14 ;#define S_SP (13*4) ;R13 ;#define S_IP (12*4) ;R12 ;#define S_FP (11*4) ;R11 ;#define S_R10 (10*4) ;#define S_R9 (9*4) ;#define S_R8 (8*4) ;#define S_R7 (7*4) ;#define S_R6 (6*4) ;#define S_R5 (5*4) ;#define S_R4 (4*4) ;#define S_R3 (3*4) ;#define S_R2 (2*4) ;#define S_R1 (1*4) ;#define S_R0 (0*4) #define MODE_SYS 0x1F #define MODE_FIQ 0x11 #define MODE_IRQ 0x12 #define MODE_SVC 0x13 #define MODE_ABT 0x17 #define MODE_UND 0x1B #define MODEMASK 0x1F #define NOINT 0xC0 #include "rt_low_level_iar.inc" MODULE ?cstartup SECTION .noinit:DATA:NOROOT(3) DATA DS8 UND_STK_SIZE PUBLIC UND_STACK_START UND_STACK_START: ALIGNRAM 2 DS8 ABT_STK_SIZE PUBLIC ABT_STACK_START ABT_STACK_START: ALIGNRAM 2 DS8 FIQ_STK_SIZE PUBLIC FIQ_STACK_START FIQ_STACK_START: ALIGNRAM 2 DS8 IRQ_STK_SIZE PUBLIC IRQ_STACK_START IRQ_STACK_START: ALIGNRAM 2 DS8 SVC_STK_SIZE PUBLIC SVC_STACK_START SVC_STACK_START: ALIGNRAM 2 DS8 SYS_STK_SIZE PUBLIC SYS_STACK_START SYS_STACK_START: ;--------------Jump vector table------------------------------------------------ SECTION .intvec:CODE:ROOT(2) ARM PUBLIC Entry_Point Entry_Point: __iar_init$$done: ; The interrupt vector is not needed ; until after copy initialization is done LDR PC, vector_reset LDR PC, vector_undef LDR PC, vector_swi LDR PC, vector_pabt LDR PC, vector_dabt LDR PC, vector_resv LDR PC, vector_irq LDR PC, vector_fiq vector_reset: DC32 Reset_Handler vector_undef: DC32 Undef_Handler vector_swi: DC32 SWI_Handler vector_pabt: DC32 PAbt_Handler vector_dabt: DC32 DAbt_Handler vector_resv: DC32 Resv_Handler vector_irq: DC32 IRQ_Handler vector_fiq: DC32 FIQ_Handler ;----------------- Reset Handler ----------------------------------------------- EXTERN rt_low_level_init EXTERN ?main PUBLIC __iar_program_start __iar_program_start: Reset_Handler: ; Set the cpu to SVC32 mode MRS R0, CPSR BIC R0, R0, #MODEMASK ORR R0, R0, #MODE_SVC|NOINT MSR CPSR_cxsf, R0 LDR SP, =SVC_STACK_START ; Call low level init function, ; disable and clear all IRQs and remap internal ram to 0x00000000. LDR R0, =rt_low_level_init BLX R0 ; Copy Exception Vectors to Internal RAM LDR R8, =Entry_Point ; Source LDR R9, =0x00000000 ; Destination CMP R8, R9 BEQ Setup_Stack LDMIA R8!, {R0-R7} ; Load Vectors STMIA R9!, {R0-R7} ; Store Vectors LDMIA R8!, {R0-R7} ; Load Handler Addresses STMIA R9!, {R0-R7} ; Store Handler Addresses Setup_Stack: ; Setup Stack for each mode MRS R0, CPSR BIC R0, R0, #MODEMASK ORR R1, R0, #MODE_UND|NOINT MSR CPSR_cxsf, R1 ; Undef mode LDR SP, =UND_STACK_START ORR R1,R0,#MODE_ABT|NOINT MSR CPSR_cxsf,R1 ; Abort mode LDR SP, =ABT_STACK_START ORR R1,R0,#MODE_IRQ|NOINT MSR CPSR_cxsf,R1 ; IRQ mode LDR SP, =IRQ_STACK_START ORR R1,R0,#MODE_FIQ|NOINT MSR CPSR_cxsf,R1 ; FIQ mode LDR SP, =FIQ_STACK_START ORR R1,R0,#MODE_SYS|NOINT MSR CPSR_cxsf,R1 ; SYS/User mode LDR SP, =SYS_STACK_START ORR R1,R0,#MODE_SVC|NOINT MSR CPSR_cxsf,R1 ; SVC mode LDR SP, =SVC_STACK_START ; Enter the C code LDR R0, =?main BLX R0 ;----------------- Exception Handler ------------------------------------------- IMPORT rt_hw_trap_udef IMPORT rt_hw_trap_swi IMPORT rt_hw_trap_pabt IMPORT rt_hw_trap_dabt IMPORT rt_hw_trap_resv IMPORT rt_hw_trap_irq IMPORT rt_hw_trap_fiq IMPORT rt_interrupt_enter IMPORT rt_interrupt_leave IMPORT rt_thread_switch_interrupt_flag IMPORT rt_interrupt_from_thread IMPORT rt_interrupt_to_thread SECTION .text:CODE:ROOT(2) ARM Undef_Handler: SUB SP, SP, #S_FRAME_SIZE STMIA SP, {R0 - R12} ; Calling R0-R12 ADD R8, SP, #S_PC STMDB R8, {SP, LR} ; Calling SP, LR STR LR, [R8, #0] ; Save calling PC MRS R6, SPSR STR R6, [R8, #4] ; Save CPSR STR R0, [R8, #8] ; Save SPSR MOV R0, SP BL rt_hw_trap_udef SWI_Handler: BL rt_hw_trap_swi PAbt_Handler: BL rt_hw_trap_pabt DAbt_Handler: SUB SP, SP, #S_FRAME_SIZE STMIA SP, {R0 - R12} ; Calling R0-R12 ADD R8, SP, #S_PC STMDB R8, {SP, LR} ; Calling SP, LR STR LR, [R8, #0] ; Save calling PC MRS R6, SPSR STR R6, [R8, #4] ; Save CPSR STR R0, [R8, #8] ; Save SPSR MOV R0, SP BL rt_hw_trap_dabt Resv_Handler: BL rt_hw_trap_resv IRQ_Handler: STMFD SP!, {R0-R12,LR} BL rt_interrupt_enter BL rt_hw_trap_irq BL rt_interrupt_leave ; If rt_thread_switch_interrupt_flag set, ; jump to rt_hw_context_switch_interrupt_do and don't return LDR R0, =rt_thread_switch_interrupt_flag LDR R1, [R0] CMP R1, #1 BEQ rt_hw_context_switch_interrupt_do LDMFD SP!, {R0-R12,LR} SUBS PC, LR, #4 FIQ_Handler: STMFD SP!, {R0-R7,LR} BL rt_hw_trap_fiq LDMFD SP!, {R0-R7,LR} SUBS PC, LR, #4 ;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) ----------------- rt_hw_context_switch_interrupt_do: MOV R1, #0 ; Clear flag STR R1, [R0] ; Save to flag variable LDMFD SP!, {R0-R12,LR} ; Reload saved registers STMFD SP!, {R0-R3} ; Save R0-R3 MOV R1, SP ; Save old task's SP to R1 ADD SP, SP, #16 ; Restore SP SUB R2, LR, #4 ; Save old task's PC to R2 MRS R3, SPSR ; Get CPSR of interrupt thread MSR CPSR_c, #MODE_SVC|NOINT ; Switch to SVC mode and no interrupt STMFD SP!, {R2} ; Push old task's PC STMFD SP!, {R4-R12,LR} ; Push old task's LR,R12-R4 MOV R4, R1 ; Special optimised code below MOV R5, R3 LDMFD R4!, {R0-R3} STMFD SP!, {R0-R3} ; Push old task's R3-R0 STMFD SP!, {R5} ; Push old task's CPSR MRS R4, SPSR STMFD SP!, {R4} ; Push old task's SPSR LDR R4, =rt_interrupt_from_thread LDR R5, [R4] ; R5 = stack ptr in old tasks's TCB STR SP, [R5] ; Store SP in preempted tasks's TCB LDR R6, =rt_interrupt_to_thread LDR R6, [R6] ; R6 = stack ptr in new tasks's TCB LDR SP, [R6] ; Get new task's stack pointer LDMFD SP!, {R4} ; Pop new task's SPSR MSR SPSR_cxsf, R4 LDMFD SP!, {R4} ; Pop new task's CPSR MSR SPSR_cxsf, R4 LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's R0-R12,LR & PC END