source: trunk/libs/newlib/src/libgloss/or1k/crt0.S @ 684

Last change on this file since 684 was 444, checked in by satin@…, 7 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 20.0 KB
Line 
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 */
18
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/* -------------------------------------------------------------------------- */
38
39#include "newlib.h"
40#include "include/or1k-asm.h"
41#include "include/or1k-sprs.h"
42
43/* -------------------------------------------------------------------------- */
44// Stack definitions
45/* -------------------------------------------------------------------------- */
46
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//  +--------------------+
58
59// Reserved stack size
60#define STACK_SIZE 8192
61
62// Reserved stack size for exceptions (can usually be smaller than normal stack)
63#define EXCEPTION_STACK_SIZE 8192
64
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
69
70#define REDZONE 128
71
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 */
77
78        .section .data
79        .global _or1k_stack_size /* reserved stack size */
80        .global _or1k_exception_stack_size
81        .global _or1k_exception_level
82
83_or1k_stack_size:               .word STACK_SIZE
84_or1k_exception_stack_size:     .word EXCEPTION_STACK_SIZE
85
86#ifdef __OR1K_MULTICORE__
87        .extern _or1k_stack_core
88        .extern _or1k_exception_stack_core
89#endif
90
91#define SHADOW_REG(x) (OR1K_SPR_SYS_GPR_BASE + 32 + x)
92
93/* -------------------------------------------------------------------------- */
94/*!Macro to handle exceptions.
95
96  Load NPC into r3, EPCR into r4
97                                                                              */
98/* -------------------------------------------------------------------------- */
99
100#ifdef HAVE_INITFINI_ARRAY
101#define _init   __libc_init_array
102#define _fini   __libc_fini_array
103#endif
104
105#define GPR_BUF_OFFSET(x) (x << 2)
106
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
244
245/* -------------------------------------------------------------------------- */
246/*!Exception vectors                                                          */
247/* -------------------------------------------------------------------------- */
248        .section .vectors,"ax"
249
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
292
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))
301
302        .org 0x200
303        CALL_EXCEPTION_HANDLER(2)
304
305        /* 0x300: Data Page Fault exception */
306        .org 0x300
307        CALL_EXCEPTION_HANDLER(3)
308
309        /* 0x400: Insn Page Fault exception */
310        .org 0x400
311        CALL_EXCEPTION_HANDLER(4)
312
313        /* 0x500: Timer exception */
314        .org 0x500
315        CALL_EXCEPTION_HANDLER(5)
316
317        /* 0x600: Aligment exception */
318        .org 0x600
319        CALL_EXCEPTION_HANDLER(6)
320
321        /* 0x700: Illegal insn exception */
322        .org 0x700
323        CALL_EXCEPTION_HANDLER(7)
324
325        /* 0x800: External interrupt exception */
326        .org 0x800
327        CALL_EXCEPTION_HANDLER(8)
328
329        /* 0x900: DTLB miss exception */
330        .org 0x900
331        CALL_EXCEPTION_HANDLER(9)
332
333        /* 0xa00: ITLB miss exception */
334        .org 0xa00
335        CALL_EXCEPTION_HANDLER(10)
336
337        /* 0xb00: Range exception */
338        .org 0xb00
339        CALL_EXCEPTION_HANDLER(11)
340
341        /* 0xc00: Syscall exception */
342        .org 0xc00
343        CALL_EXCEPTION_HANDLER(12)
344
345        /* 0xd00: Floating point exception */
346        .org 0xd00
347        CALL_EXCEPTION_HANDLER(13)
348
349        /* 0xe00: Trap exception */
350        .org 0xe00
351        CALL_EXCEPTION_HANDLER(14)
352
353        /* 0xf00: Reserved exceptions */
354        .org 0xf00
355        CALL_EXCEPTION_HANDLER(15)
356
357        .org 0x1000
358        CALL_EXCEPTION_HANDLER(16)
359
360        .org 0x1100
361        CALL_EXCEPTION_HANDLER(17)
362
363        .org 0x1200
364        CALL_EXCEPTION_HANDLER(18)
365
366        .org 0x1300
367        CALL_EXCEPTION_HANDLER(19)
368
369        .org 0x1400
370        CALL_EXCEPTION_HANDLER(20)
371
372        .org 0x1500
373        CALL_EXCEPTION_HANDLER(21)
374
375        .org 0x1600
376        CALL_EXCEPTION_HANDLER(22)
377
378        .org 0x1700
379        CALL_EXCEPTION_HANDLER(23)
380
381        .org 0x1800
382        CALL_EXCEPTION_HANDLER(24)
383
384        .org 0x1900
385        CALL_EXCEPTION_HANDLER(25)
386
387        .org 0x1a00
388        CALL_EXCEPTION_HANDLER(26)
389
390        .org 0x1b00
391        CALL_EXCEPTION_HANDLER(27)
392
393        .org 0x1c00
394        CALL_EXCEPTION_HANDLER(28)
395
396        .org 0x1d00
397        CALL_EXCEPTION_HANDLER(29)
398
399        .org 0x1e00
400        CALL_EXCEPTION_HANDLER(30)
401
402        .org 0x1f00
403        CALL_EXCEPTION_HANDLER(31)
404
405        /* Pad to the end */
406        .org 0x1ffc
407        l.nop
408
409/* -------------------------------------------------------------------------- */
410/*!Main entry point
411
412  This is the initialization code of the library. It performs these steps:
413
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.
420
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.
425
426   * Activate the caches:
427     If available the caches are initiliazed and activated.
428
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.
432
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.
439
440   * Initialize or1k support library reentrant data structures
441
442   * Initialize constructors:
443     Call the static and global constructors
444
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.
448
449   * Call board initialization:
450     The board initialization can perform board specific initializations such as
451     configuring peripherals etc.
452
453   * Jump to main
454     Call main with argc = 0 and *argv[] = 0
455
456   * Call exit after main returns
457     Now we call exit()
458
459   * Loop forever
460     We are dead.
461*/
462
463/* -------------------------------------------------------------------------- */
464        .section        .text
465
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
470
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.
476
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.
481
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))
486
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
491
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))
500
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))
514
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
528
529        // The slave cores are done, jump to main part
530        OR1K_DELAYED_NOP(OR1K_INST(l.j .Linit_done));
531
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))
537
538        /* Clear BSS */
539.Lclear_bss:
540        LOAD_SYMBOL_2_GPR(r3,__bss_start)
541        LOAD_SYMBOL_2_GPR(r4,end)
542
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        )
550
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
557
558        /* Store exception stack top address */
559        LOAD_SYMBOL_2_GPR(r3,_or1k_exception_stack_top)
560        l.sw    0(r3),r1
561
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
578
579        // Move stack pointer accordingly
580        l.or    r1,r0,r4
581        l.or    r2,r1,r1
582
583        /* Store stack top address */
584        LOAD_SYMBOL_2_GPR(r3,_or1k_stack_top)
585        l.sw    0(r3),r1
586
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
603
604        /* Reinitialize the or1k support library */
605        OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_init))
606
607        /* Reinitialize the reentrancy structure */
608        OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_libc_impure_init))
609
610        /* Call global and static constructors */
611        OR1K_DELAYED_NOP(OR1K_INST(l.jal _init))
612
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        )
619
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))
628
629.Lskip_uart:
630        /* Board initialization */
631        OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_board_init))
632
633#ifdef __OR1K_MULTICORE__
634        // Start other cores
635        l.ori   r3, r0, 1
636        l.sw    0x4(r0), r3
637#endif
638
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        )
647
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        )
672
673        /* Loop forever */
674.Lloop_forever:
675        OR1K_DELAYED_NOP(OR1K_INST(l.j .Lloop_forever))
676
677        .size _or1k_start,.-_or1k_start
Note: See TracBrowser for help on using the repository browser.