[444] | 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 |
---|