/*****************************************************************************
 * Copyright (c) 2001, 2002 Rowley Associates Limited.                       *
 *                                                                           *
 * This file may be distributed under the terms of the License Agreement     *
 * provided with this software.                                              *
 *                                                                           *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING THE   *
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
 *****************************************************************************/
  .section .init, "ax"
  .code 32
  .align 0
                
  .weak _start
  .global __start
  .global __gccmain
  .extern main
  .extern exit

/*****************************************************************************
 * Function    : _start                                                      *
 * Description : Main entry point and startup code for C system.             *
 *****************************************************************************/
_start:
__start:                        
  mrs r0, cpsr
  bic r0, r0, #0x1F

  /* Setup stacks */ 
  orr r1, r0, #0x1B /* Undefined mode */
  msr cpsr_cxsf, r1
  ldr sp, =__stack_und_end__
  
  orr r1, r0, #0x17 /* Abort mode */
  msr cpsr_cxsf, r1
  ldr sp, =__stack_abt_end__

  orr r1, r0, #0x12 /* IRQ mode */
  msr cpsr_cxsf, r1
  ldr sp, =__stack_irq_end__

  orr r1, r0, #0x11 /* FIQ mode */
  msr cpsr_cxsf, r1
  ldr sp, =__stack_fiq_end__

  orr r1, r0, #0x13 /* Supervisor mode */
  msr cpsr_cxsf, r1
  ldr sp, =__stack_svc_end__
#ifdef SUPERVISOR_START
  /* Start application in supervisor mode */
  ldr r1, =__stack_end__ /* Setup user/system mode stack */ 
  mov r2, sp
  stmfd r2!, {r1}
  ldmfd r2, {sp}^
#else
  /* Start application in system mode */
  orr r1, r0, #0x1F /* System mode */
  msr cpsr_cxsf, r1
  ldr sp, =__stack_end__
#endif
  
  /* Copy from initialised data section to data section (if necessary). */
  ldr r0, =__data_load_start__
  ldr r1, =__data_start__
  cmp r0, r1
  beq copy_data_end
  
  ldr r2, =__data_end__
  subs r2, r2, r1
  beq copy_data_end
  
copy_data_loop:
  ldrb r3, [r0], #+1
  strb r3, [r1], #+1
  subs r2, r2, #1
  bne copy_data_loop
copy_data_end:  

  /* Copy from initialised text section to text section (if necessary). */
  ldr r0, =__text_load_start__
  ldr r1, =__text_start__
  cmp r0, r1
  beq copy_text_end
  
  ldr r2, =__text_end__
  subs r2, r2, r1
  beq copy_text_end
  
copy_text_loop:
  ldrb r3, [r0], #+1
  strb r3, [r1], #+1
  subs r2, r2, #1
  bne copy_text_loop
copy_text_end:  

  /* Copy from initialised fast_text section to fast_text section (if necessary). */
  ldr r0, =__fast_load_start__
  ldr r1, =__fast_start__
  cmp r0, r1
  beq copy_fast_end
  
  ldr r2, =__fast_end__
  subs r2, r2, r1
  beq copy_fast_end
  
copy_fast_loop:
  ldrb r3, [r0], #+1
  strb r3, [r1], #+1
  subs r2, r2, #1
  bne copy_fast_loop
copy_fast_end:  

  /* Zero the bss. */
  ldr r0, =__bss_start__
  ldr r1, =__bss_end__
  mov r2, #0
zero_bss_loop:
  cmp r0, r1
  beq zero_bss_end
  strb r2, [r0], #+1
  b zero_bss_loop
zero_bss_end:    

#ifdef CHECK  
  /* Check data */
  ldr r0, =__data_load_start__
  ldr r1, =__data_start__
  cmp r0, r1
  beq check_data_end
  ldr r2, =__data_end__
  subs r2, r2, r1
  beq check_data_end
  
check_data_loop:
  ldrb r3, [r0], #+1
  ldrb r4, [r1], #+1
  cmp r3, r4
  bne data_error_loop
  subs r2, r2, #1
  bne check_data_loop
check_data_end:  

  /* Check text */
  ldr r0, =__text_load_start__
  ldr r1, =__text_start__
  cmp r0, r1
  beq check_text_end
  ldr r2, =__text_end__
  subs r2, r2, r1
  beq check_text_end
  
check_text_loop:
  ldrb r3, [r0], #+1
  ldrb r4, [r1], #+1
  cmp r3, r4
  bne text_error_loop
  subs r2, r2, #1
  bne check_text_loop
check_text_end:  

  /* Check fast */
  ldr r0, =__fast_load_start__
  ldr r1, =__fast_start__
  cmp r0, r1
  beq check_fast_end
  ldr r2, =__fast_end__
  subs r2, r2, r1
  beq check_fast_end
  
check_fast_loop:
  ldrb r3, [r0], #+1
  ldrb r4, [r1], #+1
  cmp r3, r4
  bne fast_error_loop
  subs r2, r2, #1
  bne check_fast_loop
check_fast_end:  

  /* Check bss */
  ldr r0, =__bss_start__
  ldr r1, =__bss_end__
  mov r2, #0
check_bss_loop:
  cmp r0, r1
  beq check_bss_end
  ldrb r2, [r0], #+1
  cmp r2, #0
  bne bss_error_loop  
  b check_bss_loop
check_bss_end:    
#endif

  /* Initialise the heap */
  ldr r0, = __heap_start__
  ldr r1, = __heap_end__
  sub r1, r1, r0     /* r1 = r1-r0 */ 
  mov r2, #0
  str r2, [r0], #+4 /* *r0++ = 0 */
  str r1, [r0]      /* *r0 = __heap_end__ - __heap_start__ */

  /* Call constructors */
  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
  mov pc, r2
  ldmfd sp!, {r0-r1}
  b ctor_loop
ctor_end:

  /* Setup initial call frame */
  mov lr, #4
  mov r12, sp
  stmfd sp!, {r11-r12, lr-pc}
  sub r11, r12, #0x00000004

start:
  /* Jump to main entry point */
  mov r0, #0
  mov r1, #0
  ldr r2, =main
  mov lr, pc
#ifdef __ARM_ARCH_3__
  mov pc, r2
#else    
  bx r2
#endif

  /* Call destructors */
  ldr r0, =__dtors_start__
  ldr r1, =__dtors_end__
dtor_loop:
  cmp r0, r1
  beq dtor_end
  ldr r2, [r0], #+4
  stmfd sp!, {r0-r1}
  mov lr, pc
  mov pc, r2
  ldmfd sp!, {r0-r1}
  b dtor_loop
dtor_end:

  /* Return from main, loop forever. */
exit_loop:
  b exit_loop

#ifdef CHECK
data_error_loop:
  b data_error_loop

text_error_loop:
  b text_error_loop
  
fast_error_loop:
  b fast_error_loop
  
bss_error_loop:
  b bss_error_loop  
#endif
  
                  
