.extern main                               /* ÒýÈëÍⲿCÈë¿Ú */

	.extern rt_interrupt_enter
	.extern rt_interrupt_leave
	.extern rt_thread_switch_interrupt_flag
	.extern rt_interrupt_from_thread
	.extern rt_interrupt_to_thread
	.extern rt_hw_trap_irq

	.global start
	.global endless_loop
    .global rt_hw_context_switch_interrupt_do

	/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs */
    .set  MODE_USR, 0x10            /* User Mode */
    .set  MODE_FIQ, 0x11            /* FIQ Mode */
    .set  MODE_IRQ, 0x12            /* IRQ Mode */
    .set  MODE_SVC, 0x13            /* Supervisor Mode */
    .set  MODE_ABT, 0x17            /* Abort Mode */
    .set  MODE_UND, 0x1B            /* Undefined Mode */
    .set  MODE_SYS, 0x1F            /* System Mode */

    .equ  I_BIT, 0x80               /* when I bit is set, IRQ is disabled */
    .equ  F_BIT, 0x40               /* when F bit is set, FIQ is disabled */
    .equ  I_Bit, 0x80               /* when I bit is set, IRQ is disabled */
    .equ  F_Bit, 0x40               /* when F bit is set, FIQ is disabled */

    /* VPBDIV definitions*/
    .equ  VPBDIV, 		0xE01FC100
    .set  VPBDIV_VALUE,	0x00000000

    /* Phase Locked Loop (PLL) definitions*/
    .equ  PLL_BASE, 	 0xE01FC080  /* PLL Base Address */
    .equ  PLLCON_OFS, 	 0x00        /* PLL Control Offset */
    .equ  PLLCFG_OFS, 	 0x04        /* PLL Configuration Offset */
    .equ  PLLSTAT_OFS, 	 0x08        /* PLL Status Offset */
    .equ  PLLFEED_OFS,   0x0C        /* PLL Feed Offset */
	.equ  PLLCON_PLLE,   (1<<0)      /* PLL Enable */
	.equ  PLLCON_PLLC,   (1<<1)      /* PLL Connect */
	.equ  PLLCFG_MSEL,   (0x1F<<0)   /* PLL Multiplier */
	.equ  PLLCFG_PSEL,   (0x03<<5)   /* PLL Divider */
	.equ  PLLSTAT_PLOCK, (1<<10)     /* PLL Lock Status */
    .equ  PLLCFG_Val,	 0x00000024  /* <o1.0..4>   MSEL: PLL Multiplier Selection,<o1.5..6>   PSEL: PLL Divider Selection */

    .equ  MEMMAP,		0xE01FC040     /*Memory Mapping Control*/


    /* Memory Accelerator Module (MAM) definitions*/
    .equ  MAM_BASE, 	0xE01FC000
    .equ  MAMCR_OFS, 	0x00
    .equ  MAMTIM_OFS, 	0x04
    .equ  MAMCR_Val,    0x00000002
    .equ  MAMTIM_Val,   0x00000004

    .equ  VICIntEnClr,	0xFFFFF014
    .equ  VICIntSelect,	0xFFFFF00C
/************* Ä¿±êÅäÖýáÊø *************/


/* Setup the operating mode & stack.*/
/* --------------------------------- */
	.global _reset
_reset:
	.code 32
	.align 0

/************************* PLL_SETUP **********************************/
		ldr     r0, =PLL_BASE
		mov		r1, #0xAA
		mov		r2, #0x55

/* Configure and Enable PLL */
		mov     r3, #PLLCFG_Val
		str     r3, [r0, #PLLCFG_OFS]
		mov     r3, #PLLCON_PLLE
		str     r3, [r0, #PLLCON_OFS]
		str     r1, [r0, #PLLFEED_OFS]
		str     r2, [r0, #PLLFEED_OFS]

/*  Wait until PLL Locked */
PLL_Locked_loop:
		ldr     r3, [r0, #PLLSTAT_OFS]
		ands    r3, r3, #PLLSTAT_PLOCK
		beq     PLL_Locked_loop

/*  Switch to PLL Clock */
		mov     r3, #(PLLCON_PLLE|PLLCON_PLLC)
		str     r3, [r0, #PLLCON_OFS]
		str     r1, [r0, #PLLFEED_OFS]
		str     R2, [r0, #PLLFEED_OFS]
/************************* PLL_SETUP **********************************/

/************************ Setup VPBDIV ********************************/
		ldr		r0, =VPBDIV
		ldr     r1, =VPBDIV_VALUE
		str		r1, [r0]
/************************ Setup VPBDIV ********************************/

/************** Setup MAM **************/
		ldr		r0, =MAM_BASE
		mov		r1, #MAMTIM_Val
		str		r1, [r0, #MAMTIM_OFS]
		mov		r1, #MAMCR_Val
		str		r1, [r0, #MAMCR_OFS]
/************** Setup MAM **************/

/************************ setup stack *********************************/
    ldr   r0, .undefined_stack_top
	sub   r0, r0, #4
    msr   CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction Mode */
    mov   sp, r0

    ldr   r0, .abort_stack_top
	sub   r0, r0, #4
    msr   CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */
    mov   sp, r0

    ldr   r0, .fiq_stack_top
	sub   r0, r0, #4
    msr   CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */
    mov   sp, r0

    ldr   r0, .irq_stack_top
	sub   r0, r0, #4
    msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */
    mov   sp, r0

    ldr   r0, .svc_stack_top
	sub   r0, r0, #4
    msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT  /* Supervisor Mode */
    mov   sp, r0
/************************ setup stack ********************************/

    /* copy .data to SRAM */
    ldr     r1, =_sidata            /* .data start in image */
    ldr     r2, =_edata             /* .data end in image   */
    ldr     r3, =_sdata             /* sram data start      */
data_loop:
    ldr     r0, [r1, #0]
    str     r0, [r3]

    add     r1, r1, #4
    add     r3, r3, #4

    cmp     r3, r2                   /* check if data to clear */
    blo     data_loop                /* loop until done        */
	
    /* clear .bss */
    mov     r0,#0                   /* get a zero */
    ldr     r1,=__bss_start         /* bss start  */
    ldr     r2,=__bss_end           /* bss end    */

bss_loop:
    cmp     r1,r2                   /* check if data to clear */
    strlo   r0,[r1],#4              /* clear 4 bytes          */
    blo     bss_loop                /* loop until done        */


    /* call C++ constructors of global objects */
    ldr     r0, =__ctors_start__
    ldr     r1, =__ctors_end__

ctor_loop:
    cmp     r0, r1
    beq     ctor_end
    ldr     r2, [r0], #4
    stmfd   sp!, {r0-r1}
    mov     lr, pc
    bx      r2
    ldmfd   sp!, {r0-r1}
    b       ctor_loop
ctor_end:

	/* enter C code */
	bl		main

	.align 0
	.undefined_stack_top:
	.word   _undefined_stack_top
	.abort_stack_top:
	.word   _abort_stack_top
	.fiq_stack_top:
	.word   _fiq_stack_top
	.irq_stack_top:
	.word   _irq_stack_top
	.svc_stack_top:
	.word   _svc_stack_top
/*********************** END Clear BSS  ******************************/

.section .init,"ax"
.code 32
.align 0
.globl _start
_start:

	ldr   pc, __start					/* reset - _start			*/
	ldr   pc, _undf						/* undefined - _undf		*/
	ldr   pc, _swi			    		/* SWI - _swi				*/
	ldr   pc, _pabt						/* program abort - _pabt	*/
	ldr   pc, _dabt						/* data abort - _dabt		*/
	.word 0xB8A06F58					/* reserved                 */
	ldr   pc, __IRQ_Handler				/* IRQ - read the VIC		*/
	ldr   pc, _fiq						/* FIQ - _fiq				*/

__start:.word _reset
_undf:  .word __undf                    /* undefined				*/
_swi:   .word __swi                     /* SWI						*/
_pabt:  .word __pabt                    /* program abort			*/
_dabt:  .word __dabt                    /* data abort				*/
temp1:  .word 0
__IRQ_Handler:  .word IRQ_Handler
_fiq:   .word __fiq                     /* FIQ						*/

__undf: b     .                         /* undefined				*/
__swi : b     .
__pabt: b     .                         /* program abort			*/
__dabt: b     .                         /* data abort				*/
__fiq : b     .  					    /* FIQ						*/

/* IRQÈë¿Ú */
IRQ_Handler :
		stmfd	sp!, {r0-r12,lr} 			   /* ¶ÔR0 ¨C R12£¬LR¼Ä´æÆ÷ѹջ      */
		bl	rt_interrupt_enter	 			   /* ֪ͨRT-Thread½øÈëÖжÏģʽ     */
		bl	rt_hw_trap_irq		 			   /* ÏàÓ¦ÖжϷþÎñÀý³Ì´¦Àí  	    */
		bl	rt_interrupt_leave		           /* ; ֪ͨRT-ThreadÒªÀ뿪ÖжÏģʽ */

		/* Èç¹ûÉèÖÃÁËrt_thread_switch_interrupt_flag£¬½øÐÐÖжÏÖеÄÏß³ÌÉÏÏÂÎÄ´¦Àí */
		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					   /* ´ÓIRQÖзµ»Ø */

/*
* 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]			/* */

				ldmfd	sp!, {r0-r12,lr}/* reload saved registers */
										/* ÏȻָ´±»ÖжÏÏ̵߳ÄÉÏÏÂÎÄ */
				stmfd	sp!, {r0-r3}	/* save r0-r3 */
										/* ¶ÔR0 ¨C R3ѹջ£¬ÒòΪºóÃæ»áÓõ½ */
				mov	r1,  sp				/* °Ñ´Ë´¦µÄÕ»Öµ±£´æµ½R1 */
				add	sp,  sp, #16		/* restore sp */
										/* »Ö¸´IRQµÄÕ»£¬ºóÃæ»áÌø³öIRQģʽ */
				sub	r2,  lr, #4			/* save old task's pc to r2 */
										/* ±£´æÇл»³öÏ̵߳ÄPCµ½R2 */

				mrs	r3,  spsr			/* disable interrupt ±£´æÖжÏÇ°µÄCPSRµ½R3¼Ä´æÆ÷ */
										/* »ñµÃSPSR¼Ä´æÆ÷Öµ */
				orr	r0,  r3, #I_BIT|F_BIT
				msr	spsr_c, r0			/*  ¹Ø±ÕSPSRÖеÄIRQ/FIQÖÐ¶Ï */

				ldr	r0,  =.+8		    /* °Ñµ±Ç°µØÖ·+8ÔØÈëµ½R0¼Ä´æÆ÷ÖÐ switch to interrupted task's stack */
				movs pc,  r0            /* Í˳öIRQģʽ£¬ÓÉÓÚSPSR±»ÉèÖóɹØÖжÏģʽ */
										/* ËùÒÔ´ÓIRQ·µ»Øºó£¬Öжϲ¢Ã»Óдò¿ª
										; R0¼Ä´æÆ÷ÖеÄλÖÃʵ¼Ê¾ÍÊÇÏÂÒ»ÌõÖ¸Á
										; ¼´PC¼ÌÐøÍùÏÂ×ß
										; ´Ëʱ
										; ģʽÒѾ­»»³ÉÖжÏÇ°µÄSVCģʽ£¬
										; SP¼Ä´æÆ÷Ò²ÊÇSVCģʽϵÄÕ»¼Ä´æÆ÷
										; R1±£´æIRQģʽϵÄÕ»Ö¸Õë
										; R2±£´æÇл»³öÏ̵߳ÄPC
										; R3±£´æÇл»³öÏ̵߳ÄCPSR */
				stmfd	sp!, {r2}		/* push old task's pc */
										/* ±£´æÇл»³öÈÎÎñµÄPC */
				stmfd	sp!, {r4-r12,lr}/* push old task's lr,r12-r4 */
										/* ±£´æR4 ¨C R12£¬LR¼Ä´æÆ÷ */
				mov	r4,  r1				/* Special optimised code below */
										/* R1±£´æÓÐѹջR0 ¨C R3´¦µÄջλÖà */
				mov	r5,  r3				/* R3Çл»³öÏ̵߳ÄCPSR */
				ldmfd	r4!, {r0-r3}	/* »Ö¸´R0 ¨C R3 */
				stmfd	sp!, {r0-r3}	/* push old task's r3-r0 */
										/*  R0 ¨C R3ѹջµ½Çл»³öÏß³Ì */
				stmfd	sp!, {r5}		/* push old task's psr */
										/* Çл»³öÏß³ÌCPSRѹջ */
				mrs	r4,  spsr
				stmfd	sp!, {r4}		/* push old task's spsr */
										/* Çл»³öÏß³ÌSPSRѹջ */

				ldr	r4,  =rt_interrupt_from_thread
				ldr	r5,  [r4]
				str	sp,  [r5]			/* store sp in preempted tasks's TCB */
										/* ±£´æÇл»³öÏ̵߳ÄSPÖ¸Õë */

				ldr	r6,  =rt_interrupt_to_thread
				ldr	r6,  [r6]
				ldr	sp,  [r6]			/* get new task's stack pointer */
										/* »ñµÃÇл»µ½Ï̵߳ÄÕ» */

				ldmfd	sp!, {r4}		/* pop new task's spsr */
										/* »Ö¸´SPSR */
				msr	SPSR_cxsf, r4
				ldmfd	sp!, {r4}		/* pop new task's psr */
										/* »Ö¸´CPSR */
				msr	CPSR_cxsf, r4

				ldmfd	sp!, {r0-r12,lr,pc}	/* pop new task's r0-r12,lr & pc */
											/* »Ö¸´R0 ¨C R12£¬LR¼°PC¼Ä´æÆ÷ */

/* ´úÂë¼ÓÃܹ¦ÄÜ */
#if defined(CODE_PROTECTION)
.org 0x01FC
.word 0x87654321
#endif