| 1 | /* |
| 2 | * crt0-tc2x.S -- Startup code for GNU/TriCore applications. |
| 3 | * |
| 4 | * Copyright (C) 1998-2014 HighTec EDV-Systeme GmbH. |
| 5 | * |
| 6 | * This file is part of GCC. |
| 7 | * |
| 8 | * GCC is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by |
| 10 | * the Free Software Foundation; either version 3, or (at your option) |
| 11 | * any later version. |
| 12 | * |
| 13 | * GCC is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * Under Section 7 of GPL version 3, you are granted additional |
| 19 | * permissions described in the GCC Runtime Library Exception, version |
| 20 | * 3.1, as published by the Free Software Foundation. |
| 21 | * |
| 22 | * You should have received a copy of the GNU General Public License and |
| 23 | * a copy of the GCC Runtime Library Exception along with this program; |
| 24 | * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| 25 | * <http://www.gnu.org/licenses/>. */ |
| 26 | |
| 27 | /* Define the Derivate Name as a hexvalue. This value |
| 28 | * is built-in defined in tricore-c.c (from tricore-devices.c) |
| 29 | * the derivate number as a hexvalue (e.g. TC1796 => 0x1796 |
| 30 | * This name will be used in the memory.x Memory description to |
| 31 | * to confirm that the crt0.o and the memory.x will be get from |
| 32 | * same directory |
| 33 | */ |
| 34 | .section ".startup_code", "ax", @progbits |
| 35 | .global _start |
| 36 | .type _start,@function |
| 37 | |
| 38 | /* default BMI header (only TC2xxx devices) */ |
| 39 | .word 0x00000000 |
| 40 | .word 0xb3590070 |
| 41 | .word 0x00000000 |
| 42 | .word 0x00000000 |
| 43 | .word 0x00000000 |
| 44 | .word 0x00000000 |
| 45 | .word 0x791eb864 |
| 46 | .word 0x86e1479b |
| 47 | |
| 48 | _start: |
| 49 | .code32 |
| 50 | j _startaddr |
| 51 | .align 2 |
| 52 | |
| 53 | _startaddr: |
| 54 | /* |
| 55 | * initialize user and interrupt stack pointers |
| 56 | */ |
| 57 | movh.a %sp,hi:__USTACK # load %sp |
| 58 | lea %sp,[%sp]lo:__USTACK |
| 59 | movh %d0,hi:__ISTACK # load $isp |
| 60 | addi %d0,%d0,lo:__ISTACK |
| 61 | mtcr $isp,%d0 |
| 62 | isync |
| 63 | |
| 64 | #; install trap handlers |
| 65 | |
| 66 | movh %d0,hi:first_trap_table #; load $btv |
| 67 | addi %d0,%d0,lo:first_trap_table |
| 68 | mtcr $btv,%d0 |
| 69 | isync |
| 70 | |
| 71 | /* |
| 72 | * initialize call depth counter |
| 73 | */ |
| 74 | |
| 75 | mfcr %d0,$psw |
| 76 | or %d0,%d0,0x7f # disable call depth counting |
| 77 | andn %d0,%d0,0x80 # clear CDE bit |
| 78 | mtcr $psw,%d0 |
| 79 | isync |
| 80 | |
| 81 | /* |
| 82 | * initialize access to system global registers |
| 83 | */ |
| 84 | |
| 85 | mfcr %d0,$psw |
| 86 | or %d0,%d0,0x100 # set GW bit |
| 87 | mtcr $psw,%d0 |
| 88 | isync |
| 89 | |
| 90 | /* |
| 91 | * initialize SDA base pointers |
| 92 | */ |
| 93 | .global _SMALL_DATA_,_SMALL_DATA2_,_SMALL_DATA3_,_SMALL_DATA4_ |
| 94 | .weak _SMALL_DATA_,_SMALL_DATA2_,_SMALL_DATA3_,_SMALL_DATA4_ |
| 95 | |
| 96 | movh.a %a0,hi:_SMALL_DATA_ # %a0 addresses .sdata/.sbss |
| 97 | lea %a0,[%a0]lo:_SMALL_DATA_ |
| 98 | movh.a %a1,hi:_SMALL_DATA2_ # %a1 addresses .sdata2/.sbss2 |
| 99 | lea %a1,[%a1]lo:_SMALL_DATA2_ |
| 100 | movh.a %a8,hi:_SMALL_DATA3_ # %a8 addresses .sdata3/.sbss3 |
| 101 | lea %a8,[%a8]lo:_SMALL_DATA3_ |
| 102 | movh.a %a9,hi:_SMALL_DATA4_ # %a9 addresses .sdata4/.sbss4 |
| 103 | lea %a9,[%a9]lo:_SMALL_DATA4_ |
| 104 | |
| 105 | /* |
| 106 | * reset access to system global registers |
| 107 | */ |
| 108 | |
| 109 | mfcr %d0,$psw |
| 110 | andn %d0,%d0,0x100 # clear GW bit |
| 111 | mtcr $psw,%d0 |
| 112 | isync |
| 113 | |
| 114 | /* |
| 115 | * initialize context save areas |
| 116 | */ |
| 117 | |
| 118 | jl __init_csa |
| 119 | |
| 120 | |
| 121 | |
| 122 | /* |
| 123 | * handle clear table (i.e., fill BSS with zeros) |
| 124 | */ |
| 125 | |
| 126 | jl __clear_table_func |
| 127 | |
| 128 | |
| 129 | /* |
| 130 | * handle copy table (support for romable code) |
| 131 | */ |
| 132 | |
| 133 | jl __copy_table_func |
| 134 | |
| 135 | |
| 136 | /* |
| 137 | * _exit (main (0, NULL)); |
| 138 | */ |
| 139 | mov %d4,0 # argc = 0 |
| 140 | sub.a %sp,8 |
| 141 | st.w [%sp]0,%d4 |
| 142 | st.w [%sp]4,%d4 |
| 143 | mov.aa %a4,%sp # argv |
| 144 | |
| 145 | call main # int retval = main (0, NULL); |
| 146 | mov.a %a14,%d2 # move exit code to match trap handler |
| 147 | j _exit # _exit (retval); |
| 148 | |
| 149 | debug # should never come here |
| 150 | |
| 151 | |
| 152 | /* |
| 153 | * initialize context save areas (CSAs), PCXI, LCX and FCX |
| 154 | */ |
| 155 | |
| 156 | .global __init_csa |
| 157 | .type __init_csa,function |
| 158 | |
| 159 | __init_csa: |
| 160 | movh %d0,0 |
| 161 | mtcr $pcxi,%d0 |
| 162 | isync |
| 163 | movh %d0,hi:__CSA_BEGIN #; %d0 = begin of CSA |
| 164 | addi %d0,%d0,lo:__CSA_BEGIN |
| 165 | addi %d0,%d0,63 #; force alignment (2^6) |
| 166 | andn %d0,%d0,63 |
| 167 | movh %d2,hi:__CSA_END #; %d2 = end of CSA |
| 168 | addi %d2,%d2,lo:__CSA_END |
| 169 | andn %d2,%d2,63 #; force alignment (2^6) |
| 170 | sub %d2,%d2,%d0 |
| 171 | sh %d2,%d2,-6 #; %d2 = number of CSAs |
| 172 | mov.a %a3,%d0 #; %a3 = address of first CSA |
| 173 | extr.u %d0,%d0,28,4 #; %d0 = segment << 16 |
| 174 | sh %d0,%d0,16 |
| 175 | lea %a4,0 #; %a4 = previous CSA = 0 |
| 176 | st.a [%a3],%a4 #; store it in 1st CSA |
| 177 | mov.aa %a4,%a3 #; %a4 = current CSA |
| 178 | lea %a3,[%a3]64 #; %a3 = %a3->nextCSA |
| 179 | mov.d %d1,%a3 |
| 180 | extr.u %d1,%d1,6,16 #; get CSA index |
| 181 | or %d1,%d1,%d0 #; add segment number |
| 182 | mtcr $lcx,%d1 #; initialize LCX |
| 183 | add %d2,%d2,-2 #; CSAs to initialize -= 2 |
| 184 | mov.a %a5,%d2 #; %a5 = loop counter |
| 185 | csa_loop: |
| 186 | mov.d %d1,%a4 #; %d1 = current CSA address |
| 187 | extr.u %d1,%d1,6,16 #; get CSA index |
| 188 | or %d1,%d1,%d0 #; add segment number |
| 189 | st.w [%a3],%d1 #; store "nextCSA" pointer |
| 190 | mov.aa %a4,%a3 #; %a4 = current CSA address |
| 191 | lea %a3,[%a3]64 #; %a3 = %a3->nextCSA |
| 192 | loop %a5,csa_loop #; repeat until done |
| 193 | |
| 194 | mov.d %d1,%a4 #; %d1 = current CSA address |
| 195 | extr.u %d1,%d1,6,16 #; get CSA index |
| 196 | or %d1,%d1,%d0 #; add segment number |
| 197 | mtcr $fcx,%d1 #; initialize FCX |
| 198 | isync |
| 199 | ji %a11 |
| 200 | |
| 201 | |
| 202 | |
| 203 | |
| 204 | /* |
| 205 | * handle clear table (i.e., fill BSS with zeros) |
| 206 | */ |
| 207 | .global __clear_table_func |
| 208 | .type __clear_table_func,@function |
| 209 | |
| 210 | __clear_table_func: |
| 211 | mov %d14,0 # %e14 = 0 |
| 212 | mov %d15,0 |
| 213 | movh.a %a13,hi:__clear_table # %a13 = &first table entry |
| 214 | lea %a13,[%a13]lo:__clear_table |
| 215 | |
| 216 | __clear_table_next: |
| 217 | ld.a %a15,[%a13+]4 # %a15 = current block base |
| 218 | ld.w %d3,[%a13+]4 # %d3 = current block length |
| 219 | jeq %d3,-1,__clear_table_done # length == -1 => end of table |
| 220 | sh %d0,%d3,-3 # %d0 = length / 8 (doublewords) |
| 221 | and %d1,%d3,7 # %d1 = length % 8 (rem. bytes) |
| 222 | jz %d0,__clear_word # block size < 8 => clear word |
| 223 | addi %d0,%d0,-1 # else doublewords -= 1 |
| 224 | mov.a %a2,%d0 # %a2 = loop counter |
| 225 | __clear_dword: |
| 226 | st.d [%a15+]8,%e14 # clear one doubleword |
| 227 | loop %a2,__clear_dword |
| 228 | __clear_word: |
| 229 | jz %d1,__clear_table_next |
| 230 | sh %d0,%d1,-2 # %d0 = length / 4 (words) |
| 231 | and %d1,%d1,3 # %d1 = length % 4 (rem. bytes) |
| 232 | jz %d0,__clear_hword # block size < 4 => clear hword |
| 233 | st.w [%a15+]4,%d15 # clear one word |
| 234 | __clear_hword: |
| 235 | jz %d1,__clear_table_next |
| 236 | sh %d0,%d1,-1 # %d0 = length / 2 (halfwords) |
| 237 | and %d1,%d1,1 # %d1 = length % 2 (rem. bytes) |
| 238 | jz %d0,__clear_byte # block size < 2 => clear byte |
| 239 | st.h [%a15+]2,%d15 # clear one halfword |
| 240 | __clear_byte: |
| 241 | jz %d1,__clear_table_next |
| 242 | st.b [%a15],%d15 # clear one byte |
| 243 | j __clear_table_next # handle next clear table entry |
| 244 | __clear_table_done: |
| 245 | |
| 246 | ji %a11 |
| 247 | |
| 248 | |
| 249 | |
| 250 | /* |
| 251 | * handle copy table (support for romable code) |
| 252 | */ |
| 253 | .global __copy_table_func |
| 254 | .type __copy_table_func,@function |
| 255 | |
| 256 | __copy_table_func: |
| 257 | movh.a %a13,hi:__copy_table # %a13 = &first table entry |
| 258 | lea %a13,[%a13]lo:__copy_table |
| 259 | |
| 260 | __copy_table_next: |
| 261 | ld.a %a15,[%a13+]4 # %a15 = src address |
| 262 | ld.a %a14,[%a13+]4 # %a14 = dst address |
| 263 | ld.w %d3,[%a13+]4 # %d3 = block length |
| 264 | jeq %d3,-1,__copy_table_done # length == -1 => end of table |
| 265 | sh %d0,%d3,-3 # %d0 = length / 8 (doublewords) |
| 266 | and %d1,%d3,7 # %d1 = length % 8 (rem. bytes) |
| 267 | jz %d0,__copy_word # block size < 8 => copy word |
| 268 | addi %d0,%d0,-1 # else doublewords -= 1 |
| 269 | mov.a %a2,%d0 # %a2 = loop counter |
| 270 | __copy_dword: |
| 271 | ld.d %e14,[%a15+]8 # copy one doubleword |
| 272 | st.d [%a14+]8,%e14 |
| 273 | loop %a2,__copy_dword |
| 274 | __copy_word: |
| 275 | jz %d1,__copy_table_next |
| 276 | sh %d0,%d1,-2 # %d0 = length / 4 (words) |
| 277 | and %d1,%d1,3 # %d1 = length % 4 (rem. bytes) |
| 278 | jz %d0,__copy_hword # block size < 4 => copy hword |
| 279 | ld.w %d14,[%a15+]4 # copy one word |
| 280 | st.w [%a14+]4,%d14 |
| 281 | __copy_hword: |
| 282 | jz %d1,__copy_table_next |
| 283 | sh %d0,%d1,-1 # %d0 = length / 2 (halfwords) |
| 284 | and %d1,%d1,1 # %d1 = length % 2 (rem. bytes) |
| 285 | jz %d0,__copy_byte # block size < 2 => copy byte |
| 286 | ld.h %d14,[%a15+]2 # copy one halfword |
| 287 | st.h [%a14+]2,%d14 |
| 288 | __copy_byte: |
| 289 | jz %d1,__copy_table_next |
| 290 | ld.b %d14,[%a15]0 # copy one byte |
| 291 | st.b [%a14],%d14 |
| 292 | j __copy_table_next # handle next copy table entry |
| 293 | __copy_table_done: |
| 294 | |
| 295 | ji %a11 |
| 296 | |
| 297 | _exit: |
| 298 | movh.a %a15, hi:__TESTDEVICE |
| 299 | lea %a15,[%a15]lo:__TESTDEVICE |
| 300 | mov.d %d2, %a14 |
| 301 | st.w [%a15], %d2 # write exit code to testdevice |
| 302 | debug |
| 303 | |
| 304 | /*============================================================================* |
| 305 | * Exception handlers (exceptions in startup code) |
| 306 | * |
| 307 | * This is a minimal trap vector table, which consists of eight |
| 308 | * entries, each consisting of eight words (32 bytes). |
| 309 | *============================================================================*/ |
| 310 | |
| 311 | |
| 312 | #; .section .traptab, "ax", @progbits |
| 313 | |
| 314 | .macro trapentry from=0, to=7 |
| 315 | mov.u %d14, \from << 8 |
| 316 | add %d14,%d14,%d15 |
| 317 | mov.a %a14,%d14 |
| 318 | addih.a %a14,%a14,0 # if we trap, we fail |
| 319 | j _exit |
| 320 | 0: |
| 321 | j 0b |
| 322 | nop |
| 323 | rfe |
| 324 | .align 5 |
| 325 | |
| 326 | .if \to-\from |
| 327 | trapentry "(\from+1)",\to |
| 328 | .endif |
| 329 | .endm |
| 330 | |
| 331 | .align 8 |
| 332 | .global first_trap_table |
| 333 | first_trap_table: |
| 334 | trapentry 0, 7 |
| 335 |