;----------------------------------------------------------------------------- ; This file contains the startup code used by the V850 C/C++ compiler. ; ; Copyright (c) 1998-2009 IAR Systems AB. ; ; $Revision: 5028 $ ; ;----------------------------------------------------------------------------- ; ; Naming covention of labels in this file: ; ; ?xxx - External labels only accessed from assembler. ; __xxx - External labels accessed from or defined in C. ; xxx - Labels local to one module (note: this file contains ; several modules). ; main - The starting point of the user program. ; #include "lxx.h" #include "cfi.h" CASEON #define A0 R1 #define A1 R5 #define A2 R6 ;---------------------------------------------------------------; ; Call Frame Informatio ; ;---------------------------------------------------------------; CFNAMES CFCOMMON ;---------------------------------------------------------------; ; Reset Vector ; ;---------------------------------------------------------------; MODULE ?RESET PUBLIC ?creset EXTERN __program_start COMMON INTVEC:CODE:ROOT(2) ?creset: MOV __program_start, R1 JMP [R1] ENDMOD ;---------------------------------------------------------------; ; Module start. ; ;---------------------------------------------------------------; MODULE __program_start PUBLIC __program_start PUBLIC ?cstartup EXTERN ?creset REQUIRE ?creset ;---------------------------------------------------------------; ; Forward declarations of segments used in this module. ; ;---------------------------------------------------------------; RSEG CODE:CODE:NOROOT(2) RSEG CSTACK:DATA(2) ;---------------------------------------------------------------; ; The startup code. ; ;---------------------------------------------------------------; RSEG CSTART:CODE:NOROOT(1) ;; ;; The startup sequence contained in the final linked ;; application will consist of a mosaic containing ;; modules and segment parts defined in this file. ;; ;; The only part which is required is the call to ;; the function "main". ;; EXTERN ?cstart_call_main REQUIRE ?cstart_call_main EXTERN __cstart_low_level_init REQUIRE __cstart_low_level_init PUBLIC ?BTT_cstart_begin ?BTT_cstart_begin: ?cstartup: __program_start: ;---------------------------------------------------------------; ; Set up the stack and the global pointer. ; ;---------------------------------------------------------------; #if __CORE__ == __CORE_V850__ ;; If an interrupt is issued beteween the MOVEA and ;; MOVHI instructions the SP will point into ;; nowhere. To fix this problem we build the new SP ;; value in R1 and moves it with an atomic operation ;; to SP. MOVE_M SFE CSTACK, R1 MOV R1, SP #else MOVE_M SFE CSTACK, SP #endif EXTERN ?BREL_BASE MOVE_M ?BREL_BASE + 0x8000, GP EXTERN ?BREL_CBASE MOVE_M ?BREL_CBASE + 0x8000, R25 ;---------------------------------------------------------------; ; Setup constant registers. ; ;---------------------------------------------------------------; RSEG CSTART:CODE:NOROOT(1) PUBLIC ?INIT_REG ?INIT_REG: MOV 255, R18 ORI 65535, zero, R19 ENDMOD ;---------------------------------------------------------------; ; Initialize the saddr base pointers. ; ;---------------------------------------------------------------; MODULE ?INIT_SADDR_BASE RTMODEL "__reg_ep", "saddr" RSEG CSTART:CODE:NOROOT(1) PUBLIC ?INIT_SADDR_BASE ?INIT_SADDR_BASE: EXTERN ?SADDR_BASE MOVE_M ?SADDR_BASE, EP ENDMOD ;---------------------------------------------------------------; ; If hardware must be initialized from C or if watch dog timer ; ; must be handled or if the segment init should not be ; ; performed it can now be done in `__low_level_init'. ; ;---------------------------------------------------------------; ; Call the user function __low_level_init, if defined. ; ; It is the responsibility of __low_level_init to require ; ; __cstart_low_level_init in order to be called by cstartup. ; ;---------------------------------------------------------------; MODULE ?CSTART_LOW_LEVEL_INIT RSEG CSTART:CODE:NOROOT(1) PUBLIC __cstart_low_level_init EXTERN __low_level_init REQUIRE __low_level_init EXTERN ?no_seg_init __cstart_low_level_init: CALL_FUNC __low_level_init, LP, R1 ANDI 0xFF, R1, R1 BZ ?no_seg_init ENDMOD ;---------------------------------------------------------------; ; Segment initialization code. Copy initialized ROMmed code to ; ; RAM and ?seg_clear uninitialized variables. ; ;---------------------------------------------------------------; MODULE ?INIT_MEMORY ;---------------------------------------------------------------; ; Zero out NEAR_Z ; ;---------------------------------------------------------------; PUBLIC ?INIT_NEAR_Z RSEG NEAR_Z(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_clear ?INIT_NEAR_Z: MOVE_M SFB NEAR_Z, A0 MOVE_M SFE NEAR_Z, A1 JARL ?seg_clear, LP ;---------------------------------------------------------------; ; Zero out BREL_Z ; ;---------------------------------------------------------------; PUBLIC ?INIT_BREL_Z RSEG BREL_Z(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_clear ?INIT_BREL_Z: MOVE_M SFB BREL_Z, A0 MOVE_M SFE BREL_Z, A1 JARL ?seg_clear, LP ;---------------------------------------------------------------; ; Zero out SADDR7_Z ; ;---------------------------------------------------------------; PUBLIC ?INIT_SADDR7_Z RSEG SADDR7_Z(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_clear ?INIT_SADDR7_Z: MOVE_M SFB SADDR7_Z, A0 MOVE_M SFE SADDR7_Z, A1 JARL ?seg_clear, LP ;---------------------------------------------------------------; ; Zero out SADDR8_Z ; ;---------------------------------------------------------------; PUBLIC ?INIT_SADDR8_Z RSEG SADDR8_Z(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_clear ?INIT_SADDR8_Z: MOVE_M SFB SADDR8_Z, A0 MOVE_M SFE SADDR8_Z, A1 JARL ?seg_clear, LP ;---------------------------------------------------------------; ; Zero out BREL23_Z ; ;---------------------------------------------------------------; #if __CORE__ >= __CORE_V850E2M__ PUBLIC ?INIT_BREL23_Z RSEG BREL23_Z(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_clear ?INIT_BREL23_Z: MOVE_M SFB BREL23_Z, A0 MOVE_M SFE BREL23_Z, A1 JARL ?seg_clear, LP #endif ;---------------------------------------------------------------; ; Zero out HUGE_Z ; ;---------------------------------------------------------------; PUBLIC ?INIT_HUGE_Z RSEG HUGE_Z(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_clear ?INIT_HUGE_Z: MOVE_M SFB HUGE_Z, A0 MOVE_M SFE HUGE_Z, A1 JARL ?seg_clear, LP ;---------------------------------------------------------------; ; Copy NEAR_ID into NEAR_I ; ;---------------------------------------------------------------; PUBLIC ?INIT_NEAR_I RSEG NEAR_I(2) RSEG NEAR_ID(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_copy ?INIT_NEAR_I: MOVE_M SFB NEAR_ID, A0 MOVE_M SFE NEAR_ID, A1 MOVE_M SFB NEAR_I, A2 JARL ?seg_copy, LP ;---------------------------------------------------------------; ; Copy BREL_ID into BREL_I ; ;---------------------------------------------------------------; PUBLIC ?INIT_BREL_I RSEG BREL_I(2) RSEG BREL_ID(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_copy ?INIT_BREL_I: MOVE_M SFB BREL_ID, A0 MOVE_M SFE BREL_ID, A1 MOVE_M SFB BREL_I, A2 JARL ?seg_copy, LP ;---------------------------------------------------------------; ; Copy SADDR7_ID into SADDR7_I ; ;---------------------------------------------------------------; PUBLIC ?INIT_SADDR7_I RSEG SADDR7_I(2) RSEG SADDR7_ID(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_copy ?INIT_SADDR7_I: MOVE_M SFB SADDR7_ID, A0 MOVE_M SFE SADDR7_ID, A1 MOVE_M SFB SADDR7_I, A2 JARL ?seg_copy, LP ;---------------------------------------------------------------; ; Copy SADDR8_ID into SADDR8_I ; ;---------------------------------------------------------------; PUBLIC ?INIT_SADDR8_I RSEG SADDR8_I(2) RSEG SADDR8_ID(2) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_copy ?INIT_SADDR8_I: MOVE_M SFB SADDR8_ID, A0 MOVE_M SFE SADDR8_ID, A1 MOVE_M SFB SADDR8_I, A2 JARL ?seg_copy, LP ;---------------------------------------------------------------; ; Copy BREL23_ID into BREL23_I ; ;---------------------------------------------------------------; #if __CORE__ >= __CORE_V850E2M__ PUBLIC ?INIT_BREL23_I RSEG BREL23_I(1) RSEG BREL23_ID(1) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_copy ?INIT_BREL23_I: MOVE_M SFB BREL23_ID, A0 MOVE_M SFE BREL23_ID, A1 MOVE_M SFB BREL23_I, A2 JARL ?seg_copy, LP #endif ;---------------------------------------------------------------; ; Copy HUGE_ID into HUGE_I ; ;---------------------------------------------------------------; PUBLIC ?INIT_HUGE_I RSEG HUGE_I(1) RSEG HUGE_ID(1) RSEG CSTART:CODE:NOROOT(1) EXTERN ?seg_copy ?INIT_HUGE_I: MOVE_M SFB HUGE_ID, A0 MOVE_M SFE HUGE_ID, A1 MOVE_M SFB HUGE_I, A2 JARL ?seg_copy, LP ;---------------------------------------------------------------; ; Destination label when skipping data initialization. ; ;---------------------------------------------------------------; PUBLIC ?no_seg_init RSEG CSTART:CODE:NOROOT(1) ?no_seg_init: ENDMOD ;---------------------------------------------------------------; ; Calculate code distance (PIC only). ; ;---------------------------------------------------------------; MODULE ?INIT_PIC PUBLIC ?INIT_PIC RSEG CSTART:CODE:NOROOT(1) RTMODEL "__code_model", "pic" EXTERN ?CODE_DISTANCE EXTERN_LS_M ?INIT_PIC: JARL ref_point, A1 ref_point: MOVE_M ref_point, A2 SUB A2, A1 ;; Expands to correct store instruction/sequence. STORE_M A1, ?CODE_DISTANCE, A2 ;; Note: A1 (the value of ?CODE_DISTANCE) is used below! ENDMOD #if __CORE__ >= __CORE_V850E2M__ ;---------------------------------------------------------------; ; Initialize the BSEL system register bank selector. ; ;---------------------------------------------------------------; MODULE ?INIT_BSEL RSEG CSTART:CODE:NOROOT(1) PUBLIC ?INIT_BSEL ?INIT_BSEL: LDSR R0, 31 ; BSEL ENDMOD #endif #if __CORE__ >= __CORE_V850E__ ;---------------------------------------------------------------; ; Initialize the CALLT base pointers. ; ;---------------------------------------------------------------; MODULE ?INIT_CALLT PUBLIC ?INIT_CALLT EXTERN ?CALLT_BASE COMMON CLTVEC(2) RSEG CSTART:CODE:NOROOT(1) RTMODEL "__cpu", "v850e" REQUIRE ?CALLT_BASE ;; The Call table base pointer ?INIT_CALLT: MOVE_M SFB CLTVEC, A2 #ifdef CODE_MODEL_PIC EXTERN ?CODE_DISTANCE REQUIRE ?CODE_DISTANCE ;; Add the value of ?CODE_DISTANCE calculated above ADD A1, A2 #endif #if __CORE__ >= __CORE_V850E2M__ EXTERN ?INIT_BSEL REQUIRE ?INIT_BSEL #endif LDSR A2, 20 ; CTBP ENDMOD #endif #if __CORE__ >= __CORE_V850E2M__ ;---------------------------------------------------------------; ; Initialize the SYSCALL base pointers. ; ;---------------------------------------------------------------; MODULE ?INIT_SYSCALL PUBLIC ?INIT_SYSCALL EXTERN ?INIT_BSEL EXTERN ?SYSCALL_BASE COMMON SYSCALLVEC(2) RSEG CSTART:CODE:NOROOT(1) REQUIRE ?INIT_BSEL REQUIRE ?SYSCALL_BASE ;; The syscall table base pointer ?INIT_SYSCALL: MOVE_M SFB SYSCALLVEC, A2 #ifdef CODE_MODEL_PIC EXTERN ?CODE_DISTANCE REQUIRE ?CODE_DISTANCE ;; Add the value of ?CODE_DISTANCE calculated above ADD A1, A2 #endif LDSR A2, 12 ; SCBP MOVE_M ((SFE SYSCALLVEC - SFB SYSCALLVEC)/4) - 1, A2 LDSR A2, 11 ; SCCFG ENDMOD #endif ;---------------------------------------------------------------; ; This segment part is required by the compiler when it is ; ; necessary to call constructors of global objects. ; ;---------------------------------------------------------------; MODULE ?CALL_MAIN RSEG DIFUNCT(2) RSEG CSTART:CODE:NOROOT(1) PUBLIC ?cstart_call_ctors EXTERN __call_ctors ?cstart_call_ctors: MOVE_M SFB DIFUNCT, R1 MOVE_M SFE DIFUNCT, R5 CALL_FUNC __call_ctors, LP, R6 ;---------------------------------------------------------------; ; Call C main() with no parameters. ; ;---------------------------------------------------------------; RSEG CSTART:CODE:NOROOT(1) PUBLIC ?cstart_call_main EXTERN main EXTERN exit EXTERN __exit ?cstart_call_main: CALL_FUNC main, LP, R6 ;---------------------------------------------------------------; ; If we come here we have returned from main with a 'return' ; ; statement, not with a call to exit() or abort(). ; ; In this case we must call exit() here for a nice ending. ; ; Note: The return value of main() is the argument to exit(). ; ;---------------------------------------------------------------; CALL_FUNC exit, LP, R6 ;---------------------------------------------------------------; ; We should never come here, but just in case. ; ;---------------------------------------------------------------; MOV __exit, LP JMP [LP] PUBLIC ?BTT_cstart_end ?BTT_cstart_end: ;---------------------------------------------------------------; ; Copy a chunk of memory. ; ; A0 = Start of from block ; ; A1 = End of from block (+1) ; ; A2 = Start of to block ; ;---------------------------------------------------------------; PUBLIC ?seg_copy PUBLIC ?seg_clear RSEG CSTART:CODE:NOROOT(1) REQUIRE done cp_cont: LD.B 0[A0], R7 ADD 1, A0 ST.B R7, 0[A2] ADD 1, A2 ;; Note: The entry point is here. ?seg_copy: CMP A0, A1 BNE cp_cont RSEG CSTART:CODE:NOROOT(1) done: JMP [LP] ;---------------------------------------------------------------; ; Clear a chunk of memory. ; ; A0 = Start of block ; ; A1 = End of block (+1) ; ;---------------------------------------------------------------; RSEG CSTART:CODE:NOROOT(1) REQUIRE done ?seg_clear: CMP A0, A1 BE done cl_cont: ST.B zero, 0[A0] ADD 1, A0 BR ?seg_clear ENDMOD ;---------------------------------------------------------------; ; _exit code ; ; ; ; Call destructors (if required), then fall through to __exit. ; ;---------------------------------------------------------------; MODULE ?_exit PUBLIC _exit PUBLIC ?BTT_exit_begin EXTERN ?exit_restore2 RSEG RCODE:CODE:NOROOT(1) ?BTT_exit_begin: _exit: REQUIRE ?exit_restore2 ;; If any of the two pieces of code "__cstart_call_dtors" ;; or "__cstart_closeall" is called we need to save the ;; argument to "_exit". However, since we never will ;; from this function we can use a permanent register ;; rather than storing the value on the stack. RSEG RCODE:CODE:NOROOT(1) EXTERN ?exit_restore PUBLIC ?exit_save ?exit_save: REQUIRE ?exit_restore MOV R1, R29 RSEG RCODE:CODE:NOROOT(1) PUBLIC __cstart_call_dtors EXTERN __call_dtors REQUIRE ?exit_save ;; This label is required by "__record_needed_destruction". __cstart_call_dtors: CALL_FUNC __call_dtors, LP, R1 ENDMOD ;; A new module is needed so that a non-terminal-IO program ;; doesn't include this, which requires __putchar. MODULE ?__cstart_closeall RSEG RCODE:CODE:NOROOT(1) ;; When stdio is used, the following piece of code is ;; required by the _Closreg macro. PUBLIC __cstart_closeall EXTERN ?exit_save REQUIRE ?exit_save ;; This label is required by _Closreg __cstart_closeall: EXTERN _Close_all CALL_FUNC _Close_all, LP, R1 ENDMOD ;; Restore the argument previously stored by the "save" section ;; above. MODULE ?_exit_end RSEG RCODE:CODE:NOROOT(1) PUBLIC ?exit_restore EXTERN ?exit_restore2 ?exit_restore: REQUIRE ?exit_restore2 MOV R29, R1 ENDMOD MODULE ?_exit_end2 PUBLIC ?BTT_exit_end RSEG RCODE:CODE:NOROOT(1) PUBLIC ?exit_restore2 EXTERN __exit ?exit_restore2: MOV __exit, LP JMP [LP] ?BTT_exit_end: ENDMOD ;---------------------------------------------------------------; ; Define the base of the base relative (brel) data for RAM. ; ; ; ; This empty segment should be places in front of the brel ; ; RAM data segments. ; ;---------------------------------------------------------------; MODULE ?BREL_BASE PUBLIC ?BREL_BASE RSEG BREL_BASE:DATA:NOROOT(2) ?BREL_BASE: ENDMOD ;---------------------------------------------------------------; ; Define the base of the base relative (brel) data for ROM. ; ; ; ; This empty segment should be places in front of the brel ; ; ROM data segment. ; ;---------------------------------------------------------------; MODULE ?BREL_CBASE PUBLIC ?BREL_CBASE RSEG BREL_CBASE:CONST:NOROOT(2) ?BREL_CBASE: ENDMOD ;---------------------------------------------------------------; ; Define the base of the short addressing (saddr) data. ; ; ; ; This empty segment should be places in front of the saddr ; ; data segments. ; ;---------------------------------------------------------------; MODULE ?SADDR_BASE RTMODEL "__reg_ep", "saddr" PUBLIC ?SADDR_BASE RSEG SADDR_BASE:CONST:NOROOT(2) EXTERN ?INIT_SADDR_BASE REQUIRE ?INIT_SADDR_BASE ?SADDR_BASE: ENDMOD ;---------------------------------------------------------------; ; The base of the CALLT vector. ; ;---------------------------------------------------------------; MODULE ?CALLT_BASE PUBLIC ?CALLT_BASE COMMON CLTVEC:CONST:NOROOT(2) DATA ?CALLT_BASE: ENDMOD #if __CORE__ >= __CORE_V850E2M__ ;---------------------------------------------------------------; ; The base of the SYSCALL vector. ; ;---------------------------------------------------------------; MODULE ?SYSCALL_BASE PUBLIC ?SYSCALL_BASE COMMON SYSCALLVEC:CONST:NOROOT(2) DATA ?SYSCALL_BASE: ENDMOD #endif ;---------------------------------------------------------------; ; The distance the code has been moved when using position ; ; independent code. ; ;---------------------------------------------------------------; MODULE ?CODE_DISTANCE RTMODEL "__code_model", "pic" PUBLIC ?CODE_DISTANCE RSEG LIBRARY_N:DATA:NOROOT(2) EXTERN ?INIT_PIC REQUIRE ?INIT_PIC ?CODE_DISTANCE: DS 4 ENDMOD ;---------------------------------------------------------------; ; A dummy "low level init" that will be used if the user ; ; hasn't defined this function. ; ;---------------------------------------------------------------; MODULE ?__low_level_init_stub PUBLIC __low_level_init RSEG RCODE:CODE:NOROOT __low_level_init: MOV 1, R1 JMP [LP] ENDMOD END