Cygwin: pinfo: raise MAX_PID to 4194304
[newlib-cygwin.git] / libgloss / or1k / crt0.S
blob74a0409811f03aabb5f90606bb6528415f60d2cc
1 /* crt0.S -- startup file for OpenRISC 1000.
2  *
3  * Copyright (c) 2011, 2014 Authors
4  *
5  * Contributor Julius Baxter <juliusbaxter@gmail.com>
6  * Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de>
7  *
8  * The authors hereby grant permission to use, copy, modify, distribute,
9  * and license this software and its documentation for any purpose, provided
10  * that existing copyright notices are retained in all copies and that this
11  * notice is included verbatim in any distributions. No written agreement,
12  * license, or royalty fee is required for any of the authorized uses.
13  * Modifications to this software may be copyrighted by their authors
14  * and need not follow the licensing terms described here, provided that
15  * the new terms are clearly indicated on the first page of each file where
16  * they apply.
17  */
19 /* -------------------------------------------------------------------------- */
20 /* Coding convention:
21    Assembly is hard to read per se, so please follow the following coding
22    conventions to keep it consistent and ease reading:
23     * internal jump labels start with L, no identation
24     * assemble lines have one tab identation
25     * attributes (.section, .global, ..) are indented with one tab
26     * code is structured using tabs, i.e., use 'l.sw\t0(r1),r1' with a single
27       tab. libgloss assumes 8 space tab width, so that might look unstructured
28       with tab widths below 6. Nevertheless don't use spaces or two tabs.
29     * no space after comma
30     * use the defined macros if possible as they reduce errors
31     * use OR1K_INST with OR1K_DELAYED(_NOP)
32     * OR1K_DELAYED is multiline for better readability, the inner parts are
33       indented with another tab.
34     * COMMENT! Try to accompy every line with a meaningful comment. If possible
35       use pseudo code to describe the code. Also mention intentions and not only
36       the obvious things..                                                    */
37 /* -------------------------------------------------------------------------- */
39 #include "newlib.h"
40 #include "include/or1k-asm.h"
41 #include "include/or1k-sprs.h"
43 /* -------------------------------------------------------------------------- */
44 // Stack definitions
45 /* -------------------------------------------------------------------------- */
47 // Stacks
48 // Memory layout:
49 //  +--------------------+ <- board_mem_base+board_mem_size/exception_stack_top
50 //  | exception stack(s) |
51 //  +--------------------+ <- stack_top
52 //  |     stack(s)       |
53 //  +--------------------+ <- stack_bottom
54 //  |      heap          |
55 //  +--------------------+
56 //  | text, data, bss..  |
57 //  +--------------------+
59 // Reserved stack size
60 #define STACK_SIZE 8192
62 // Reserved stack size for exceptions (can usually be smaller than normal stack)
63 #define EXCEPTION_STACK_SIZE 8192
65 // Size of space required to store state
66 // This value must match that in the support library or1k_exception_handler
67 // function
68 #define EXCEPTION_STACK_FRAME 136
70 #define REDZONE 128
72         .extern _or1k_stack_top    /* points to the next address after the stack */
73         .extern _or1k_stack_bottom /* points to the last address in the stack */
74         .extern _or1k_exception_stack_top
75         .extern _or1k_exception_stack_bottom
76         .extern _or1k_exception_level /* Nesting level of exceptions */
78         .section .data
79         .global _or1k_stack_size /* reserved stack size */
80         .global _or1k_exception_stack_size
81         .global _or1k_exception_level
83 _or1k_stack_size:               .word STACK_SIZE
84 _or1k_exception_stack_size:     .word EXCEPTION_STACK_SIZE
86 #ifdef __OR1K_MULTICORE__
87         .extern _or1k_stack_core
88         .extern _or1k_exception_stack_core
89 #endif
91 #define SHADOW_REG(x) (OR1K_SPR_SYS_GPR_BASE + 32 + x)
93 /* -------------------------------------------------------------------------- */
94 /*!Macro to handle exceptions.
96   Load NPC into r3, EPCR into r4
97                                                                               */
98 /* -------------------------------------------------------------------------- */
100 #ifdef _HAVE_INITFINI_ARRAY
101 #define _init   __libc_init_array
102 #define _fini   __libc_fini_array
103 #endif
105 #define GPR_BUF_OFFSET(x) (x << 2)
107 #ifndef __OR1K_MULTICORE__
108 #define CALL_EXCEPTION_HANDLER(id)                              \
109         /* Store current stack pointer to address 4 */          \
110         l.sw    0x4(r0),r1;                                     \
111         /* Load address of exception nesting level */           \
112         l.movhi r1,hi(_or1k_exception_level);                   \
113         l.ori   r1,r1,lo(_or1k_exception_level);                \
114         /* Load the current nesting level */                    \
115         l.lwz   r1,0(r1);                                       \
116         /* Set flag if this is the outer (first) exception */   \
117         l.sfeq  r1,r0;                                          \
118         /* Branch to the code for nested exceptions */          \
119         OR1K_DELAYED_NOP(                                       \
120                 OR1K_INST(l.bnf .Lnested_##id)                  \
121         );                                                      \
122         /* Load top of the exception stack */                   \
123         l.movhi r1,hi(_or1k_exception_stack_top);               \
124         l.ori   r1,r1,lo(_or1k_exception_stack_top);            \
125         OR1K_DELAYED(                                           \
126                 /* Load value from array to stack pointer */    \
127                 OR1K_INST(l.lwz r1,0(r1)),                      \
128                 /* and jump over the nested code */             \
129                 OR1K_INST(l.j   .Lnesting_done_##id)            \
130         );                                                      \
131 .Lnested_##id:                                                  \
132         /* Load back the stack pointer */                       \
133         l.lwz   r1,0x4(r0);                                     \
134         /* Add redzone, nesting needs this */                   \
135         l.addi  r1,r1,-REDZONE;                                 \
136 .Lnesting_done_##id:                                            \
137         /* Reserve red zone and context space */                \
138         l.addi  r1,r1,-EXCEPTION_STACK_FRAME;                   \
139         /* Store GPR3 in context */                             \
140         l.sw    GPR_BUF_OFFSET(3)(r1),r3;                       \
141         /* Load back software's stack pointer */                \
142         l.lwz   r3,0x4(r0);                                     \
143         /* Store this in the context */                         \
144         l.sw    GPR_BUF_OFFSET(1)(r1),r3;                       \
145         /* Store GPR4 in the context */                         \
146         l.sw    GPR_BUF_OFFSET(4)(r1),r4;                       \
147         /* Load address of the exception level */               \
148         l.movhi r3,hi(_or1k_exception_level);                   \
149         l.ori   r3,r3,lo(_or1k_exception_level);                \
150         /* Load current value */                                \
151         l.lwz   r4,0(r3);                                       \
152         /* Increment level */                                   \
153         l.addi  r4,r4,1;                                        \
154         /* Store back */                                        \
155         l.sw    0(r3),r4;                                       \
156         /* Copy the current program counter as first */         \
157         /* argument for the exception handler. This */          \
158         /* is then used to determine the exception. */          \
159         l.mfspr r3,r0,OR1K_SPR_SYS_NPC_ADDR;                    \
160         OR1K_DELAYED(                                           \
161         /* Copy program counter of exception as */              \
162         /* second argument to the exception handler */          \
163                 OR1K_INST(l.mfspr r4,r0,OR1K_SPR_SYS_EPCR_BASE),\
164         /* Jump to exception handler. This will rfe */          \
165                 OR1K_INST(l.j _or1k_exception_handler)          \
166         )
167 #else
168 #define CALL_EXCEPTION_HANDLER(id)                              \
169         /* Store current stack pointer to shadow reg */         \
170         l.mtspr r0,r1,SHADOW_REG(1);                            \
171         /* Store current GPR3 for temporary use */              \
172         l.mtspr r0,r3,SHADOW_REG(2);                            \
173         /* Store current GPR2 for the level pointer */          \
174         l.mtspr r0,r4,SHADOW_REG(3);                            \
175         /* Load nesting level of exceptions */                  \
176         l.movhi r4,hi(_or1k_exception_level);                   \
177         l.ori   r4,r4,lo(_or1k_exception_level);                \
178         /* Load array pointer */                                \
179         l.lwz   r4,0(r4);                                       \
180         /* Get core id */                                       \
181         l.mfspr r3,r0,OR1K_SPR_SYS_COREID_ADDR;                 \
182         /* Generate offset */                                   \
183         l.slli  r3,r3,2;                                        \
184         /* Generate core nesting level address */               \
185         l.add   r4,r4,r3;                                       \
186         /* Load nesting level */                                \
187         l.lwz   r3,0(r4);                                       \
188         /* Increment nesting level */                           \
189         l.addi  r3,r3,1;                                        \
190         /* Write back nesting level */                          \
191         l.sw    0(r4),r3;                                       \
192         /* Set flag if this is the outer (first) exception */   \
193         l.sfeqi r3,1;                                           \
194         /* Branch to the code for nested exceptions */          \
195         OR1K_DELAYED_NOP(                                       \
196                 OR1K_INST(l.bnf .Lnested_##id)                  \
197         );                                                      \
198         /* Load pointer to exception stack array */             \
199         l.movhi r1,hi(_or1k_exception_stack_core);              \
200         l.ori   r1,r1,lo(_or1k_exception_stack_core);           \
201         l.lwz   r1,0(r1);                                       \
202         /* Get core id */                                       \
203         l.mfspr r3,r0,OR1K_SPR_SYS_COREID_ADDR;                 \
204         /* Calculate offset in array */                         \
205         l.slli  r3,r3,2;                                        \
206         l.add   r1,r1,r3;                                       \
207         OR1K_DELAYED(                                           \
208                 /* Load value from array to stack pointer */    \
209                 OR1K_INST(l.lwz r1,0(r1)),                      \
210                 /* and jump over nested exception pointer */    \
211                 OR1K_INST(l.j .Lnesting_done_##id)              \
212         );                                                      \
213 .Lnested_##id:                                                  \
214         /* The stack pointer is still active */                 \
215         /* Add redzone, nesting needs this */                   \
216         l.addi  r1,r1,-REDZONE;                                 \
217 .Lnesting_done_##id:                                            \
218         /* Reserve context space */                             \
219         l.addi  r1,r1,-EXCEPTION_STACK_FRAME;                   \
220         /* Load back software's stack pointer */                \
221         l.mfspr r3,r0,SHADOW_REG(1);                            \
222         /* Store this in the context */                         \
223         l.sw    GPR_BUF_OFFSET(1)(r1),r3;                       \
224         /* Load back GPR3 */                                    \
225         l.mfspr r3,r0,SHADOW_REG(2);                            \
226         /* Store this in the context */                         \
227         l.sw    GPR_BUF_OFFSET(3)(r1),r3;                       \
228         /* Load back GPR4 */                                    \
229         l.mfspr r4,r0,SHADOW_REG(3);                            \
230         /* Store GPR4 in the context */                         \
231         l.sw    GPR_BUF_OFFSET(4)(r1),r4;                       \
232         /* Copy the current program counter as first */         \
233         /* argument for the exception handler. This */          \
234         /* is then used to determine the exception. */          \
235         l.mfspr r3,r0,OR1K_SPR_SYS_NPC_ADDR;                    \
236         OR1K_DELAYED(                                           \
237         /* Copy program counter of exception as */              \
238         /* second argument to the exception handler */          \
239                 OR1K_INST(l.mfspr r4,r0,OR1K_SPR_SYS_EPCR_BASE),\
240         /* Jump to exception handler. This will rfe */          \
241                 OR1K_INST(l.j _or1k_exception_handler)          \
242         )
243 #endif
245 /* -------------------------------------------------------------------------- */
246 /*!Exception vectors                                                          */
247 /* -------------------------------------------------------------------------- */
248         .section .vectors,"ax"
250         /* 0x100: RESET exception */
251         .org 0x100
252 _or1k_reset:
253         l.movhi r0,0
254 #ifdef __OR1K_MULTICORE__
255         // This is a hack that relies on the fact, that all cores start at the
256         // same time and they are similarily fast
257         l.sw    0x4(r0),r0
258         // Similarly, we use address 8 to signal how many cores have exit'ed
259         l.sw    0x8(r0),r0
260 #endif
261         l.movhi r1,0
262         l.movhi r2,0
263         l.movhi r3,0
264         l.movhi r4,0
265         l.movhi r5,0
266         l.movhi r6,0
267         l.movhi r7,0
268         l.movhi r8,0
269         l.movhi r9,0
270         l.movhi r10,0
271         l.movhi r11,0
272         l.movhi r12,0
273         l.movhi r13,0
274         l.movhi r14,0
275         l.movhi r15,0
276         l.movhi r16,0
277         l.movhi r17,0
278         l.movhi r18,0
279         l.movhi r19,0
280         l.movhi r20,0
281         l.movhi r21,0
282         l.movhi r22,0
283         l.movhi r23,0
284         l.movhi r24,0
285         l.movhi r25,0
286         l.movhi r26,0
287         l.movhi r27,0
288         l.movhi r28,0
289         l.movhi r29,0
290         l.movhi r30,0
291         l.movhi r31,0
293         /* Clear status register, set supervisor mode */
294         l.ori   r1,r0,OR1K_SPR_SYS_SR_SM_MASK
295         l.mtspr r0,r1,OR1K_SPR_SYS_SR_ADDR
296         /* Clear timer mode register*/
297         l.mtspr r0,r0,OR1K_SPR_TICK_TTMR_ADDR
298         /* Jump to program initialisation code */
299         LOAD_SYMBOL_2_GPR(r4, _or1k_start)
300         OR1K_DELAYED_NOP(OR1K_INST(l.jr r4))
302         .org 0x200
303         CALL_EXCEPTION_HANDLER(2)
305         /* 0x300: Data Page Fault exception */
306         .org 0x300
307         CALL_EXCEPTION_HANDLER(3)
309         /* 0x400: Insn Page Fault exception */
310         .org 0x400
311         CALL_EXCEPTION_HANDLER(4)
313         /* 0x500: Timer exception */
314         .org 0x500
315         CALL_EXCEPTION_HANDLER(5)
317         /* 0x600: Aligment exception */
318         .org 0x600
319         CALL_EXCEPTION_HANDLER(6)
321         /* 0x700: Illegal insn exception */
322         .org 0x700
323         CALL_EXCEPTION_HANDLER(7)
325         /* 0x800: External interrupt exception */
326         .org 0x800
327         CALL_EXCEPTION_HANDLER(8)
329         /* 0x900: DTLB miss exception */
330         .org 0x900
331         CALL_EXCEPTION_HANDLER(9)
333         /* 0xa00: ITLB miss exception */
334         .org 0xa00
335         CALL_EXCEPTION_HANDLER(10)
337         /* 0xb00: Range exception */
338         .org 0xb00
339         CALL_EXCEPTION_HANDLER(11)
341         /* 0xc00: Syscall exception */
342         .org 0xc00
343         CALL_EXCEPTION_HANDLER(12)
345         /* 0xd00: Floating point exception */
346         .org 0xd00
347         CALL_EXCEPTION_HANDLER(13)
349         /* 0xe00: Trap exception */
350         .org 0xe00
351         CALL_EXCEPTION_HANDLER(14)
353         /* 0xf00: Reserved exceptions */
354         .org 0xf00
355         CALL_EXCEPTION_HANDLER(15)
357         .org 0x1000
358         CALL_EXCEPTION_HANDLER(16)
360         .org 0x1100
361         CALL_EXCEPTION_HANDLER(17)
363         .org 0x1200
364         CALL_EXCEPTION_HANDLER(18)
366         .org 0x1300
367         CALL_EXCEPTION_HANDLER(19)
369         .org 0x1400
370         CALL_EXCEPTION_HANDLER(20)
372         .org 0x1500
373         CALL_EXCEPTION_HANDLER(21)
375         .org 0x1600
376         CALL_EXCEPTION_HANDLER(22)
378         .org 0x1700
379         CALL_EXCEPTION_HANDLER(23)
381         .org 0x1800
382         CALL_EXCEPTION_HANDLER(24)
384         .org 0x1900
385         CALL_EXCEPTION_HANDLER(25)
387         .org 0x1a00
388         CALL_EXCEPTION_HANDLER(26)
390         .org 0x1b00
391         CALL_EXCEPTION_HANDLER(27)
393         .org 0x1c00
394         CALL_EXCEPTION_HANDLER(28)
396         .org 0x1d00
397         CALL_EXCEPTION_HANDLER(29)
399         .org 0x1e00
400         CALL_EXCEPTION_HANDLER(30)
402         .org 0x1f00
403         CALL_EXCEPTION_HANDLER(31)
405         /* Pad to the end */
406         .org 0x1ffc
407         l.nop
409 /* -------------------------------------------------------------------------- */
410 /*!Main entry point
412   This is the initialization code of the library. It performs these steps:
414    * Call early board initialization:
415      Before anything happened, the board support may do some very early
416      initialization. This is at maximum some very basic stuff that would
417      otherwise prevent the following code from functioning. Other initialization
418      of peripherals etc. is done later (before calling main).
419      See the description below and README.board for details.
421    * Initialize the stacks:
422      Two stacks are configured: The system stack is used by the software and
423      the exception stack is used when an exception occurs. We added this as
424      this should be flexible with respect to the usage of virtual memory.
426    * Activate the caches:
427      If available the caches are initiliazed and activated.
429    * Clear BSS:
430      The BSS are essentially the uninitialized C variables. They are set to 0
431      by default. This is performed by this function.
433    * Initialize the impure data structure:
434      Similarly, we need two library contexts, one for the normal software and
435      one that is used during exceptions. The impure data structure holds
436      the context information of the library. The called C function will setup
437      both data structures. There is furthermore a pointer to the currently
438      active impure data structure, which is initially set to the normal one.
440    * Initialize or1k support library reentrant data structures
442    * Initialize constructors:
443      Call the static and global constructors
445    * Set up destructors to call from exit
446      The library will call the function set via atexit() during exit(). We set
447      it to call the _fini function which performs destruction.
449    * Call board initialization:
450      The board initialization can perform board specific initializations such as
451      configuring peripherals etc.
453    * Jump to main
454      Call main with argc = 0 and *argv[] = 0
456    * Call exit after main returns
457      Now we call exit()
459    * Loop forever
460      We are dead.
463 /* -------------------------------------------------------------------------- */
464         .section        .text
466         /* Following externs from board-specific object passed at link time */
467         .extern _or1k_board_mem_base
468         .extern _or1k_board_mem_size
469         .extern _or1k_board_uart_base
471         /* The early board initialization may for example read the memory size and
472            set the mem_base and mem_size or do some preliminary board
473            initialization. As we do not have a stack at this time, the function may
474            not use the stack (and therefore be a or call a C function. But it can
475            safely use all registers.
477            We define a default implementation, which allows board files in C. As
478            described above, this can only be used in assembly (board_*.S) as at
479            the early stage not stack is available. A board that needs early
480            initialization can overwrite the function with .global _board_init_early.
482            Recommendation: Only use when you really need it! */
483         .weak _or1k_board_init_early
484 _or1k_board_init_early:
485         OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
487         /* The board initialization is then called after the C library and UART
488            are initialized. It can then be used to configure UART or other
489            devices before the actual main function is called. */
490         .extern _or1k_board_init
492         .global _or1k_start
493         .type   _or1k_start,@function
494 _or1k_start:
495         /* It is good to initialize and enable the caches before we do anything,
496            otherwise the cores will continuously access the bus during the wait
497            time for the boot barrier (0x4).
498            Fortunately or1k_cache_init does not need a stack */
499         OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_cache_init))
501 #ifdef __OR1K_MULTICORE__
502         // All but core 0 have to wait
503         l.mfspr r1, r0, OR1K_SPR_SYS_COREID_ADDR
504         l.sfeq  r1, r0
505         OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lcore0))
506 .Lspin:
507         /* r1 will be used by the other cores to check for the boot variable
508            Check if r1 is still zero, core 0 will set it to 1 once it booted
509            As the cache is already turned on, this will not create traffic on
510            the bus, but the change is snooped by cache coherency then */
511         l.lwz r1,0x4(r0)
512         l.sfeq r1, r0
513         OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lspin))
515         /* Initialize core i stack */
516         // _or1k_stack_core is the array of stack pointers
517         LOAD_SYMBOL_2_GPR(r2,_or1k_stack_core)
518         // Load the base address
519         l.lwz   r2,0(r2)
520         // Generate offset in array
521         l.mfspr r1,r0,OR1K_SPR_SYS_COREID_ADDR
522         l.slli  r1,r1,2
523         // Add to array base
524         l.add   r2,r2,r1
525         // Load pointer to the stack top and set frame pointer
526         l.lwz   r1,0(r2)
527         l.or    r2,r1,r1
529         // The slave cores are done, jump to main part
530         OR1K_DELAYED_NOP(OR1K_INST(l.j .Linit_done));
532         /* Only core 0 executes the initialization code */
533 .Lcore0:
534 #endif
535         /* Call early board initialization */
536         OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_board_init_early))
538         /* Clear BSS */
539 .Lclear_bss:
540         LOAD_SYMBOL_2_GPR(r3,__bss_start)
541         LOAD_SYMBOL_2_GPR(r4,end)
543 .Lclear_bss_loop:
544         l.sw    (0)(r3),r0
545         l.sfltu r3,r4
546         OR1K_DELAYED(
547                 OR1K_INST(l.addi r3,r3,4),
548                 OR1K_INST(l.bf .Lclear_bss_loop)
549         )
551         /* Initialise stack and frame pointer (set to same value) */
552         LOAD_SYMBOL_2_GPR(r1,_or1k_board_mem_base)
553         l.lwz   r1,0(r1)
554         LOAD_SYMBOL_2_GPR(r2,_or1k_board_mem_size)
555         l.lwz   r2,0(r2)
556         l.add   r1,r1,r2
558         /* Store exception stack top address */
559         LOAD_SYMBOL_2_GPR(r3,_or1k_exception_stack_top)
560         l.sw    0(r3),r1
562         /* Store exception stack bottom address */
563         // calculate bottom address
564         // r3 = *exception stack size
565         LOAD_SYMBOL_2_GPR(r3,_or1k_exception_stack_size)
566         // r3 = exception stack size
567         l.lwz   r3,0(r3)
568 #ifdef __OR1K_MULTICORE__
569         l.mfspr r4,r0,OR1K_SPR_SYS_NUMCORES_ADDR
570         l.mul   r3,r4,r3
571 #endif
572         // r4 = exception stack top - exception stack size = exception stack bottom
573         l.sub   r4,r1,r3
574         // r5 = *exception stack bottom
575         LOAD_SYMBOL_2_GPR(r5,_or1k_exception_stack_bottom)
576         // store
577         l.sw    0(r5),r4
579         // Move stack pointer accordingly
580         l.or    r1,r0,r4
581         l.or    r2,r1,r1
583         /* Store stack top address */
584         LOAD_SYMBOL_2_GPR(r3,_or1k_stack_top)
585         l.sw    0(r3),r1
587         /* Store stack bottom address */
588         // calculate bottom address
589         // r3 = stack size
590         LOAD_SYMBOL_2_GPR(r3,_or1k_stack_size)
591         l.lwz   r3,0(r3)
592 #ifdef __OR1K_MULTICORE__
593         l.mfspr r4, r0, OR1K_SPR_SYS_NUMCORES_ADDR
594         l.mul   r3, r4, r3
595 #endif
596         // r4 = stack top - stack size = stack bottom
597         // -> stack bottom
598         l.sub   r4,r1,r3
599         // r5 = *exception stack bottom
600         LOAD_SYMBOL_2_GPR(r5,_or1k_stack_bottom)
601         // store to variable
602         l.sw    0(r5),r4
604         /* Reinitialize the or1k support library */
605         OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_init))
607         /* Reinitialize the reentrancy structure */
608         OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_libc_impure_init))
610         /* Call global and static constructors */
611         OR1K_DELAYED_NOP(OR1K_INST(l.jal _init))
613         /* Set up destructors to be called from exit if main ever returns */
614         l.movhi r3,hi(_fini)
615         OR1K_DELAYED(
616                 OR1K_INST(l.ori r3,r3,lo(_fini)),
617                 OR1K_INST(l.jal atexit)
618         )
620         /* Check if UART is to be initialised */
621         LOAD_SYMBOL_2_GPR(r4,_or1k_board_uart_base)
622         l.lwz   r4,0(r4)
623         /* Is base set? If not, no UART */
624         l.sfne  r4,r0
625         l.bnf   .Lskip_uart
626         l.or    r3,r0,r0
627         OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_uart_init))
629 .Lskip_uart:
630         /* Board initialization */
631         OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_board_init))
633 #ifdef __OR1K_MULTICORE__
634         // Start other cores
635         l.ori   r3, r0, 1
636         l.sw    0x4(r0), r3
637 #endif
639 .Linit_done:
640         /* Jump to main program entry point (argc = argv = envp = 0) */
641         l.or    r3,r0,r0
642         l.or    r4,r0,r0
643         OR1K_DELAYED(
644                 OR1K_INST(l.or r5,r0,r0),
645                 OR1K_INST(l.jal main)
646         )
648 #ifdef __OR1K_MULTICORE__
649 .incrementexit:
650         /* Atomically increment number of finished cores */
651         l.lwa   r3,0x8(r0)
652         l.addi  r3,r3,1
653         l.swa   0x8(r0),r3
654         OR1K_DELAYED_NOP(OR1K_INST(l.bnf .incrementexit));
655         /* Compare to number of cores in this cluster */
656         l.mfspr r4,r0, OR1K_SPR_SYS_NUMCORES_ADDR
657         /* Compare to number of finished tasks */
658         l.sfeq  r3,r4
659         /* Last core needs to desctruct library etc. */
660         OR1K_DELAYED_NOP(OR1K_INST(l.bf .exitcorelast));
661         OR1K_DELAYED(
662                 OR1K_INST(l.addi r3,r11,0),
663                 OR1K_INST(l.jal _exit)
664         )
665 .exitcorelast:
666 #endif
667         /* If program exits, call exit routine */
668         OR1K_DELAYED(
669                 OR1K_INST(l.addi r3,r11,0),
670                 OR1K_INST(l.jal exit)
671         )
673         /* Loop forever */
674 .Lloop_forever:
675         OR1K_DELAYED_NOP(OR1K_INST(l.j .Lloop_forever))
677         .size _or1k_start,.-_or1k_start