1/* $NetBSD: start.S,v 1.4 2021/12/03 10:49:25 andvar Exp $ */ 2 3/*- 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code was written by Alessandro Forin and Neil Pittman 8 * at Microsoft Research and contributed to The NetBSD Foundation 9 * by Microsoft Corporation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* Trivial support for printing stuff on the serial line from C pgms. 34 */ 35#include <mips/asm.h> 36#include <mips/cpuregs.h> 37#define __ASSEMBLER__ 1 38#include <machine/emipsreg.h> 39 40/* Offsets in the CXTINFO structure 41 */ 42#define TS_AT (1 * 4) 43#define TS_V0 (2 * 4) 44#define TS_V1 (3 * 4) 45#define TS_A0 (4 * 4) 46#define TS_A1 (5 * 4) 47#define TS_A2 (6 * 4) 48#define TS_A3 (7 * 4) 49#define TS_T0 (8 * 4) 50#define TS_T1 (9 * 4) 51#define TS_T2 (10 * 4) 52#define TS_T3 (11 * 4) 53#define TS_T4 (12 * 4) 54#define TS_T5 (13 * 4) 55#define TS_T6 (14 * 4) 56#define TS_T7 (15 * 4) 57#define TS_S0 (16 * 4) 58#define TS_S1 (17 * 4) 59#define TS_S2 (18 * 4) 60#define TS_S3 (19 * 4) 61#define TS_S4 (20 * 4) 62#define TS_S5 (21 * 4) 63#define TS_S6 (22 * 4) 64#define TS_S7 (23 * 4) 65#define TS_T8 (24 * 4) 66#define TS_T9 (25 * 4) 67#define TS_K0 (26 * 4) 68#define TS_K1 (27 * 4) 69#define TS_GP (28 * 4) 70#define TS_SP (29 * 4) 71#define TS_FP (30 * 4) 72#define fp s8 73#define TS_RA (31 * 4) 74 75#define TS_PC (32 * 4) 76#define TS_SR (33 * 4) 77#define TS_HI (34 * 4) 78#define TS_LO (35 * 4) 79#define TS_EC (36 * 4) 80#define SIZEOF_CXTINFO (37*4) 81 82/* PROM_MODE means the user plans to keep this code around while running an OS. 83 * So we act kind of like PROM code (BIOS?), but we live in RAM. 84 * So we need to safeguard ourselves against corruptions, some unavoidable. 85 * Like the overriding of the exception vectors, right where our "start" code is. 86 */ 87 88 IMPORT(main,4) 89 IMPORT(_end,4) 90 91 .set noreorder 92 93EXPORT(start) 94 bgezal zero,_C_LABEL(real_start) 95 nop 96 97 98/* Does not handle the exception, really. 99 * But to test interrupts should be enough 100 */ 101 .org 0x00000080 102NESTED_NOPROFILE(ExceptionHandler,SIZEOF_CXTINFO,$31) 103 la k1, UserInterruptHandler 104 lw k1,0(k1) 105 bne k1,zero,Dispatch 106 mfc0 k0, MIPS_COP_0_EXC_PC 107 j k0 108 nop /* do not! pop status */ 109 110EXPORT(UserInterruptHandler) 111 .word 0 112 113EXPORT(Dispatch) 114 /* Save state on stack */ 115 addiu sp, sp, -SIZEOF_CXTINFO 116 /* save registers */ 117 .set noat 118 sw AT, TS_AT(sp) 119 .set at 120 sw v0, TS_V0(sp) 121 sw v1, TS_V1(sp) 122 sw a0, TS_A0(sp) 123 sw a1, TS_A1(sp) 124 sw a2, TS_A2(sp) 125 sw a3, TS_A3(sp) 126 sw t0, TS_T0(sp) 127 sw t1, TS_T1(sp) 128 sw t2, TS_T2(sp) 129 sw t3, TS_T3(sp) 130 sw t4, TS_T4(sp) 131 sw t5, TS_T5(sp) 132 sw t6, TS_T6(sp) 133 sw t7, TS_T7(sp) 134 sw s0, TS_S0(sp) 135 sw s1, TS_S1(sp) 136 sw s2, TS_S2(sp) 137 sw s3, TS_S3(sp) 138 sw s4, TS_S4(sp) 139 sw s5, TS_S5(sp) 140 sw s6, TS_S6(sp) 141 sw s7, TS_S7(sp) 142 sw t8, TS_T8(sp) 143 sw t9, TS_T9(sp) 144 sw k0, TS_K0(sp) 145 sw k1, TS_K1(sp) 146 sw gp, TS_GP(sp) 147 /* sp: later */ 148 sw fp, TS_FP(sp) 149 sw ra, TS_RA(sp) 150 151 mfc0 a0, MIPS_COP_0_STATUS 152 mflo t0 153 mfhi t1 154 sw a0, TS_SR(sp) 155 sw t0, TS_LO(sp) 156 sw t1, TS_HI(sp) 157 sw k0, TS_PC(sp) 158 159 /* Save original stack */ 160 move a0,sp 161 addiu t0, sp, SIZEOF_CXTINFO 162 jalr k1 163 sw t0, TS_SP(sp) 164 165 /* Returned value is new PCXINFO */ 166 move a0,v0 167 168 /* First load most registers */ 169 .set noat 170 lw AT, TS_AT(a0) 171 lw v0, TS_V0(a0) 172 lw v1, TS_V1(a0) 173 /* a0 later */ 174 lw a1, TS_A1(a0) 175 lw a2, TS_A2(a0) 176 lw a3, TS_A3(a0) 177 lw t0, TS_T0(a0) 178 lw t1, TS_T1(a0) 179 lw t2, TS_T2(a0) 180 lw t3, TS_T3(a0) 181 lw t4, TS_T4(a0) 182 lw t5, TS_T5(a0) 183 lw t6, TS_T6(a0) 184 lw t7, TS_T7(a0) 185 lw s0, TS_S0(a0) 186 lw s1, TS_S1(a0) 187 lw s2, TS_S2(a0) 188 lw s3, TS_S3(a0) 189 lw s4, TS_S4(a0) 190 lw s5, TS_S5(a0) 191 lw s6, TS_S6(a0) 192 lw s7, TS_S7(a0) 193 lw t8, TS_T8(a0) 194 lw t9, TS_T9(a0) 195 /* k0,k1 not restored */ 196 lw gp, TS_GP(a0) 197 /* sp later */ 198 lw fp, TS_FP(a0) 199 lw ra, TS_RA(a0) 200 201 lw k1, TS_HI(a0) 202 lw k0, TS_LO(a0) 203 mthi k1 204 mtlo k0 205 lw k1, TS_SR(a0) 206 mtc0 k1, MIPS_COP_0_STATUS 207 /* NB: After this instruction we cannot take any interrupts or traps 208 */ 209 lw sp, TS_SP(a0) 210 211 /* Put pc into k0 */ 212 lw k0, TS_PC(a0) 213 lw a0, TS_A0(a0) 214 j k0 215 rfe 216 .set at 217 218END(ExceptionHandler) 219 220 .org 0x00000200 221EXPORT(real_start) 222 .ent _C_LABEL(real_start) 223 224#ifdef SECONDARY_BOOTBLOCK 225 /* 226 * If this is the program that goes into FLASH we must copy ourselves down to RAM. 227 * FLASH default on the MLx is at 0xf0000000, DRAM at 0. 228 */ 229 addi a0,ra,-8 /* Compensate for the first two instructions */ 230 231 /* Get the address(relative) of TextStart 232 */ 233 bgezal zero, _C_LABEL(MipsStart2) /* Always jumps */ 234 nop 235 236 /* All of the static data, since we are at it. 237 */ 238TextStart: /* + 0 */ 239 /* Text start at final link address */ 240 .int start 241 242DataEnd: /* + 4 */ 243 /* Data end == bss start */ 244 .int _edata 245 246BssEnd: /* + 8 */ 247 /* Bss end */ 248 .int _end 249 250RelocToRAM: /* *+12 */ 251 .int InRAM 252 253MipsStart2: 254 255 /* Source = a0, Dst = t2 */ 256 lw t2, 0(ra) /* _C_LABEL(TextStart) */ 257 258 /* EndPtr = t3 */ 259 /* in bdelay slot */ 260 261 /* If a0 != t2 then we are running in Flash but should run in RAM 262 * In that case copy .text. Otherwise skip to .bss. 263 */ 264 beq a0,t2,ZroLoop-4 265 lw t3, 4(ra) /* _C_LABEL(DataEnd) */ 266 267CpyLoop: 268 /* loop copying 2 words at a time */ 269 lw t4,0(a0) 270 lw t5,4(a0) 271 addiu a0,a0,8 272 sw t4,0(t2) 273 addiu t2,t2,8 274 sltu t1,t2,t3 275 bne t1,zero,CpyLoop 276 sw t5,-4(t2) 277 278 /* zero the bss 279 */ 280 lw t4, 8(ra) /* _C_LABEL(BssEnd) */ 281ZroLoop: 282 sltu t1,t3,t4 283 sw zero,0(t3) 284 bne t1,zero,ZroLoop 285 addiu t3,t3,4 286 287 /* Jump to RAM copy (below) 288 */ 289 lw t1, 12(ra) /* _C_LABEL(RelocToRAM) */ 290 jr t1 291 nop 292 293 /* 294 * Execute from here after copying out of FLASH into RAM 295 */ 296InRAM: 297 298#endif /* SECONDARY_BOOTBLOCK */ 299 300 /* Get a stack 301 */ 302#ifdef __GP_SUPPORT__ 303 la gp, _C_LABEL (_gp) 304#endif 305 la sp,_end 306 addiu sp,sp,(8*1024) /* BUGBUG arbitrary */ 307 308 /* Jump to main 309 */ 310 jal main 311 add a0,sp,zero 312 313 /* Load failed, reset the processor and jump back to the origins. 314 */ 315EXPORT(_rtt) /* ahem */ 316 li t0,0x1260ff80 /* NB: On new builds this is a SYS-RESET as well */ 317 mtc0 t0,MIPS_COP_0_STATUS 318 319 lui t0,(BRAM_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */ 320 jr t0 321 nop 322 323EXPORT(Stop) 324 b Stop 325 nop 326 327END(real_start) 328 329 .set noreorder 330 .set noat 331 .set nomacro 332 333/* void Delay(UINT32 count) 334 */ 335LEAF(Delay) 336 bne a0,zero,_C_LABEL(Delay) 337 subu a0,1 338 j ra 339 nop 340END(Delay) 341 342/* UINT32 GetPsr(void) 343 * Returns the PSR (coprocessor 0 status) 344 */ 345LEAF(GetPsr) 346 mfc0 v0, MIPS_COP_0_STATUS 347 j ra 348 nop 349END(GetPsr) 350 351/* void SetPsr(UINT32 Psr) 352 * Sets the PSR (coprocessor 0 status) 353 */ 354LEAF(SetPsr) 355 mtc0 a0,MIPS_COP_0_STATUS 356 j ra 357 nop 358END(SetPsr) 359 360/* UINT32 GetCause(void) 361 * Returns the Cause register (coprocessor 0) 362 */ 363LEAF(GetCause) 364 mfc0 v0,MIPS_COP_0_CAUSE 365 j ra 366 nop 367END(GetCause) 368 369/* UINT32 GetEpc(void) 370 * Returns the Epc register (coprocessor 0) 371 */ 372LEAF(GetEpc) 373 mfc0 v0,MIPS_COP_0_EXC_PC 374 j ra 375 nop 376END(GetEpc) 377 378 379/* int PutWord(UINT32 Word); 380 * Returns: 0 if ok, -1 otherwise 381 */ 382NESTED(PutWord,12,$31) 383 subu sp,sp,12 384 sw s0,8(sp) 385 sw s1,4(sp) 386 sw ra,0(sp) 387 388 or s1,a0,zero 389 /* Spit all nibbles 390 */ 391 li s0,8 392PutWordLoop: 393 srl a0,s1,32-4 394 li t0,10 395 sltu t1,a0,t0 396 bnez t1,$Digit 397 li a1,'0' 398 subu a0,a0,t0 399 li a1,'a' 400$Digit: 401 sll s1,s1,4 402 jal PutChar 403 add a0,a0,a1 404 405 subu s0,s0,1 406 bne v0,zero,PutWordDone /* printed ok? */ 407 li v0,-1 408 409 /* done yet? */ 410 bne s0,zero,PutWordLoop 411 nop 412 413 /* done 414 */ 415 li v0,0 416PutWordDone: 417 lw ra,0(sp) 418 lw s1,4(sp) 419 lw s0,8(sp) 420 jr ra 421 addiu sp,sp,12 422 423END(PutWord) 424 425/* int Puts(char *String); 426 * Returns: 0 if ok, -1 otherwise 427 */ 428NESTED(Puts,8,$31) 429 subu sp,sp,8 430 sw s0,4(sp) 431 sw ra,0(sp) 432 433 or s0,a0,zero 434 /* Spit all chars until zero 435 */ 436PutsLoop: 437 lbu a0,0(s0) 438 addiu s0,s0,1 439 beq a0,zero,PutsDoneOk 440 nop 441 jal PutChar 442 nop 443 beq v0,zero,PutsLoop 444 nop 445 446 /* Timed out 447 */ 448 b PutsDone 449 li v0,-1 450 451 /* done 452 */ 453PutsDoneOk: 454 li v0,0 455PutsDone: 456 lw ra,0(sp) 457 lw s0,4(sp) 458 jr ra 459 addiu sp,sp,8 460 461END(Puts) 462 463 464/* int GetChar(void); 465 * Returns: a non-negative value if ok, -1 otherwise 466 */ 467LEAF(GetChar) 468 lui t0,(USART_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */ 469 lui t1,1000 /* n*65k spins max */ 470RxNotReady: 471 lw t4,USARTST(t0) /* ChannelStatus */ 472 andi t4,t4,USI_RXRDY 473 bgtz t4,$GotByte 474 subu t1,t1,1 475 /* still ok to spin? */ 476 bgtz t1,RxNotReady 477 nop 478 /* Timed out 479 */ 480 jr ra 481 li v0,-1 482 483 /* Gottabyte 484 */ 485$GotByte: 486 lw v0,USARTRX(t0) /* RxData */ 487 jr ra 488 andi v0,0xff 489END(GetChar) 490 491/* int PutChar(UINT8 v); 492 * Returns: 0 if ok, -1 otherwise 493 */ 494LEAF(PutChar) 495 lui t0,(USART_DEFAULT_ADDRESS>>16) /* nb: knows about 16bit chop */ 496 lui t1,1000 /* n*65k spins max */ 497 li v0,0 498TxNotReady: 499 lw t4,USARTST(t0) /* ChannelStatus */ 500 andi t4,t4,USI_TXRDY 501 bgtz t4,TxReady 502 subu t1,t1,1 503 /* still ok to spin? */ 504 bgtz t1,TxNotReady 505 nop 506 /* Timed out 507 */ 508 jr ra 509 li v0,-1 510 511 /* Send it 512 */ 513TxReady: 514 jr ra 515 sw a0,USARTTX(t0) 516 517END(PutChar) 518 519/* Second arg is a function to call with the first arg: 520 * void switch_stack_and_call(void *arg, void (*function)(void *)); 521 */ 522LEAF(switch_stack_and_call) 523 /* Get a stack and jump. It would be a very bad idea to return but.. 524 */ 525 lui sp,%hi(_end) 526 addiu sp,%lo(_end) 527 jr a1 528 addiu sp,sp,(2*1024) /* BUGBUG arbitrary */ 529 530END(switch_stack_and_call) 531 532