diff options
Diffstat (limited to 'libgcc/config/sh/crt1.S')
-rw-r--r-- | libgcc/config/sh/crt1.S | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/libgcc/config/sh/crt1.S b/libgcc/config/sh/crt1.S new file mode 100644 index 0000000000..99579523e3 --- /dev/null +++ b/libgcc/config/sh/crt1.S @@ -0,0 +1,724 @@ +/* Copyright (C) 2000-2017 Free Software Foundation, Inc. + This file was pretty much copied from newlib. + +This file is part of GCC. + +GCC 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 3, or (at your option) any +later version. + +GCC 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#include "crt.h" + +#ifdef MMU_SUPPORT + /* Section used for exception/timer interrupt stack area */ + .section .data.vbr.stack,"aw" + .align 4 + .global __ST_VBR +__ST_VBR: + .zero 1024 * 2 /* ; 2k for VBR handlers */ +/* Label at the highest stack address where the stack grows from */ +__timer_stack: +#endif /* MMU_SUPPORT */ + + /* ;---------------------------------------- + Normal newlib crt1.S */ + + ! make a place to keep any previous value of the vbr register + ! this will only have a value if it has been set by redboot (for example) + .section .bss +old_vbr: + .long 0 +#ifdef PROFILE +profiling_enabled: + .long 0 +#endif + + + .section .text + .global start + .import ___rtos_profiler_start_timer + .weak ___rtos_profiler_start_timer +start: + mov.l stack_k,r15 + +#if defined (__SH3__) || (defined (__SH_FPU_ANY__) && ! defined (__SH2E__) && ! defined (__SH2A__)) || defined (__SH4_NOFPU__) +#define VBR_SETUP + ! before zeroing the bss ... + ! if the vbr is already set to vbr_start then the program has been restarted + ! (i.e. it is not the first time the program has been run since reset) + ! reset the vbr to its old value before old_vbr (in bss) is wiped + ! this ensures that the later code does not create a circular vbr chain + stc vbr, r1 + mov.l vbr_start_k, r2 + cmp/eq r1, r2 + bf 0f + ! reset the old vbr value + mov.l old_vbr_k, r1 + mov.l @r1, r2 + ldc r2, vbr +0: +#endif /* VBR_SETUP */ + + ! zero out bss + mov.l edata_k,r0 + mov.l end_k,r1 + mov #0,r2 +start_l: + mov.l r2,@r0 + add #4,r0 + cmp/ge r0,r1 + bt start_l + +#if defined (__SH_FPU_ANY__) + mov.l set_fpscr_k, r1 + mov #4,r4 + jsr @r1 + shll16 r4 ! Set DN bit (flush denormal inputs to zero) + lds r3,fpscr ! Switch to default precision +#endif /* defined (__SH_FPU_ANY__) */ + +#ifdef VBR_SETUP + ! save the existing contents of the vbr + ! there will only be a prior value when using something like redboot + ! otherwise it will be zero + stc vbr, r1 + mov.l old_vbr_k, r2 + mov.l r1, @r2 + ! setup vbr + mov.l vbr_start_k, r1 + ldc r1,vbr +#endif /* VBR_SETUP */ + + ! if an rtos is exporting a timer start fn, + ! then pick up an SR which does not enable ints + ! (the rtos will take care of this) + mov.l rtos_start_fn, r0 + mov.l sr_initial_bare, r1 + tst r0, r0 + bt set_sr + + mov.l sr_initial_rtos, r1 + +set_sr: + ! Set status register (sr) + ldc r1, sr + + ! arrange for exit to call fini + mov.l atexit_k,r0 + mov.l fini_k,r4 + jsr @r0 + nop + +#ifdef PROFILE + ! arrange for exit to call _mcleanup (via stop_profiling) + mova stop_profiling,r0 + mov.l atexit_k,r1 + jsr @r1 + mov r0, r4 + + ! Call profiler startup code + mov.l monstartup_k, r0 + mov.l start_k, r4 + mov.l etext_k, r5 + jsr @r0 + nop + + ! enable profiling trap + ! until now any trap 33s will have been ignored + ! This means that all library functions called before this point + ! (directly or indirectly) may have the profiling trap at the start. + ! Therefore, only mcount itself may not have the extra header. + mov.l profiling_enabled_k2, r0 + mov #1, r1 + mov.l r1, @r0 +#endif /* PROFILE */ + + ! call init + mov.l init_k,r0 + jsr @r0 + nop + + ! call the mainline + mov.l main_k,r0 + jsr @r0 + nop + + ! call exit + mov r0,r4 + mov.l exit_k,r0 + jsr @r0 + nop + + .balign 4 +#ifdef PROFILE +stop_profiling: + # stop mcount counting + mov.l profiling_enabled_k2, r0 + mov #0, r1 + mov.l r1, @r0 + + # call mcleanup + mov.l mcleanup_k, r0 + jmp @r0 + nop + + .balign 4 +mcleanup_k: + .long __mcleanup +monstartup_k: + .long ___monstartup +profiling_enabled_k2: + .long profiling_enabled +start_k: + .long _start +etext_k: + .long __etext +#endif /* PROFILE */ + + .align 2 +#if defined (__SH_FPU_ANY__) +set_fpscr_k: + .long ___set_fpscr +#endif /* defined (__SH_FPU_ANY__) */ + +stack_k: + .long _stack +edata_k: + .long _edata +end_k: + .long _end +main_k: + .long ___setup_argv_and_call_main +exit_k: + .long _exit +atexit_k: + .long _atexit +init_k: + .long GLOBAL(_init) +fini_k: + .long GLOBAL(_fini) +#ifdef VBR_SETUP +old_vbr_k: + .long old_vbr +vbr_start_k: + .long vbr_start +#endif /* VBR_SETUP */ + +sr_initial_rtos: + ! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work. + ! Whether profiling or not, keep interrupts masked, + ! the RTOS will enable these if required. + .long 0x600000f1 + +rtos_start_fn: + .long ___rtos_profiler_start_timer + +#ifdef PROFILE +sr_initial_bare: + ! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work. + ! For bare machine, we need to enable interrupts to get profiling working + .long 0x60000001 +#else + +sr_initial_bare: + ! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work. + ! Keep interrupts disabled - the application will enable as required. + .long 0x600000f1 +#endif + + ! supplied for backward compatibility only, in case of linking + ! code whose main() was compiled with an older version of GCC. + .global ___main +___main: + rts + nop +#ifdef VBR_SETUP +! Exception handlers + .section .text.vbr, "ax" +vbr_start: + + .org 0x100 +vbr_100: +#ifdef PROFILE + ! Note on register usage. + ! we use r0..r3 as scratch in this code. If we are here due to a trapa for profiling + ! then this is OK as we are just before executing any function code. + ! The other r4..r7 we save explicityl on the stack + ! Remaining registers are saved by normal ABI conventions and we assert we do not + ! use floating point registers. + mov.l expevt_k1, r1 + mov.l @r1, r1 + mov.l event_mask, r0 + and r0,r1 + mov.l trapcode_k, r2 + cmp/eq r1,r2 + bt 1f + bra handler_100 ! if not a trapa, go to default handler + nop +1: + mov.l trapa_k, r0 + mov.l @r0, r0 + shlr2 r0 ! trapa code is shifted by 2. + cmp/eq #33, r0 + bt 2f + bra handler_100 + nop +2: + + ! If here then it looks like we have trap #33 + ! Now we need to call mcount with the following convention + ! Save and restore r4..r7 + mov.l r4,@-r15 + mov.l r5,@-r15 + mov.l r6,@-r15 + mov.l r7,@-r15 + sts.l pr,@-r15 + + ! r4 is frompc. + ! r5 is selfpc + ! r0 is the branch back address. + ! The code sequence emitted by gcc for the profiling trap is + ! .align 2 + ! trapa #33 + ! .align 2 + ! .long lab Where lab is planted by the compiler. This is the address + ! of a datum that needs to be incremented. + sts pr, r4 ! frompc + stc spc, r5 ! selfpc + mov #2, r2 + not r2, r2 ! pattern to align to 4 + and r2, r5 ! r5 now has aligned address +! add #4, r5 ! r5 now has address of address + mov r5, r2 ! Remember it. +! mov.l @r5, r5 ! r5 has value of lable (lab in above example) + add #8, r2 + ldc r2, spc ! our return address avoiding address word + + ! only call mcount if profiling is enabled + mov.l profiling_enabled_k, r0 + mov.l @r0, r0 + cmp/eq #0, r0 + bt 3f + ! call mcount + mov.l mcount_k, r2 + jsr @r2 + nop +3: + lds.l @r15+,pr + mov.l @r15+,r7 + mov.l @r15+,r6 + mov.l @r15+,r5 + mov.l @r15+,r4 + rte + nop + .balign 4 +event_mask: + .long 0xfff +trapcode_k: + .long 0x160 +expevt_k1: + .long 0xff000024 ! Address of expevt +trapa_k: + .long 0xff000020 +mcount_k: + .long __call_mcount +profiling_enabled_k: + .long profiling_enabled +#endif + ! Non profiling case. +handler_100: + mov.l 2f, r0 ! load the old vbr setting (if any) + mov.l @r0, r0 + cmp/eq #0, r0 + bf 1f + ! no previous vbr - jump to own generic handler + bra handler + nop +1: ! there was a previous handler - chain them + add #0x7f, r0 ! 0x7f + add #0x7f, r0 ! 0xfe + add #0x2, r0 ! add 0x100 without corrupting another register + jmp @r0 + nop + .balign 4 +2: + .long old_vbr + + .org 0x400 +vbr_400: ! Should be at vbr+0x400 + mov.l 2f, r0 ! load the old vbr setting (if any) + mov.l @r0, r0 + cmp/eq #0, r0 + ! no previous vbr - jump to own generic handler + bt handler + ! there was a previous handler - chain them + rotcr r0 + rotcr r0 + add #0x7f, r0 ! 0x1fc + add #0x7f, r0 ! 0x3f8 + add #0x02, r0 ! 0x400 + rotcl r0 + rotcl r0 ! Add 0x400 without corrupting another register + jmp @r0 + nop + .balign 4 +2: + .long old_vbr +handler: + /* If the trap handler is there call it */ + mov.l superh_trap_handler_k, r0 + cmp/eq #0, r0 ! True if zero. + bf 3f + bra chandler + nop +3: + ! Here handler available, call it. + /* Now call the trap handler with as much of the context unchanged as possible. + Move trapping address into PR to make it look like the trap point */ + stc spc, r1 + lds r1, pr + mov.l expevt_k, r4 + mov.l @r4, r4 ! r4 is value of expevt, first parameter. + mov r1, r5 ! Remember trapping pc. + mov r1, r6 ! Remember trapping pc. + mov.l chandler_k, r1 + mov.l superh_trap_handler_k, r2 + ! jmp to trap handler to avoid disturbing pr. + jmp @r2 + nop + + .org 0x600 +vbr_600: +#ifdef PROFILE + ! Should be at vbr+0x600 + ! Now we are in the land of interrupts so need to save more state. + ! Save register state + mov.l interrupt_stack_k, r15 ! r15 has been saved to sgr. + mov.l r0,@-r15 + mov.l r1,@-r15 + mov.l r2,@-r15 + mov.l r3,@-r15 + mov.l r4,@-r15 + mov.l r5,@-r15 + mov.l r6,@-r15 + mov.l r7,@-r15 + sts.l pr,@-r15 + sts.l mach,@-r15 + sts.l macl,@-r15 +#if defined(__SH_FPU_ANY__) + ! Save fpul and fpscr, save fr0-fr7 in 64 bit mode + ! and set the pervading precision for the timer_handler + mov #0,r0 + sts.l fpul,@-r15 + sts.l fpscr,@-r15 + lds r0,fpscr ! Clear fpscr + fmov fr0,@-r15 + fmov fr1,@-r15 + fmov fr2,@-r15 + fmov fr3,@-r15 + mov.l pervading_precision_k,r0 + fmov fr4,@-r15 + fmov fr5,@-r15 + mov.l @r0,r0 + fmov fr6,@-r15 + fmov fr7,@-r15 + lds r0,fpscr +#endif /* __SH_FPU_ANY__ */ + ! Pass interrupted pc to timer_handler as first parameter (r4). + stc spc, r4 + mov.l timer_handler_k, r0 + jsr @r0 + nop +#if defined(__SH_FPU_ANY__) + mov #0,r0 + lds r0,fpscr ! Clear the fpscr + fmov @r15+,fr7 + fmov @r15+,fr6 + fmov @r15+,fr5 + fmov @r15+,fr4 + fmov @r15+,fr3 + fmov @r15+,fr2 + fmov @r15+,fr1 + fmov @r15+,fr0 + lds.l @r15+,fpscr + lds.l @r15+,fpul +#endif /* __SH_FPU_ANY__ */ + lds.l @r15+,macl + lds.l @r15+,mach + lds.l @r15+,pr + mov.l @r15+,r7 + mov.l @r15+,r6 + mov.l @r15+,r5 + mov.l @r15+,r4 + mov.l @r15+,r3 + mov.l @r15+,r2 + mov.l @r15+,r1 + mov.l @r15+,r0 + stc sgr, r15 ! Restore r15, destroyed by this sequence. + rte + nop +#if defined(__SH_FPU_ANY__) + .balign 4 +pervading_precision_k: + .long GLOBAL(__fpscr_values)+4 +#endif +#else + mov.l 2f, r0 ! Load the old vbr setting (if any). + mov.l @r0, r0 + cmp/eq #0, r0 + ! no previous vbr - jump to own handler + bt chandler + ! there was a previous handler - chain them + rotcr r0 + rotcr r0 + add #0x7f, r0 ! 0x1fc + add #0x7f, r0 ! 0x3f8 + add #0x7f, r0 ! 0x5f4 + add #0x03, r0 ! 0x600 + rotcl r0 + rotcl r0 ! Add 0x600 without corrupting another register + jmp @r0 + nop + .balign 4 +2: + .long old_vbr +#endif /* PROFILE code */ +chandler: + mov.l expevt_k, r4 + mov.l @r4, r4 ! r4 is value of expevt hence making this the return code + mov.l handler_exit_k,r0 + jsr @r0 + nop + ! We should never return from _exit but in case we do we would enter the + ! the following tight loop +limbo: + bra limbo + nop + .balign 4 +#ifdef PROFILE +interrupt_stack_k: + .long __timer_stack ! The high end of the stack +timer_handler_k: + .long __profil_counter +#endif +expevt_k: + .long 0xff000024 ! Address of expevt +chandler_k: + .long chandler +superh_trap_handler_k: + .long __superh_trap_handler +handler_exit_k: + .long _exit + .align 2 +! Simulated compile of trap handler. + .section .debug_abbrev,"",@progbits +.Ldebug_abbrev0: + .section .debug_info,"",@progbits +.Ldebug_info0: + .section .debug_line,"",@progbits +.Ldebug_line0: + .text +.Ltext0: + .align 5 + .type __superh_trap_handler,@function +__superh_trap_handler: +.LFB1: + mov.l r14,@-r15 +.LCFI0: + add #-4,r15 +.LCFI1: + mov r15,r14 +.LCFI2: + mov.l r4,@r14 + lds r1, pr + add #4,r14 + mov r14,r15 + mov.l @r15+,r14 + rts + nop +.LFE1: +.Lfe1: + .size __superh_trap_handler,.Lfe1-__superh_trap_handler + .section .debug_frame,"",@progbits +.Lframe0: + .ualong .LECIE0-.LSCIE0 +.LSCIE0: + .ualong 0xffffffff + .byte 0x1 + .string "" + .uleb128 0x1 + .sleb128 -4 + .byte 0x11 + .byte 0xc + .uleb128 0xf + .uleb128 0x0 + .align 2 +.LECIE0: +.LSFDE0: + .ualong .LEFDE0-.LASFDE0 +.LASFDE0: + .ualong .Lframe0 + .ualong .LFB1 + .ualong .LFE1-.LFB1 + .byte 0x4 + .ualong .LCFI0-.LFB1 + .byte 0xe + .uleb128 0x4 + .byte 0x4 + .ualong .LCFI1-.LCFI0 + .byte 0xe + .uleb128 0x8 + .byte 0x8e + .uleb128 0x1 + .byte 0x4 + .ualong .LCFI2-.LCFI1 + .byte 0xd + .uleb128 0xe + .align 2 +.LEFDE0: + .text +.Letext0: + .section .debug_info + .ualong 0xb3 + .uaword 0x2 + .ualong .Ldebug_abbrev0 + .byte 0x4 + .uleb128 0x1 + .ualong .Ldebug_line0 + .ualong .Letext0 + .ualong .Ltext0 + .string "trap_handler.c" + .string "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" + .string "GNU C 3.2 20020529 (experimental)" + .byte 0x1 + .uleb128 0x2 + .ualong 0xa6 + .byte 0x1 + .string "_superh_trap_handler" + .byte 0x1 + .byte 0x2 + .byte 0x1 + .ualong .LFB1 + .ualong .LFE1 + .byte 0x1 + .byte 0x5e + .uleb128 0x3 + .string "trap_reason" + .byte 0x1 + .byte 0x1 + .ualong 0xa6 + .byte 0x2 + .byte 0x91 + .sleb128 0 + .byte 0x0 + .uleb128 0x4 + .string "unsigned int" + .byte 0x4 + .byte 0x7 + .byte 0x0 + .section .debug_abbrev + .uleb128 0x1 + .uleb128 0x11 + .byte 0x1 + .uleb128 0x10 + .uleb128 0x6 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x1b + .uleb128 0x8 + .uleb128 0x25 + .uleb128 0x8 + .uleb128 0x13 + .uleb128 0xb + .byte 0x0 + .byte 0x0 + .uleb128 0x2 + .uleb128 0x2e + .byte 0x1 + .uleb128 0x1 + .uleb128 0x13 + .uleb128 0x3f + .uleb128 0xc + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x27 + .uleb128 0xc + .uleb128 0x11 + .uleb128 0x1 + .uleb128 0x12 + .uleb128 0x1 + .uleb128 0x40 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x5 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0x3a + .uleb128 0xb + .uleb128 0x3b + .uleb128 0xb + .uleb128 0x49 + .uleb128 0x13 + .uleb128 0x2 + .uleb128 0xa + .byte 0x0 + .byte 0x0 + .uleb128 0x4 + .uleb128 0x24 + .byte 0x0 + .uleb128 0x3 + .uleb128 0x8 + .uleb128 0xb + .uleb128 0xb + .uleb128 0x3e + .uleb128 0xb + .byte 0x0 + .byte 0x0 + .byte 0x0 + .section .debug_pubnames,"",@progbits + .ualong 0x27 + .uaword 0x2 + .ualong .Ldebug_info0 + .ualong 0xb7 + .ualong 0x67 + .string "_superh_trap_handler" + .ualong 0x0 + .section .debug_aranges,"",@progbits + .ualong 0x1c + .uaword 0x2 + .ualong .Ldebug_info0 + .byte 0x4 + .byte 0x0 + .uaword 0x0 + .uaword 0x0 + .ualong .Ltext0 + .ualong .Letext0-.Ltext0 + .ualong 0x0 + .ualong 0x0 +#endif /* VBR_SETUP */ |