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