1 /* $OpenBSD: asm.h,v 1.16 2023/12/06 06:15:33 miod Exp $ */ 2 /* $NetBSD: asm.h,v 1.23 2000/06/23 12:18:45 kleink Exp $ */ 3 4 /* 5 * Copyright (c) 1991,1990,1989,1994,1995,1996 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie Mellon 26 * the rights to redistribute these changes. 27 */ 28 29 /* 30 * Assembly coding style 31 * 32 * This file contains macros and register defines to 33 * aid in writing more readable assembly code. 34 * Some rules to make assembly code understandable by 35 * a debugger are also noted. 36 * 37 * The document 38 * 39 * "ALPHA Calling Standard", DEC 27-Apr-90 40 * 41 * defines (a superset of) the rules and conventions 42 * we use. While we make no promise of adhering to 43 * such standard and its evolution (esp where we 44 * can get faster code paths) it is certainly intended 45 * that we be interoperable with such standard. 46 * 47 * In this sense, this file is a proper part of the 48 * definition of the (software) Alpha architecture. 49 */ 50 51 /* 52 * Symbolic register names and register saving rules 53 * 54 * Legend: 55 * T Saved by caller (Temporaries) 56 * S Saved by callee (call-Safe registers) 57 */ 58 59 #define v0 $0 /* (T) return value */ 60 #define t0 $1 /* (T) temporary registers */ 61 #define t1 $2 62 #define t2 $3 63 #define t3 $4 64 #define t4 $5 65 #define t5 $6 66 #define t6 $7 67 #define t7 $8 68 69 #define s0 $9 /* (S) call-safe registers */ 70 #define s1 $10 71 #define s2 $11 72 #define s3 $12 73 #define s4 $13 74 #define s5 $14 75 #define s6 $15 76 #define a0 $16 /* (T) argument registers */ 77 #define a1 $17 78 #define a2 $18 79 #define a3 $19 80 #define a4 $20 81 #define a5 $21 82 #define t8 $22 /* (T) temporary registers */ 83 #define t9 $23 84 #define t10 $24 85 #define t11 $25 86 #define ra $26 /* (T) return address */ 87 #define t12 $27 /* (T) another temporary */ 88 #define at_reg $28 /* (T) assembler scratch */ 89 #define gp $29 /* (T) (local) data pointer */ 90 #define sp $30 /* (S) stack pointer */ 91 #define zero $31 /* wired zero */ 92 93 /* Floating point registers (XXXX VERIFY THIS) */ 94 #define fv0 $f0 /* (T) return value (real) */ 95 #define fv1 $f1 /* (T) return value (imaginary)*/ 96 #define ft0 fv1 97 #define fs0 $f2 /* (S) call-safe registers */ 98 #define fs1 $f3 99 #define fs2 $f4 100 #define fs3 $f5 101 #define fs4 $f6 102 #define fs5 $f7 103 #define fs6 $f8 104 #define fs7 $f9 105 #define ft1 $f10 /* (T) temporary registers */ 106 #define ft2 $f11 107 #define ft3 $f12 108 #define ft4 $f13 109 #define ft5 $f14 110 #define ft6 $f15 111 #define fa0 $f16 /* (T) argument registers */ 112 #define fa1 $f17 113 #define fa2 $f18 114 #define fa3 $f19 115 #define fa4 $f20 116 #define fa5 $f21 117 #define ft7 $f22 /* (T) more temporaries */ 118 #define ft8 $f23 119 #define ft9 $f24 120 #define ft10 $f25 121 #define ft11 $f26 122 #define ft12 $f27 123 #define ft13 $f28 124 #define ft14 $f29 125 #define ft15 $f30 126 #define fzero $f31 /* wired zero */ 127 128 129 /* Other DEC standard names */ 130 #define fp $15 /* (S) frame pointer */ 131 #define ai $25 /* (T) argument information */ 132 #define pv $27 /* (T) procedure value */ 133 #define AT $28 /* (T) assembler scratch */ 134 135 136 /* 137 * Useful stuff. 138 */ 139 #ifdef __STDC__ 140 #define __CONCAT(a,b) a ## b 141 #else 142 #define __CONCAT(a,b) a/**/b 143 #endif 144 #define ___CONCAT(a,b) __CONCAT(a,b) 145 146 /* 147 * Macro to make a local label name. 148 */ 149 #define LLABEL(name,num) ___CONCAT(___CONCAT(L,name),num) 150 151 /* 152 * 153 * Debuggers need symbol table information to be able to properly 154 * decode a stack trace. The minimum that should be provided is: 155 * 156 * name: 157 * .proc name,numargs 158 * 159 * where "name" is the function's name; 160 * "numargs" how many arguments it expects. For varargs 161 * procedures this should be a negative number, 162 * indicating the minimum required number of 163 * arguments (which is at least 1); 164 * 165 * NESTED functions (functions that call other functions) should define 166 * how they handle their stack frame in a .frame directive: 167 * 168 * .frame framesize, pc_reg, i_mask, f_mask 169 * 170 * where "framesize" is the size of the frame for this function, in bytes. 171 * That is: 172 * new_sp + framesize == old_sp 173 * Framesizes should be rounded to a cacheline size. 174 * Note that old_sp plays the role of a conventional 175 * "frame pointer"; 176 * "pc_reg" is either a register which preserves the caller's PC 177 * or 'std', if std the saved PC should be stored at 178 * old_sp-8 179 * "i_mask" is a bitmask that indicates which of the integer 180 * registers are saved. See the M_xx defines at the 181 * end for the encoding of this 32bit value. 182 * "f_mask" is the same, for floating point registers. 183 * 184 * Note, 10/31/97: This is interesting but it isn't the way gcc outputs 185 * frame directives and it isn't the way the macros below output them 186 * either. Frame directives look like this: 187 * 188 * .frame $15,framesize,$26,0 189 * 190 * If no fp is set up then $30 should be used instead of $15. 191 * Also, gdb expects to find a <lda sp,-framesize(sp)> at the beginning 192 * of a procedure. Don't use things like sub sp,framesize,sp for this 193 * reason. End Note 10/31/97. ross@netbsd.org 194 * 195 * Note that registers should be saved starting at "old_sp-8", where the 196 * return address should be stored. Other registers follow at -16-24-32.. 197 * starting from register 0 (if saved) and up. Then float registers (ifany) 198 * are saved. 199 * 200 * If you need to alias a leaf function, or to provide multiple entry points 201 * use the LEAF() macro for the main entry point and XLEAF() for the other 202 * additional/alternate entry points. 203 * "XLEAF"s must be nested within a "LEAF" and a ".end". 204 * Similar rules for nested routines, e.g. use NESTED/XNESTED 205 * Symbols that should not be exported can be declared with the STATIC_xxx 206 * macros. 207 * 208 * All functions must be terminated by the END macro 209 * 210 * It is conceivable, although currently at the limits of compiler 211 * technology, that while performing inter-procedural optimizations 212 * the compiler/linker be able to avoid unnecessary register spills 213 * if told about the register usage of LEAF procedures (and by transitive 214 * closure of NESTED procedures as well). Assembly code can help 215 * this process using the .reguse directive: 216 * 217 * .reguse i_mask, f_mask 218 * 219 * where the register masks are built as above or-ing M_xx defines. 220 * 221 * 222 * All symbols are internal unless EXPORTed. Symbols that are IMPORTed 223 * must be appropriately described to the debugger. 224 * 225 */ 226 227 /* 228 * MCOUNT 229 */ 230 231 #ifndef GPROF 232 #define MCOUNT /* nothing */ 233 #else 234 #define MCOUNT \ 235 .set noat; \ 236 jsr at_reg,_mcount; \ 237 .set at 238 #endif 239 /* 240 * PALVECT, ESETUP, and ERSAVE 241 * Declare a palcode transfer point, and carefully construct 242 * gdb symbols with an unusual _negative_ register-save offset 243 * so that gdb can find the otherwise lost PC and then 244 * invert the vector for traceback. Also, fix up framesize, 245 * allowing for the palframe for the same reason. 246 */ 247 248 #define PALVECT(_name_) \ 249 ESETUP(_name_); \ 250 ERSAVE() 251 252 #define ESETUP(_name_) \ 253 /* .loc 1 __LINE__; */ \ 254 .globl _name_; \ 255 .ent _name_ 0; \ 256 _name_:; \ 257 .set noat; \ 258 lda sp,-(FRAME_SW_SIZE*8)(sp); \ 259 .frame $30,(FRAME_SW_SIZE+6)*8,$26,0; /* give gdb the real size */\ 260 .mask 0x4000000,-0x28; \ 261 .set at 262 263 #define ERSAVE() \ 264 .set noat; \ 265 stq at_reg,(FRAME_AT*8)(sp); \ 266 .set at; \ 267 stq ra,(FRAME_RA*8)(sp); \ 268 /* .loc 1 __LINE__; */ \ 269 bsr ra,exception_save_regs /* jmp/CALL trashes pv/t12 */ 270 271 272 /* 273 * LEAF 274 * Declare a global leaf function. 275 * A leaf function does not call other functions AND does not 276 * use any register that is callee-saved AND does not modify 277 * the stack pointer. 278 */ 279 #define LEAF(_name_,_n_args_) \ 280 .globl _name_; \ 281 .ent _name_ 0; \ 282 _name_:; \ 283 .frame sp,0,ra; \ 284 MCOUNT 285 /* should have been 286 .proc _name_,_n_args_; \ 287 .frame 0,ra,0,0 288 */ 289 290 #define LEAF_NOPROFILE(_name_,_n_args_) \ 291 .globl _name_; \ 292 .ent _name_ 0; \ 293 _name_:; \ 294 .frame sp,0,ra 295 /* should have been 296 .proc _name_,_n_args_; \ 297 .frame 0,ra,0,0 298 */ 299 300 /* 301 * STATIC_LEAF 302 * Declare a local leaf function. 303 */ 304 #define STATIC_LEAF(_name_,_n_args_) \ 305 .ent _name_ 0; \ 306 _name_:; \ 307 .frame sp,0,ra; \ 308 MCOUNT 309 /* should have been 310 .proc _name_,_n_args_; \ 311 .frame 0,ra,0,0 312 */ 313 /* 314 * XLEAF 315 * Global alias for a leaf function, or alternate entry point 316 */ 317 #define XLEAF(_name_,_n_args_) \ 318 .globl _name_; \ 319 .aent _name_ 0; \ 320 _name_: 321 /* should have been 322 .aproc _name_,_n_args_; 323 */ 324 325 /* 326 * STATIC_XLEAF 327 * Local alias for a leaf function, or alternate entry point 328 */ 329 #define STATIC_XLEAF(_name_,_n_args_) \ 330 .aent _name_ 0; \ 331 _name_: 332 /* should have been 333 .aproc _name_,_n_args_; 334 */ 335 336 /* 337 * NESTED 338 * Declare a (global) nested function 339 * A nested function calls other functions and needs 340 * therefore stack space to save/restore registers. 341 */ 342 #define NESTED(_name_, _n_args_, _framesize_, _pc_reg_, _i_mask_, _f_mask_ ) \ 343 .globl _name_; \ 344 .ent _name_ 0; \ 345 _name_:; \ 346 .frame sp,_framesize_,_pc_reg_; \ 347 .livereg _i_mask_,_f_mask_; \ 348 MCOUNT 349 /* should have been 350 .proc _name_,_n_args_; \ 351 .frame _framesize_, _pc_reg_, _i_mask_, _f_mask_ 352 */ 353 354 #define NESTED_NOPROFILE(_name_, _n_args_, _framesize_, _pc_reg_, _i_mask_, _f_mask_ ) \ 355 .globl _name_; \ 356 .ent _name_ 0; \ 357 _name_:; \ 358 .frame sp,_framesize_,_pc_reg_; \ 359 .livereg _i_mask_,_f_mask_ 360 /* should have been 361 .proc _name_,_n_args_; \ 362 .frame _framesize_, _pc_reg_, _i_mask_, _f_mask_ 363 */ 364 365 /* 366 * STATIC_NESTED 367 * Declare a local nested function. 368 */ 369 #define STATIC_NESTED(_name_, _n_args_, _framesize_, _pc_reg_, _i_mask_, _f_mask_ ) \ 370 .ent _name_ 0; \ 371 _name_:; \ 372 .frame sp,_framesize_,_pc_reg_; \ 373 .livereg _i_mask_,_f_mask_; \ 374 MCOUNT 375 /* should have been 376 .proc _name_,_n_args_; \ 377 .frame _framesize_, _pc_reg_, _i_mask_, _f_mask_ 378 */ 379 380 /* 381 * XNESTED 382 * Same as XLEAF, for a nested function. 383 */ 384 #define XNESTED(_name_,_n_args_) \ 385 .globl _name_; \ 386 .aent _name_ 0; \ 387 _name_: 388 /* should have been 389 .aproc _name_,_n_args_; 390 */ 391 392 393 /* 394 * STATIC_XNESTED 395 * Same as STATIC_XLEAF, for a nested function. 396 */ 397 #define STATIC_XNESTED(_name_,_n_args_) \ 398 .aent _name_ 0; \ 399 _name_: 400 /* should have been 401 .aproc _name_,_n_args_; 402 */ 403 404 405 /* 406 * END 407 * Function delimiter 408 */ 409 #define END(_name_) \ 410 .end _name_ 411 412 413 /* 414 * CALL 415 * Function invocation 416 */ 417 #define CALL(_name_) \ 418 /* .loc 1 __LINE__; */ \ 419 jsr ra,_name_; \ 420 ldgp gp,0(ra) 421 /* but this would cover longer jumps 422 br ra,.+4; \ 423 bsr ra,_name_ 424 */ 425 426 427 /* 428 * RET 429 * Return from function 430 */ 431 #define RET \ 432 ret zero,(ra),1 433 434 435 /* 436 * EXPORT 437 * Export a symbol 438 */ 439 #define EXPORT(_name_) \ 440 .globl _name_; \ 441 _name_: 442 443 444 /* 445 * IMPORT 446 * Make an external name visible, typecheck the size 447 */ 448 #define IMPORT(_name_, _size_) \ 449 .extern _name_,_size_ 450 451 452 /* 453 * ABS 454 * Define an absolute symbol 455 */ 456 #define ABS(_name_, _value_) \ 457 .globl _name_; \ 458 _name_ = _value_ 459 460 461 /* 462 * BSS 463 * Allocate un-initialized space for a global symbol 464 */ 465 #define BSS(_name_,_numbytes_) \ 466 .comm _name_,_numbytes_ 467 468 /* 469 * VECTOR 470 * Make an exception entry point look like a called function, 471 * to make it digestible to the debugger (KERNEL only) 472 */ 473 #define VECTOR(_name_, _i_mask_) \ 474 .globl _name_; \ 475 .ent _name_ 0; \ 476 _name_:; \ 477 .mask _i_mask_|IM_EXC,0; \ 478 .frame sp,MSS_SIZE,ra; 479 /* .livereg _i_mask_|IM_EXC,0 */ 480 /* should have been 481 .proc _name_,1; \ 482 .frame MSS_SIZE,$31,_i_mask_,0; \ 483 */ 484 485 /* 486 * MSG 487 * Allocate space for a message (a read-only ascii string) 488 */ 489 #define ASCIZ .asciz 490 #define MSG(msg,reg,label) \ 491 lda reg, label; \ 492 .data; \ 493 label: ASCIZ msg; \ 494 .text; 495 496 /* 497 * PRINTF 498 * Print a message 499 */ 500 #define PRINTF(msg,label) \ 501 MSG(msg,a0,label); \ 502 CALL(printf) 503 504 /* 505 * PANIC 506 * Fatal error (KERNEL) 507 */ 508 #define PANIC(msg,label) \ 509 MSG(msg,a0,label); \ 510 CALL(panic) 511 512 /* 513 * Register mask defines, used to define both save 514 * and use register sets. 515 * 516 * NOTE: The bit order should HAVE BEEN maintained when saving 517 * registers on the stack: sp goes at the highest 518 * address, gp lower on the stack, etc etc 519 * BUT NOONE CARES ABOUT DEBUGGERS AT MIPS 520 */ 521 522 #define IM_EXC 0x80000000 523 #define IM_SP 0x40000000 524 #define IM_GP 0x20000000 525 #define IM_AT 0x10000000 526 #define IM_T12 0x08000000 527 # define IM_PV IM_T4 528 #define IM_RA 0x04000000 529 #define IM_T11 0x02000000 530 # define IM_AI IM_T3 531 #define IM_T10 0x01000000 532 #define IM_T9 0x00800000 533 #define IM_T8 0x00400000 534 #define IM_A5 0x00200000 535 #define IM_A4 0x00100000 536 #define IM_A3 0x00080000 537 #define IM_A2 0x00040000 538 #define IM_A1 0x00020000 539 #define IM_A0 0x00010000 540 #define IM_S6 0x00008000 541 #define IM_S5 0x00004000 542 #define IM_S4 0x00002000 543 #define IM_S3 0x00001000 544 #define IM_S2 0x00000800 545 #define IM_S1 0x00000400 546 #define IM_S0 0x00000200 547 #define IM_T7 0x00000100 548 #define IM_T6 0x00000080 549 #define IM_T5 0x00000040 550 #define IM_T4 0x00000020 551 #define IM_T3 0x00000010 552 #define IM_T2 0x00000008 553 #define IM_T1 0x00000004 554 #define IM_T0 0x00000002 555 #define IM_V0 0x00000001 556 557 #define FM_T15 0x40000000 558 #define FM_T14 0x20000000 559 #define FM_T13 0x10000000 560 #define FM_T12 0x08000000 561 #define FM_T11 0x04000000 562 #define FM_T10 0x02000000 563 #define FM_T9 0x01000000 564 #define FM_T8 0x00800000 565 #define FM_T7 0x00400000 566 #define FM_A5 0x00200000 567 #define FM_A4 0x00100000 568 #define FM_A3 0x00080000 569 #define FM_A2 0x00040000 570 #define FM_A1 0x00020000 571 #define FM_A0 0x00010000 572 #define FM_T6 0x00008000 573 #define FM_T5 0x00004000 574 #define FM_T4 0x00002000 575 #define FM_T3 0x00001000 576 #define FM_T2 0x00000800 577 #define FM_T1 0x00000400 578 #define FM_S7 0x00000200 579 #define FM_S6 0x00000100 580 #define FM_S5 0x00000080 581 #define FM_S4 0x00000040 582 #define FM_S3 0x00000020 583 #define FM_S2 0x00000010 584 #define FM_S1 0x00000008 585 #define FM_S0 0x00000004 586 #define FM_T0 0x00000002 587 #define FM_V1 FM_T0 588 #define FM_V0 0x00000001 589 590 /* Pull in PAL "function" codes. */ 591 #include <machine/pal.h> 592 593 /* 594 * Load the global pointer. 595 */ 596 #define LDGP(reg) \ 597 ldgp gp, 0(reg) 598 599 /* 600 * STRONG_ALIAS, WEAK_ALIAS 601 * Create a strong or weak alias. 602 */ 603 #define STRONG_ALIAS(alias,sym) \ 604 .global alias; \ 605 alias = sym 606 #define WEAK_ALIAS(alias,sym) \ 607 .weak alias; \ 608 alias = sym 609