1 /* $NetBSD: asm.h,v 1.46 2024/06/09 22:35:37 riastradh 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@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 #ifdef __STDC__
137 #define   __CONCAT(a,b)       a ## b
138 #else
139 #define   __CONCAT(a,b)       a/**/b
140 #endif
141 #define ___CONCAT(a,b)        __CONCAT(a,b)
142 
143 /*
144  * Macro to make a local label name.
145  */
146 #define   LLABEL(name,num)    ___CONCAT(___CONCAT(L,name),num)
147 
148 /*
149  *
150  * Debuggers need symbol table information to be able to properly
151  * decode a stack trace.  The minimum that should be provided is:
152  *
153  *        name:
154  *                  .proc     name,numargs
155  *
156  * where "name"     is the function's name;
157  *         "numargs"          how many arguments it expects. For varargs
158  *                            procedures this should be a negative number,
159  *                            indicating the minimum required number of
160  *                            arguments (which is at least 1);
161  *
162  * NESTED functions (functions that call other functions) should define
163  * how they handle their stack frame in a .frame directive:
164  *
165  *                  .frame    framesize, pc_reg, i_mask, f_mask
166  *
167  * where "framesize"          is the size of the frame for this function, in bytes.
168  *                            That is:
169  *                                      new_sp + framesize == old_sp
170  *                            Framesizes should be rounded to a cacheline size.
171  *                            Note that old_sp plays the role of a conventional
172  *                            "frame pointer";
173  *         "pc_reg" is either a register which preserves the caller's PC
174  *                            or 'std', if std the saved PC should be stored at
175  *                                      old_sp-8
176  *         "i_mask" is a bitmask that indicates which of the integer
177  *                            registers are saved. See the M_xx defines at the
178  *                            end for the encoding of this 32bit value.
179  *         "f_mask" is the same, for floating point registers.
180  *
181  * Note, 10/31/97: This is interesting but it isn't the way gcc outputs
182  * frame directives and it isn't the way the macros below output them
183  * either. Frame directives look like this:
184  *
185  *                  .frame    $15,framesize,$26,0
186  *
187  * If no fp is set up then $30 should be used instead of $15.
188  * Also, gdb expects to find a <lda sp,-framesize(sp)> at the beginning
189  * of a procedure. Don't use things like sub sp,framesize,sp for this
190  * reason. End Note 10/31/97. ross@NetBSD.org
191  *
192  * Note that registers should be saved starting at "old_sp-8", where the
193  * return address should be stored. Other registers follow at -16-24-32..
194  * starting from register 0 (if saved) and up. Then float registers (ifany)
195  * are saved.
196  *
197  * If you need to alias a leaf function, or to provide multiple entry points
198  * use the LEAF() macro for the main entry point and XLEAF() for the other
199  * additional/alternate entry points.
200  * "XLEAF"s must be nested within a "LEAF" and a ".end".
201  * Similar rules for nested routines, e.g. use NESTED/XNESTED
202  * Symbols that should not be exported can be declared with the STATIC_xxx
203  * macros.
204  *
205  * All functions must be terminated by the END macro
206  *
207  * It is conceivable, although currently at the limits of compiler
208  * technology, that while performing inter-procedural optimizations
209  * the compiler/linker be able to avoid unnecessary register spills
210  * if told about the register usage of LEAF procedures (and by transitive
211  * closure of NESTED procedures as well).  Assembly code can help
212  * this process using the .reguse directive:
213  *
214  *                  .reguse   i_mask, f_mask
215  *
216  * where the register masks are built as above or-ing M_xx defines.
217  *
218  *
219  * All symbols are internal unless EXPORTed.  Symbols that are IMPORTed
220  * must be appropriately described to the debugger.
221  *
222  */
223 
224 /*
225  * MCOUNT
226  */
227 
228 #ifndef GPROF
229 #define MCOUNT      /* nothing */
230 #else
231 #define MCOUNT                                                                  \
232           .set noat;                                                            \
233           jsr       at_reg,_mcount;                                             \
234           .set at
235 #endif
236 /*
237  * PALVECT, ESETUP, and ERSAVE
238  *        Declare a palcode transfer point, and carefully construct
239  *        gdb symbols with an unusual _negative_ register-save offset
240  *        so that gdb can find the otherwise lost PC and then
241  *        invert the vector for traceback. Also, fix up framesize,
242  *        allowing for the palframe for the same reason.
243  */
244 
245 #define PALVECT(_name_)                                                         \
246           ESETUP(_name_);                                                       \
247           ERSAVE()
248 
249 #define   ESETUP(_name_)                                                        \
250           /* .loc   1 __LINE__; */                                              \
251           .globl    _name_;                                                     \
252           .ent      _name_ 0;                                         \
253 _name_:;                                                              \
254           .set      noat;                                                       \
255           lda       sp,-(FRAME_SW_SIZE*8)(sp);                        \
256           .frame    $30,(FRAME_SW_SIZE+6)*8,$26,0;   /* give gdb the real size */\
257           .mask     0x4000000,-0x28;                                  \
258           .set      at
259 
260 #define   ERSAVE()                                                    \
261           .set      noat;                                                       \
262           stq       at_reg,(FRAME_AT*8)(sp);                          \
263           .set      at;                                                         \
264           stq       ra,(FRAME_RA*8)(sp);                                        \
265           /* .loc   1 __LINE__; */                                              \
266           bsr       ra,exception_save_regs         /* jmp/CALL trashes pv/t12 */
267 
268 
269 /*
270  * LEAF
271  *        Declare a global leaf function.
272  *        A leaf function does not call other functions AND does not
273  *        use any register that is callee-saved AND does not modify
274  *        the stack pointer.
275  */
276 #define   LEAF(_name_,_n_args_)                                                 \
277           .globl    _name_;                                                     \
278           .ent      _name_ 0;                                         \
279 _name_:;                                                              \
280           .frame    sp,0,ra;                                          \
281           MCOUNT
282 /* should have been
283           .proc     _name_,_n_args_;                                  \
284           .frame    0,ra,0,0
285 */
286 
287 #define   LEAF_NOPROFILE(_name_,_n_args_)                                                 \
288           .globl    _name_;                                                     \
289           .ent      _name_ 0;                                         \
290 _name_:;                                                              \
291           .frame    sp,0,ra
292 /* should have been
293           .proc     _name_,_n_args_;                                  \
294           .frame    0,ra,0,0
295 */
296 
297 /*
298  * STATIC_LEAF
299  *        Declare a local leaf function.
300  */
301 #define STATIC_LEAF(_name_,_n_args_)                                  \
302           .ent      _name_ 0;                                         \
303 _name_:;                                                              \
304           .frame    sp,0,ra;                                          \
305           MCOUNT
306 /* should have been
307           .proc     _name_,_n_args_;                                  \
308           .frame    0,ra,0,0
309 */
310 /*
311  * XLEAF
312  *        Global alias for a leaf function, or alternate entry point
313  */
314 #define   XLEAF(_name_,_n_args_)                                                \
315           .globl    _name_;                                                     \
316           .aent     _name_ 0;                                         \
317 _name_:
318 /* should have been
319           .aproc    _name_,_n_args_;
320 */
321 
322 /*
323  * STATIC_XLEAF
324  *        Local alias for a leaf function, or alternate entry point
325  */
326 #define   STATIC_XLEAF(_name_,_n_args_)                               \
327           .aent     _name_ 0;                                         \
328 _name_:
329 /* should have been
330           .aproc    _name_,_n_args_;
331 */
332 
333 /*
334  * NESTED
335  *        Declare a (global) nested function
336  *        A nested function calls other functions and needs
337  *        therefore stack space to save/restore registers.
338  */
339 #define   NESTED(_name_, _n_args_, _framesize_, _pc_reg_, _i_mask_, _f_mask_ ) \
340           .globl    _name_;                                                     \
341           .ent      _name_ 0;                                         \
342 _name_:;                                                              \
343           .frame    sp,_framesize_,_pc_reg_;                          \
344           .livereg _i_mask_,_f_mask_;                                 \
345           MCOUNT
346 /* should have been
347           .proc     _name_,_n_args_;                                  \
348           .frame    _framesize_, _pc_reg_, _i_mask_, _f_mask_
349 */
350 
351 #define   NESTED_NOPROFILE(_name_, _n_args_, _framesize_, _pc_reg_, _i_mask_, _f_mask_ ) \
352           .globl    _name_;                                                     \
353           .ent      _name_ 0;                                         \
354 _name_:;                                                              \
355           .frame    sp,_framesize_,_pc_reg_;                          \
356           .livereg _i_mask_,_f_mask_
357 /* should have been
358           .proc     _name_,_n_args_;                                  \
359           .frame    _framesize_, _pc_reg_, _i_mask_, _f_mask_
360 */
361 
362 /*
363  * STATIC_NESTED
364  *        Declare a local nested function.
365  */
366 #define   STATIC_NESTED(_name_, _n_args_, _framesize_, _pc_reg_, _i_mask_, _f_mask_ ) \
367           .ent      _name_ 0;                                         \
368 _name_:;                                                              \
369           .frame    sp,_framesize_,_pc_reg_;                          \
370           .livereg _i_mask_,_f_mask_;                                 \
371           MCOUNT
372 /* should have been
373           .proc     _name_,_n_args_;                                  \
374           .frame    _framesize_, _pc_reg_, _i_mask_, _f_mask_
375 */
376 
377 /*
378  * XNESTED
379  *        Same as XLEAF, for a nested function.
380  */
381 #define   XNESTED(_name_,_n_args_)                                    \
382           .globl    _name_;                                                     \
383           .aent     _name_ 0;                                         \
384 _name_:
385 /* should have been
386           .aproc    _name_,_n_args_;
387 */
388 
389 
390 /*
391  * STATIC_XNESTED
392  *        Same as STATIC_XLEAF, for a nested function.
393  */
394 #define   STATIC_XNESTED(_name_,_n_args_)                                       \
395           .aent     _name_ 0;                                         \
396 _name_:
397 /* should have been
398           .aproc    _name_,_n_args_;
399 */
400 
401 
402 /*
403  * END
404  *        Function delimiter
405  */
406 #define   END(_name_)                                                           \
407           .end      _name_
408 
409 
410 /*
411  * CALL
412  *        Function invocation
413  */
414 #define   CALL(_name_)                                                          \
415           /* .loc   1 __LINE__; */                                              \
416           jsr       ra,_name_;                                                  \
417           ldgp      gp,0(ra)
418 /* but this would cover longer jumps
419           br        ra,.+4;                                                     \
420           bsr       ra,_name_
421 */
422 
423 
424 /*
425  * RET
426  *        Return from function
427  */
428 #define   RET                                                                   \
429           ret       zero,(ra),1
430 
431 
432 /*
433  * EXPORT
434  *        Export a symbol
435  */
436 #define   EXPORT(_name_)                                                        \
437           .globl    _name_;                                                     \
438 _name_:
439 
440 
441 /*
442  * IMPORT
443  *        Make an external name visible, typecheck the size
444  */
445 #define   IMPORT(_name_, _size_)                                                \
446           .extern   _name_,_size_
447 
448 
449 /*
450  * ABS
451  *        Define an absolute symbol
452  */
453 #define   ABS(_name_, _value_)                                                  \
454           .globl    _name_;                                                     \
455 _name_    =         _value_
456 
457 
458 /*
459  * BSS
460  *        Allocate un-initialized space for a global symbol
461  */
462 #define   BSS(_name_,_numbytes_)                                                \
463           .comm     _name_,_numbytes_
464 
465 /*
466  * VECTOR
467  *        Make an exception entry point look like a called function,
468  *        to make it digestible to the debugger (KERNEL only)
469  */
470 #define   VECTOR(_name_, _i_mask_)                                    \
471           .globl    _name_;                                                     \
472           .ent      _name_ 0;                                         \
473 _name_:;                                                              \
474           .mask     _i_mask_|IM_EXC,0;                                \
475           .frame    sp,MSS_SIZE,ra;
476 /*        .livereg _i_mask_|IM_EXC,0    */
477 /* should have been
478           .proc     _name_,1;                                         \
479           .frame    MSS_SIZE,$31,_i_mask_,0;                          \
480 */
481 
482 /*
483  * MSG
484  *        Allocate space for a message (a read-only ascii string)
485  */
486 #define   ASCIZ     .asciz
487 #define   MSG(msg,reg,label)                                          \
488           lda reg, label;                                                       \
489           .data;                                                                \
490 label:    ASCIZ msg;                                                            \
491           .text;
492 
493 /*
494  * PRINTF
495  *        Print a message
496  */
497 #define   PRINTF(msg,label)                                           \
498           MSG(msg,a0,label);                                          \
499           CALL(printf)
500 
501 /*
502  * PANIC
503  *        Fatal error (KERNEL)
504  */
505 #define   PANIC(msg,label)                                            \
506           MSG(msg,a0,label);                                          \
507           CALL(panic)
508 
509 /*
510  * Register mask defines, used to define both save
511  * and use register sets.
512  *
513  * NOTE: The bit order should HAVE BEEN maintained when saving
514  *         registers on the stack: sp goes at the highest
515  *         address, gp lower on the stack, etc etc
516  *         BUT NOONE CARES ABOUT DEBUGGERS AT MIPS
517  */
518 
519 #define   IM_EXC    0x80000000
520 #define   IM_SP     0x40000000
521 #define   IM_GP     0x20000000
522 #define   IM_AT     0x10000000
523 #define   IM_T12    0x08000000
524 #         define    IM_PV     IM_T4
525 #define   IM_RA     0x04000000
526 #define   IM_T11    0x02000000
527 #         define    IM_AI     IM_T3
528 #define   IM_T10    0x01000000
529 #define   IM_T9     0x00800000
530 #define   IM_T8     0x00400000
531 #define   IM_A5     0x00200000
532 #define   IM_A4     0x00100000
533 #define   IM_A3     0x00080000
534 #define   IM_A2     0x00040000
535 #define   IM_A1     0x00020000
536 #define   IM_A0     0x00010000
537 #define   IM_S6     0x00008000
538 #define   IM_S5     0x00004000
539 #define   IM_S4     0x00002000
540 #define   IM_S3     0x00001000
541 #define   IM_S2     0x00000800
542 #define   IM_S1     0x00000400
543 #define   IM_S0     0x00000200
544 #define   IM_T7     0x00000100
545 #define   IM_T6     0x00000080
546 #define   IM_T5     0x00000040
547 #define   IM_T4     0x00000020
548 #define   IM_T3     0x00000010
549 #define   IM_T2     0x00000008
550 #define   IM_T1     0x00000004
551 #define   IM_T0     0x00000002
552 #define   IM_V0     0x00000001
553 
554 #define   FM_T15    0x40000000
555 #define   FM_T14    0x20000000
556 #define   FM_T13    0x10000000
557 #define   FM_T12    0x08000000
558 #define   FM_T11    0x04000000
559 #define   FM_T10    0x02000000
560 #define   FM_T9     0x01000000
561 #define   FM_T8     0x00800000
562 #define   FM_T7     0x00400000
563 #define   FM_A5     0x00200000
564 #define   FM_A4     0x00100000
565 #define   FM_A3     0x00080000
566 #define   FM_A2     0x00040000
567 #define   FM_A1     0x00020000
568 #define   FM_A0     0x00010000
569 #define   FM_T6     0x00008000
570 #define   FM_T5     0x00004000
571 #define   FM_T4     0x00002000
572 #define   FM_T3     0x00001000
573 #define   FM_T2     0x00000800
574 #define   FM_T1     0x00000400
575 #define   FM_S7     0x00000200
576 #define   FM_S6     0x00000100
577 #define   FM_S5     0x00000080
578 #define   FM_S4     0x00000040
579 #define   FM_S3     0x00000020
580 #define   FM_S2     0x00000010
581 #define   FM_S1     0x00000008
582 #define   FM_S0     0x00000004
583 #define   FM_T0     0x00000002
584 #define   FM_V1     FM_T0
585 #define   FM_V0     0x00000001
586 
587 /* Pull in PAL "function" codes. */
588 #include <machine/pal.h>
589 
590 /*
591  * System call glue.
592  */
593 #define   SYSCALLNUM(name)                                            \
594           ___CONCAT(SYS_,name)
595 
596 #define   CALLSYS_NOERROR(name)                                                 \
597           ldiq      v0, SYSCALLNUM(name);                                       \
598           call_pal PAL_OSF1_callsys
599 
600 #define LINUX_SYSCALLNUM(name)                                                  \
601           ___CONCAT(LINUX_SYS_,name)
602 
603 #define LINUX_CALLSYS_NOERROR(name)                                   \
604           ldiq      v0, LINUX_SYSCALLNUM(name);                       \
605           call_pal PAL_OSF1_callsys
606 
607 /*
608  * Load the global pointer.
609  */
610 #define   LDGP(reg)                                                   \
611           ldgp      gp, 0(reg)
612 
613 /*
614  * WEAK_ALIAS: create a weak alias.
615  */
616 #define WEAK_ALIAS(alias,sym)                                         \
617           .weak alias;                                                          \
618           alias = sym
619 
620 /*
621  * STRONG_ALIAS: create a strong alias.
622  */
623 #define STRONG_ALIAS(alias,sym)                                                 \
624           .globl alias;                                                         \
625           alias = sym
626 
627 /*
628  * WARN_REFERENCES: create a warning if the specified symbol is referenced.
629  */
630 #ifdef __STDC__
631 #define   WARN_REFERENCES(sym,msg)                                              \
632           .pushsection .gnu.warning. ## sym;                                    \
633           .ascii msg;                                                                     \
634           .popsection
635 #else
636 #define   WARN_REFERENCES(sym,msg)                                              \
637           .pushsection .gnu.warning./**/sym;                                    \
638           .ascii msg;                                                                     \
639           .popsection
640 #endif /* __STDC__ */
641 
642 /*
643  * Kernel RCS ID tag and copyright macros
644  */
645 #define   __SECTIONSTRING(_sec, _str)                                 \
646           .pushsection _sec,"MS",@progbits,1;                         \
647           .asciz _str;                                                          \
648           .popsection
649 
650 #ifdef _KERNEL
651 
652 #ifdef _NETBSD_REVISIONID
653 #define   __KERNEL_RCSID(_n, _s)                                                                \
654           __SECTIONSTRING(.ident, _s);                                                \
655           __SECTIONSTRING(.ident,                                                               \
656               "$" "NetBSD: " __FILE__ " " _NETBSD_REVISIONID " $")
657 #else
658 #define   __KERNEL_RCSID(_n, _s)                  __SECTIONSTRING(.ident, _s)
659 #endif
660 #define   __KERNEL_COPYRIGHT(_n, _s)    __SECTIONSTRING(.copyright, _s)
661 
662 #ifdef NO_KERNEL_RCSIDS
663 #undef __KERNEL_RCSID
664 #define   __KERNEL_RCSID(_n, _s)                  /* nothing */
665 #endif
666 
667 #if defined(MULTIPROCESSOR)
668 
669 /*
670  * Get various per-cpu values.  A pointer to our cpu_info structure
671  * is stored in SysValue.  These macros clobber v0, t0, t8..t11.
672  * SET_CURLWP also clobbers a0.
673  *
674  * All return values are in v0.
675  */
676 #define   GET_CURLWP                                                                      \
677           call_pal PAL_OSF1_rdval
678 
679 /*
680  * Issue barriers to coordinate mutex_exit on this CPU with
681  * mutex_vector_enter on another CPU.
682  *
683  * 1. Any prior mutex_exit by oldlwp must be visible to other
684  *    CPUs before we set ci_curlwp := newlwp on this one,
685  *    requiring a store-before-store barrier.
686  *
687  * 2. ci_curlwp := newlwp must be visible on all other CPUs
688  *    before any subsequent mutex_exit by newlwp can even test
689  *    whether there might be waiters, requiring a
690  *    store-before-load barrier.
691  *
692  * See kern_mutex.c for details -- this is necessary for
693  * adaptive mutexes to detect whether the lwp is on the CPU in
694  * order to safely block without requiring atomic r/m/w in
695  * mutex_exit.
696  */
697 #define   SET_CURLWP(r)                                                                   \
698           ldq       v0, L_CPU(r)                                                ;         \
699           mov       r, a0                                                       ;         \
700           wmb       /* store-before-store XXX patch out if !MP? */    ;         \
701           stq       r, CPU_INFO_CURLWP(v0)                                      ;         \
702           mb        /* store-before-load XXX patch out if !MP? */     ;         \
703           call_pal PAL_OSF1_wrval
704 
705 #else     /* if not MULTIPROCESSOR... */
706 
707 IMPORT(cpu_info_primary, CPU_INFO_SIZEOF)
708 
709 #define   GET_CURLWP                    lda v0, cpu_info_primary      ;         \
710                                         ldq v0, CPU_INFO_CURLWP(v0)
711 
712 #define   SET_CURLWP(r)                 lda v0, cpu_info_primary      ;         \
713                                         stq r, CPU_INFO_CURLWP(v0)
714 
715 #endif /* MULTIPROCESSOR */
716 
717 #else /* !_KERNEL */
718 
719 #ifdef _NETBSD_REVISIONID
720 #define   RCSID(_s)                                                                   \
721           __SECTIONSTRING(.ident, _s);                                                \
722           __SECTIONSTRING(.ident,                                                               \
723               "$" "NetBSD: " __FILE__ " " _NETBSD_REVISIONID " $")
724 #else
725 #define   RCSID(_s)           __SECTIONSTRING(.ident, _s)
726 #endif
727 
728 #endif /* _KERNEL */
729