| 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 | 
|---|