1/* $NetBSD: locore.s,v 1.186 2024/02/04 18:52:35 andvar Exp $ */ 2 3/* 4 * Copyright (c) 1980, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 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 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: Utah $Hdr: locore.s 1.66 92/12/22$ 36 * 37 * @(#)locore.s 8.6 (Berkeley) 5/27/94 38 */ 39 40/* 41 * Copyright (c) 1994, 1995 Gordon W. Ross 42 * Copyright (c) 1988 University of Utah. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * the Systems Programming Group of the University of Utah Computer 46 * Science Department. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Berkeley and its contributors. 60 * 4. Neither the name of the University nor the names of its contributors 61 * may be used to endorse or promote products derived from this software 62 * without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 74 * SUCH DAMAGE. 75 * 76 * from: Utah $Hdr: locore.s 1.66 92/12/22$ 77 * 78 * @(#)locore.s 8.6 (Berkeley) 5/27/94 79 */ 80 81#include "opt_compat_netbsd.h" 82#include "opt_compat_sunos.h" 83#include "opt_ddb.h" 84#include "opt_fpsp.h" 85#include "opt_kgdb.h" 86#include "opt_lockdebug.h" 87#include "opt_fpu_emulate.h" 88#include "opt_m68k_arch.h" 89 90#include "assym.h" 91#include <machine/asm.h> 92#include <machine/trap.h> 93 94#include "opt_useleds.h" 95#ifdef USELEDS 96#include <hp300/hp300/leds.h> 97#endif 98 99#include "audio.h" 100#include "ksyms.h" 101 102#define MMUADDR(ar) movl _C_LABEL(MMUbase),ar 103#define CLKADDR(ar) movl _C_LABEL(CLKbase),ar 104 105/* 106 * This is for kvm_mkdb, and should be the address of the beginning 107 * of the kernel text segment (not necessarily the same as kernbase). 108 */ 109 .text 110GLOBAL(kernel_text) 111 112/* 113 * Clear and skip the first page of text; it will not be mapped at 114 * VA 0. 115 * 116 * The bootloader places the bootinfo in this page, and we allocate 117 * a VA for it and map it later. 118 */ 119 .fill PAGE_SIZE/4,4,0 120 121/* 122 * Temporary stack for a variety of purposes. 123 * Try and make this the first thing is the data segment so it 124 * is page aligned. Note that if we overflow here, we run into 125 * our text segment. 126 */ 127 .data 128 .space PAGE_SIZE 129ASLOCAL(tmpstk) 130 131/* 132 * Macro to relocate a symbol, used before MMU is enabled. 133 */ 134#define IMMEDIATE # 135#define _RELOC(var, ar) \ 136 movel IMMEDIATE var,ar; \ 137 addl %a5,ar 138 139#define RELOC(var, ar) _RELOC(_C_LABEL(var), ar) 140#define ASRELOC(var, ar) _RELOC(_ASM_LABEL(var), ar) 141 142/* 143 * Final bits of grunt work required to reboot the system. The MMU 144 * must be disabled when this is invoked. 145 */ 146#define DOREBOOT \ 147 /* Reset Vector Base Register to what PROM expects. */ \ 148 movl #0,%d0; \ 149 movc %d0,%vbr; \ 150 /* Jump to REQ_REBOOT */ \ 151 jmp 0x1A4; 152 153/* 154 * Initialization 155 * 156 * A4 contains the address of the end of the symtab 157 * A5 contains physical load point from boot 158 * VBR contains zero from ROM. Exceptions will continue to vector 159 * through ROM until MMU is turned on at which time they will vector 160 * through our table (vectors.s). 161 */ 162 163BSS(lowram,4) 164BSS(esym,4) 165 166ASENTRY_NOPROFILE(start) 167 movw #PSL_HIGHIPL,%sr | no interrupts 168 ASRELOC(tmpstk, %a0) 169 movl %a0,%sp | give ourselves a temporary stack 170 RELOC(esym, %a0) 171 movl %a4,%a0@ | store end of symbol table 172 RELOC(lowram, %a0) 173 movl %a5,%a0@ | store start of physical memory 174 movl #CACHE_OFF,%d0 175 movc %d0,%cacr | clear and disable on-chip cache(s) 176 177/* check for internal HP-IB in SYSFLAG */ 178 btst #5,0xfffffed2 | internal HP-IB? 179 jeq Lhaveihpib | yes, have HP-IB just continue 180 RELOC(internalhpib, %a0) 181 movl #0,%a0@ | no, clear associated address 182Lhaveihpib: 183 184 RELOC(boothowto, %a0) | save reboot flags 185 movl %d7,%a0@ 186 RELOC(bootdev, %a0) | and boot device 187 movl %d6,%a0@ 188 189 /* 190 * All data registers are now free. All address registers 191 * except %a5 are free. %a5 is used by the RELOC() macro, 192 * and cannot be used until after the MMU is enabled. 193 */ 194 195/* determine our CPU/MMU combo - check for all regardless of kernel config */ 196 movl #INTIOBASE+MMUBASE,%a1 197 movl #DC_FREEZE,%d0 | data freeze bit 198 movc %d0,%cacr | only exists on 68030 199 movc %cacr,%d0 | read it back 200 tstl %d0 | zero? 201 jeq Lnot68030 | yes, we have 68020/68040 202 203 /* 204 * 68030 models 205 */ 206 207 RELOC(mmutype, %a0) | no, we have 68030 208 movl #MMU_68030,%a0@ | set to reflect 68030 PMMU 209 RELOC(cputype, %a0) 210 movl #CPU_68030,%a0@ | and 68030 CPU 211 RELOC(machineid, %a0) 212 movl #0x80,%a1@(MMUCMD) | set magic cookie 213 movl %a1@(MMUCMD),%d0 | read it back 214 btst #7,%d0 | cookie still on? 215 jeq Lnot370 | no, 360, 362 or 375 216 movl #0,%a1@(MMUCMD) | clear magic cookie 217 movl %a1@(MMUCMD),%d0 | read it back 218 btst #7,%d0 | still on? 219 jeq Lisa370 | no, must be a 370 220 movl #HP_340,%a0@ | yes, must be a 340 221 jra Lstart1 222Lnot370: 223 movl #HP_360,%a0@ | type is at least a 360 224 movl #0,%a1@(MMUCMD) | clear magic cookie2 225 movl %a1@(MMUCMD),%d0 | read it back 226 btst #16,%d0 | still on? 227 jeq Lisa36x | no, must be a 360 or a 362 228 RELOC(mmuid, %a0) | save MMU ID 229 lsrl #MMUID_SHIFT,%d0 230 andl #MMUID_MASK,%d0 231 movl %d0,%a0@ 232 RELOC(machineid, %a0) 233 cmpb #MMUID_345,%d0 | are we a 345? 234 beq Lisa345 235 cmpb #MMUID_375,%d0 | how about a 375? 236 beq Lisa375 237 movl #HP_400,%a0@ | must be a 400 238 jra Lhaspac 239Lisa36x: 240 /* 241 * If we found a 360, we need to check for a 362 (neither the 360 242 * nor the 362 have a nonzero mmuid). Identify 362 by checking 243 * on-board VRX framebuffer which has secid 0x11 at dio scode 132. 244 */ 245 movl #DIOII_BASE,%a0 | probe dio scode 132 246 ASRELOC(phys_badaddr,%a3) 247 jbsr %a3@ 248 tstl %d0 | device at scode 132? 249 jne Lstart1 | no, not 362, assume 360 250 movb %a0@(DIO_IDOFF),%d0 251 cmpb #DIO_DEVICE_ID_FRAMEBUFFER,%d0 | framebuffer? 252 jne Lstart1 | no, not 362, assume 360 253 movb %a0@(DIO_SECIDOFF),%d0 254 cmpb #0x11,%d0 | VRX sti on 362? 255 jne Lstart1 | no, not 362, assume 360 256 RELOC(machineid,%a0) 257 movl #HP_362,%a0@ 258 jra Lstart1 259Lisa345: 260 movl #HP_345,%a0@ 261 jra Lhaspac 262Lisa375: 263 movl #HP_375,%a0@ 264 jra Lhaspac 265Lisa370: 266 movl #HP_370,%a0@ | set to 370 267Lhaspac: 268 RELOC(ectype, %a0) 269 movl #EC_PHYS,%a0@ | also has a physical address cache 270 jra Lstart1 271 272 /* 273 * End of 68030 section 274 */ 275 276Lnot68030: 277 bset #31,%d0 | data cache enable bit 278 movc %d0,%cacr | only exists on 68040 279 movc %cacr,%d0 | read it back 280 tstl %d0 | zero? 281 beq Lis68020 | yes, we have 68020 282 moveq #0,%d0 | now turn it back off 283 movec %d0,%cacr | before we access any data 284 285 /* 286 * 68040 models 287 */ 288 289 RELOC(mmutype, %a0) 290 movl #MMU_68040,%a0@ | with a 68040 MMU 291 RELOC(cputype, %a0) 292 movl #CPU_68040,%a0@ | and a 68040 CPU 293 RELOC(fputype, %a0) 294 movl #FPU_68040,%a0@ | ...and FPU 295 RELOC(ectype, %a0) 296 movl #EC_NONE,%a0@ | and no cache (for now XXX) 297 RELOC(mmuid,%a0) | save MMU ID 298 movl %a1@(MMUCMD),%d0 299 lsrl #MMUID_SHIFT,%d0 300 andl #MMUID_MASK,%d0 301 movl %d0,%a0@ 302 RELOC(machineid, %a0) 303 cmpb #MMUID_425_T,%d0 | are we a 425t? 304 jeq Lisa425 305 cmpb #MMUID_425_S,%d0 | how about 425s? 306 jeq Lisa425 307 cmpb #MMUID_425_E,%d0 | or maybe a 425e? 308 jeq Lisa425 309 cmpb #MMUID_433_T,%d0 | or a 433t? 310 jeq Lisa433 311 cmpb #MMUID_433_S,%d0 | or a 433s? 312 jeq Lisa433 313 cmpb #MMUID_385,%d0 | or a 385? 314 jeq Lisa385 315 cmpb #MMUID_382,%d0 | or a 382? 316 jeq Lisa382 317 movl #HP_380,%a0@ | guess we're a 380 318 jra Lstart1 319Lisa425: 320 movl #HP_425,%a0@ 321 jra Lstart1 322Lisa433: 323 movl #HP_433,%a0@ 324 jra Lstart1 325Lisa385: 326 movl #HP_385,%a0@ 327 jra Lstart1 328Lisa382: 329 movl #HP_382,%a0@ 330 jra Lstart1 331 332 /* 333 * End of 68040 section 334 */ 335 336 /* 337 * 68020 models 338 */ 339 340Lis68020: 341 RELOC(fputype, %a0) | all of the 68020 systems 342 movl #FPU_68881,%a0@ | have a 68881 FPU 343 movl #1,%a1@(MMUCMD) | a 68020, write HP MMU location 344 movl %a1@(MMUCMD),%d0 | read it back 345 btst #0,%d0 | non-zero? 346 jne Lishpmmu | yes, we have HP MMU 347 RELOC(mmutype, %a0) 348 movl #MMU_68851,%a0@ | no, we have PMMU 349 RELOC(machineid, %a0) 350 movl #HP_330,%a0@ | and 330 CPU 351 jra Lstart1 352Lishpmmu: 353 RELOC(ectype, %a0) | 320 or 350 354 movl #EC_VIRT,%a0@ | both have a virtual address cache 355 movl #0x80,%a1@(MMUCMD) | set magic cookie 356 movl %a1@(MMUCMD),%d0 | read it back 357 btst #7,%d0 | cookie still on? 358 jeq Lis320 | no, just a 320 359 RELOC(machineid, %a0) 360 movl #HP_350,%a0@ | yes, a 350 361 jra Lstart1 362Lis320: 363 RELOC(machineid, %a0) 364 movl #HP_320,%a0@ 365 366 /* 367 * End of 68020 section 368 */ 369 370Lstart1: 371 movl #0,%a1@(MMUCMD) | clear out MMU again 372/* initialize source/destination control registers for movs */ 373 moveq #FC_USERD,%d0 | user space 374 movc %d0,%sfc | as source 375 movc %d0,%dfc | and destination of transfers 376/* save the first PA as bootinfo_pa to map it to a virtual address later. */ 377 movl %a5,%d0 | lowram value from ROM via boot 378 RELOC(bootinfo_pa, %a0) 379 movl %d0,%a0@ | save the lowram as bootinfo PA 380/* initialize memory sizes (for pmap_bootstrap) */ 381 movl #MAXADDR,%d1 | last page 382 moveq #PGSHIFT,%d2 383 lsrl %d2,%d1 | convert to page (click) number 384 RELOC(maxmem, %a0) 385 movl %d1,%a0@ | save as maxmem 386 lsrl %d2,%d0 | convert the lowram to page number 387 subl %d0,%d1 | compute amount of RAM present 388 RELOC(physmem, %a0) 389 movl %d1,%a0@ | and physmem 390 391/* configure kernel and lwp0 VA space so we can get going */ 392#if NKSYMS || defined(DDB) || defined(MODULAR) 393 RELOC(esym,%a0) | end of static kernel test/data/syms 394 movl %a0@,%d5 395 jne Lstart3 396#endif 397 movl #_C_LABEL(end),%d5 | end of static kernel text/data 398Lstart3: 399 addl #PAGE_SIZE-1,%d5 400 andl #PG_FRAME,%d5 | round to a page 401 movl %d5,%a4 402 addl %a5,%a4 | convert to PA 403 pea %a5@ | firstpa 404 pea %a4@ | nextpa 405 RELOC(pmap_bootstrap,%a0) 406 jbsr %a0@ | pmap_bootstrap(firstpa, nextpa) 407 addql #8,%sp 408 409/* 410 * Prepare to enable MMU. 411 * Since the kernel is not mapped logical == physical we must insure 412 * that when the MMU is turned on, all prefetched addresses (including 413 * the PC) are valid. In order guarantee that, we use the last physical 414 * page (which is conveniently mapped == VA) and load it up with enough 415 * code to defeat the prefetch, then we execute the jump back to here. 416 * 417 * Is this all really necessary, or am I paranoid?? 418 */ 419 RELOC(Sysseg_pa, %a0) | system segment table addr 420 movl %a0@,%d1 | read value (a PA) 421 RELOC(mmutype, %a0) 422 tstl %a0@ | HP MMU? 423 jeq Lhpmmu2 | yes, skip 424 cmpl #MMU_68040,%a0@ | 68040? 425 jne Lmotommu1 | no, skip 426 .long 0x4e7b1807 | movc %d1,%srp 427 jra Lstploaddone 428Lmotommu1: 429 RELOC(protorp, %a0) 430 movl %d1,%a0@(4) | segtable address 431 pmove %a0@,%srp | load the supervisor root pointer 432 jra Lstploaddone | done 433Lhpmmu2: 434 moveq #PGSHIFT,%d2 435 lsrl %d2,%d1 | convert to page frame 436 movl %d1,INTIOBASE+MMUBASE+MMUSSTP | load in sysseg table register 437Lstploaddone: 438 lea MAXADDR,%a2 | PA of last RAM page 439#if 0 440 ASRELOC(Lhighcode, %a1) | addr of high code 441 ASRELOC(Lehighcode, %a3) | end addr 442#else 443 /* don't want pc-relative addressing */ 444 .word 0x43f9 | lea Lhighcode, %a1 445 .long Lhighcode 446 addl %a5, %a1 447 .word 0x47f9 | lea Lehighcode, %a3 448 .long Lehighcode 449 addl %a5, %a3 450#endif 451Lcodecopy: 452 movw %a1@+,%a2@+ | copy a word 453 cmpl %a3,%a1 | done yet? 454 jcs Lcodecopy | no, keep going 455 jmp MAXADDR | go for it! 456 457 /* 458 * BEGIN MMU TRAMPOLINE. This section of code is not 459 * executed in-place. It's copied to the last page 460 * of RAM (mapped va == pa) and executed there. 461 */ 462 463Lhighcode: 464 RELOC(mmutype, %a0) 465 tstl %a0@ | HP MMU? 466 jeq Lhpmmu3 | yes, skip 467 cmpl #MMU_68040,%a0@ | 68040? 468 jne Lmotommu2 | no, skip 469 movw #0,INTIOBASE+MMUBASE+MMUCMD+2 470 movw #MMU_IEN+MMU_CEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD+2 471 | enable FPU and caches 472 moveq #0,%d0 | ensure TT regs are disabled 473 .long 0x4e7b0004 | movc %d0,%itt0 474 .long 0x4e7b0005 | movc %d0,%itt1 475 .long 0x4e7b0006 | movc %d0,%dtt0 476 .long 0x4e7b0007 | movc %d0,%dtt1 477 .word 0xf4d8 | cinva bc 478 .word 0xf518 | pflusha 479 movl #MMU40_TCR_BITS,%d0 480 .long 0x4e7b0003 | movc %d0,%tc 481 movl #CACHE40_ON,%d0 482 movc %d0,%cacr | turn on both caches 483 jmp Lenab1:l | forced not be pc-relative 484Lmotommu2: 485 movl #MMU_IEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD 486 | enable 68881 and i-cache 487 pflusha 488 RELOC(prototc, %a2) 489 movl #MMU51_TCR_BITS,%a2@ | value to load TC with 490 pmove %a2@,%tc | load it 491 jmp Lenab1:l | forced not be pc-relative 492Lhpmmu3: 493 movl #0,INTIOBASE+MMUBASE+MMUCMD | clear external cache 494 movl #MMU_ENAB,INTIOBASE+MMUBASE+MMUCMD | turn on MMU 495 jmp Lenab1:l | forced not be pc-relative 496Lehighcode: 497 498 /* 499 * END MMU TRAMPOLINE. Address register %a5 is now free. 500 */ 501 502/* 503 * Should be running mapped from this point on 504 */ 505Lenab1: 506 lea _ASM_LABEL(tmpstk),%sp | re-load the temporary stack 507 jbsr _C_LABEL(vec_init) | initialize the vector table 508/* call final pmap setup */ 509 jbsr _C_LABEL(pmap_bootstrap_finalize) 510/* set kernel stack, user SP */ 511 movl _C_LABEL(lwp0uarea),%a1 | get lwp0 uarea 512 lea %a1@(USPACE-4),%sp | set kernel stack to end of area 513 movl #USRSTACK-4,%a2 514 movl %a2,%usp | init user SP 515 516 jbsr _C_LABEL(fpu_probe) 517 movl %d0,_C_LABEL(fputype) 518 tstl _C_LABEL(fputype) | Have an FPU? 519 jeq Lenab2 | No, skip. 520 clrl %a1@(PCB_FPCTX) | ensure null FP context 521 movl %a1,%sp@- 522 jbsr _C_LABEL(m68881_restore) | restore it (does not kill %a1) 523 addql #4,%sp 524Lenab2: 525/* flush TLB and turn on caches */ 526 jbsr _C_LABEL(_TBIA) | invalidate TLB 527 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 528 jeq Lnocache0 | yes, cache already on 529 movl #CACHE_ON,%d0 530 movc %d0,%cacr | clear cache(s) 531 tstl _C_LABEL(ectype) 532 jeq Lnocache0 533 MMUADDR(%a0) 534 orl #MMU_CEN,%a0@(MMUCMD) | turn on external cache 535Lnocache0: 536/* Final setup for call to main(). */ 537 jbsr _C_LABEL(hp300_init) 538 539/* 540 * Create a fake exception frame so that cpu_lwp_fork() can copy it. 541 * main() nevers returns; we exit to user mode from a forked process 542 * later on. 543 */ 544 clrw %sp@- | vector offset/frame type 545 clrl %sp@- | PC - filled in by "execve" 546 movw #PSL_USER,%sp@- | in user mode 547 clrl %sp@- | stack adjust count and padding 548 lea %sp@(-64),%sp | construct space for D0-D7/A0-A7 549 lea _C_LABEL(lwp0),%a0 | save pointer to frame 550 movl %sp,%a0@(L_MD_REGS) | in lwp0.l_md.md_regs 551 552 jra _C_LABEL(main) | main() 553 PANIC("main() returned") 554 /* NOTREACHED */ 555 556/* 557 * Trap/interrupt vector routines 558 */ 559#include <m68k/m68k/trap_subr.s> 560 561/* 562 * Use common m68k bus error and address error handlers. 563 */ 564#include <m68k/m68k/busaddrerr.s> 565 566/* 567 * FP exceptions. 568 */ 569ENTRY_NOPROFILE(fpfline) 570#if defined(M68040) 571 cmpl #FPU_68040,_C_LABEL(fputype) | 68040 FPU? 572 jne Lfp_unimp | no, skip FPSP 573 cmpw #0x202c,%sp@(6) | format type 2? 574 jne _C_LABEL(illinst) | no, not an FP emulation 575Ldofp_unimp: 576#ifdef FPSP 577 jmp _ASM_LABEL(fpsp_unimp) | yes, go handle it 578#endif 579Lfp_unimp: 580#endif /* M68040 */ 581#ifdef FPU_EMULATE 582 clrl %sp@- | stack adjust count 583 moveml #0xFFFF,%sp@- | save registers 584 moveq #T_FPEMULI,%d0 | denote as FP emulation trap 585 jra _ASM_LABEL(fault) | do it 586#else 587 jra _C_LABEL(illinst) 588#endif 589 590ENTRY_NOPROFILE(fpunsupp) 591#if defined(M68040) 592 cmpl #FPU_68040,_C_LABEL(fputype) | 68040 FPU? 593 jne _C_LABEL(illinst) | no, treat as illinst 594#ifdef FPSP 595 jmp _ASM_LABEL(fpsp_unsupp) | yes, go handle it 596#endif 597Lfp_unsupp: 598#endif /* M68040 */ 599#ifdef FPU_EMULATE 600 clrl %sp@- | stack adjust count 601 moveml #0xFFFF,%sp@- | save registers 602 moveq #T_FPEMULD,%d0 | denote as FP emulation trap 603 jra _ASM_LABEL(fault) | do it 604#else 605 jra _C_LABEL(illinst) 606#endif 607 608/* 609 * Handles all other FP coprocessor exceptions. 610 * Note that since some FP exceptions generate mid-instruction frames 611 * and may cause signal delivery, we need to test for stack adjustment 612 * after the trap call. 613 */ 614ENTRY_NOPROFILE(fpfault) 615 clrl %sp@- | stack adjust count 616 moveml #0xFFFF,%sp@- | save user registers 617 movl %usp,%a0 | and save 618 movl %a0,%sp@(FR_SP) | the user stack pointer 619 clrl %sp@- | no VA arg 620 movl _C_LABEL(curpcb),%a0 | current pcb 621 lea %a0@(PCB_FPCTX),%a0 | address of FP savearea 622 fsave %a0@ | save state 623#if defined(M68040) || defined(M68060) 624 /* always null state frame on 68040, 68060 */ 625 cmpl #FPU_68040,_C_LABEL(fputype) 626 jge Lfptnull 627#endif 628 tstb %a0@ | null state frame? 629 jeq Lfptnull | yes, safe 630 clrw %d0 | no, need to tweak BIU 631 movb %a0@(1),%d0 | get frame size 632 bset #3,%a0@(0,%d0:w) | set exc_pend bit of BIU 633Lfptnull: 634 fmovem %fpsr,%sp@- | push %fpsr as code argument 635 frestore %a0@ | restore state 636 movl #T_FPERR,%sp@- | push type arg 637 jra _ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup 638 639/* 640 * Other exceptions only cause four and six word stack frame and require 641 * no post-trap stack adjustment. 642 */ 643 644ENTRY_NOPROFILE(badtrap) 645 moveml #0xC0C0,%sp@- | save scratch regs 646 movw %sp@(22),%sp@- | push exception vector info 647 clrw %sp@- 648 movl %sp@(22),%sp@- | and PC 649 jbsr _C_LABEL(straytrap) | report 650 addql #8,%sp | pop args 651 moveml %sp@+,#0x0303 | restore regs 652 jra _ASM_LABEL(rei) | all done 653 654ENTRY_NOPROFILE(trap0) 655 clrl %sp@- | stack adjust count 656 moveml #0xFFFF,%sp@- | save user registers 657 movl %usp,%a0 | save the user SP 658 movl %a0,%sp@(FR_SP) | in the savearea 659 movl %d0,%sp@- | push syscall number 660 jbsr _C_LABEL(syscall) | handle it 661 addql #4,%sp | pop syscall arg 662 tstl _C_LABEL(astpending) | AST pending? 663 jne Lrei | yes, handle it via trap 664 movl %sp@(FR_SP),%a0 | grab and restore 665 movl %a0,%usp | user SP 666 moveml %sp@+,#0x7FFF | restore most registers 667 addql #8,%sp | pop SP and stack adjust 668 rte 669 670/* 671 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD) 672 * cachectl(command, addr, length) 673 * command in %d0, addr in %a1, length in %d1 674 */ 675ENTRY_NOPROFILE(trap12) 676 movl _C_LABEL(curlwp),%a0 677 movl %a0@(L_PROC),%sp@- | push current proc pointer 678 movl %d1,%sp@- | push length 679 movl %a1,%sp@- | push addr 680 movl %d0,%sp@- | push command 681 jbsr _C_LABEL(cachectl1) | do it 682 lea %sp@(16),%sp | pop args 683 jra _ASM_LABEL(rei) | all done 684 685/* 686 * Trace (single-step) trap. Kernel-mode is special. 687 * User mode traps are simply passed on to trap(). 688 */ 689ENTRY_NOPROFILE(trace) 690 clrl %sp@- | stack adjust count 691 moveml #0xFFFF,%sp@- 692 moveq #T_TRACE,%d0 693 694 | Check PSW and see what happen. 695 | T=0 S=0 (should not happen) 696 | T=1 S=0 trace trap from user mode 697 | T=0 S=1 trace trap on a trap instruction 698 | T=1 S=1 trace trap from system mode (kernel breakpoint) 699 700 movw %sp@(FR_HW),%d1 | get PSW 701 notw %d1 | XXX no support for T0 on 680[234]0 702 andw #PSL_TS,%d1 | from system mode (T=1, S=1)? 703 jeq Lkbrkpt | yes, kernel breakpoint 704 jra _ASM_LABEL(fault) | no, user-mode fault 705 706/* 707 * Trap 15 is used for: 708 * - GDB breakpoints (in user programs) 709 * - KGDB breakpoints (in the kernel) 710 * - trace traps for SUN binaries (not fully supported yet) 711 * User mode traps are simply passed to trap(). 712 */ 713ENTRY_NOPROFILE(trap15) 714 clrl %sp@- | stack adjust count 715 moveml #0xFFFF,%sp@- 716 moveq #T_TRAP15,%d0 717 movw %sp@(FR_HW),%d1 | get PSW 718 andw #PSL_S,%d1 | from system mode? 719 jne Lkbrkpt | yes, kernel breakpoint 720 jra _ASM_LABEL(fault) | no, user-mode fault 721 722Lkbrkpt: | Kernel-mode breakpoint or trace trap. (%d0=trap_type) 723 | Save the system sp rather than the user sp. 724 movw #PSL_HIGHIPL,%sr | lock out interrupts 725 lea %sp@(FR_SIZE),%a6 | Save stack pointer 726 movl %a6,%sp@(FR_SP) | from before trap 727 728 | If were are not on tmpstk switch to it. 729 | (so debugger can change the stack pointer) 730 movl %a6,%d1 731 cmpl #_ASM_LABEL(tmpstk),%d1 732 jls Lbrkpt2 | already on tmpstk 733 | Copy frame to the temporary stack 734 movl %sp,%a0 | %a0=src 735 lea _ASM_LABEL(tmpstk)-96,%a1 | %a1=dst 736 movl %a1,%sp | %sp=new frame 737 moveq #FR_SIZE,%d1 738Lbrkpt1: 739 movl %a0@+,%a1@+ 740 subql #4,%d1 741 jgt Lbrkpt1 742 743Lbrkpt2: 744 | Call the trap handler for the kernel debugger. 745 | Do not call trap() to do it, so that we can 746 | set breakpoints in trap() if we want. We know 747 | the trap type is either T_TRACE or T_BREAKPOINT. 748 | If we have both DDB and KGDB, let KGDB see it first, 749 | because KGDB will just return 0 if not connected. 750 | Save args in %d2, %a2 751 movl %d0,%d2 | trap type 752 movl %sp,%a2 | frame ptr 753#ifdef KGDB 754 | Let KGDB handle it (if connected) 755 movl %a2,%sp@- | push frame ptr 756 movl %d2,%sp@- | push trap type 757 jbsr _C_LABEL(kgdb_trap) | handle the trap 758 addql #8,%sp | pop args 759 cmpl #0,%d0 | did kgdb handle it? 760 jne Lbrkpt3 | yes, done 761#endif 762#ifdef DDB 763 | Let DDB handle it 764 movl %a2,%sp@- | push frame ptr 765 movl %d2,%sp@- | push trap type 766 jbsr _C_LABEL(kdb_trap) | handle the trap 767 addql #8,%sp | pop args 768#if 0 /* not needed on hp300 */ 769 cmpl #0,%d0 | did ddb handle it? 770 jne Lbrkpt3 | yes, done 771#endif 772#endif 773 /* Sun 3 drops into PROM here. */ 774Lbrkpt3: 775 | The stack pointer may have been modified, or 776 | data below it modified (by kgdb push call), 777 | so push the hardware frame at the current sp 778 | before restoring registers and returning. 779 780 movl %sp@(FR_SP),%a0 | modified %sp 781 lea %sp@(FR_SIZE),%a1 | end of our frame 782 movl %a1@-,%a0@- | copy 2 longs with 783 movl %a1@-,%a0@- | ... predecrement 784 movl %a0,%sp@(FR_SP) | %sp = h/w frame 785 moveml %sp@+,#0x7FFF | restore all but %sp 786 movl %sp@,%sp | ... and %sp 787 rte | all done 788 789/* 790 * Interrupt handlers. 791 * All device interrupts are auto-vectored. The CPU provides 792 * the vector 0x18+level. Note we count spurious interrupts, but 793 * we don't do anything else with them. 794 */ 795 796/* 64-bit evcnt counter increments */ 797#define EVCNT_COUNTER(ipl) \ 798 _C_LABEL(m68k_intr_evcnt) + (ipl)*SIZEOF_EVCNT + EV_COUNT 799#define EVCNT_INCREMENT(ipl) \ 800 clrl %d0; \ 801 addql #1,EVCNT_COUNTER(ipl)+4; \ 802 movel EVCNT_COUNTER(ipl),%d1; \ 803 addxl %d0,%d1; \ 804 movel %d1,EVCNT_COUNTER(ipl) 805 806ENTRY_NOPROFILE(lev6intr) /* level 6: clock */ 807 addql #1,_C_LABEL(intr_depth) | entering interrupt 808 INTERRUPT_SAVEREG 809 CLKADDR(%a0) 810 movb %a0@(CLKSR),%d0 | read clock status 811Lclkagain: 812 btst #0,%d0 | clear timer1 int immediately to 813 jeq Lnotim1 | minimize chance of losing another 814 movpw %a0@(CLKMSB1),%d1 | due to statintr processing delay 815 movl _C_LABEL(clkint),%d1 | clkcounter += clkint 816 addl %d1,_C_LABEL(clkcounter) 817Lnotim1: 818 btst #2,%d0 | timer3 interrupt? 819 jeq Lnotim3 | no, skip statclock 820 movpw %a0@(CLKMSB3),%d1 | clear timer3 interrupt 821 lea %sp@(0),%a1 | a1 = &clockframe 822 movl %d0,%sp@- | save status 823 movl %a1,%sp@- 824 jbsr _C_LABEL(statintr) | statintr(&frame) 825 addql #4,%sp 826 movl %sp@+,%d0 | restore pre-statintr status 827 CLKADDR(%a0) 828Lnotim3: 829 btst #0,%d0 | timer1 interrupt? 830 jeq Lrecheck | no, skip hardclock 831 EVCNT_INCREMENT(6) 832 lea %sp@(0),%a1 | a1 = &clockframe 833 movl %a1,%sp@- 834#ifdef USELEDS 835 tstl _C_LABEL(ledaddr) | using LEDs? 836 jeq Lnoleds0 | no, skip this code 837 movl _ASM_LABEL(heartbeat),%d0 | get tick count 838 addql #1,%d0 | increment 839 movl _C_LABEL(hz),%d1 840 addl #50,%d1 | get the timing a little closer 841 tstb _ASM_LABEL(beatstatus) | time to slow down? 842 jeq Lslowthrob | yes, slow down 843 lsrl #3,%d1 | no, fast throb 844Lslowthrob: 845 lsrl #1,%d1 | slow throb 846 cmpl %d0,%d1 | are we there yet? 847 jne Lnoleds1 | no, nothing to do 848 addqb #1,_ASM_LABEL(beatstatus) | incr beat status 849 cmpb #3,_ASM_LABEL(beatstatus) | time to reset? 850 jle Ltwinkle | no, twinkle the lights 851 movb #0,_ASM_LABEL(beatstatus) | reset the status indicator 852Ltwinkle: 853 movl #LED_PULSE,%sp@- 854 movl #LED_DISK+LED_LANRCV+LED_LANXMT,%sp@- 855 clrl %sp@- 856 jbsr _C_LABEL(ledcontrol) | toggle pulse, turn all others off 857 lea %sp@(12),%sp 858 movql #0,%d0 859Lnoleds1: 860 movl %d0,_ASM_LABEL(heartbeat) 861Lnoleds0: 862#endif /* USELEDS */ 863 jbsr _C_LABEL(hardclock) | hardclock(&frame) 864 addql #4,%sp 865Lrecheck: 866 CPUINFO_INCREMENT(CI_NINTR) | chalk up another interrupt 867 CLKADDR(%a0) 868 movb %a0@(CLKSR),%d0 | see if anything happened 869 jmi Lclkagain | while we were in hardclock/statintr 870#if NAUDIO >0 871 jbsr _C_LABEL(m68k_intr_autovec) | call dispatch routine 872 | in case the audio device 873 | generated the interrupt 874#endif 875 INTERRUPT_RESTOREREG 876 subql #1,_C_LABEL(intr_depth) | exiting from interrupt 877 jra _ASM_LABEL(rei) | all done 878 879ENTRY_NOPROFILE(lev7intr) /* level 7: parity errors, reset key */ 880 clrl %sp@- 881 moveml #0xFFFF,%sp@- | save registers 882 EVCNT_INCREMENT(7) 883 movl %usp,%a0 | and save 884 movl %a0,%sp@(FR_SP) | the user stack pointer 885 jbsr _C_LABEL(nmihand) | call handler 886 movl %sp@(FR_SP),%a0 | restore 887 movl %a0,%usp | user SP 888 moveml %sp@+,#0x7FFF | and remaining registers 889 addql #8,%sp | pop SP and stack adjust 890 jra _ASM_LABEL(rei) | all done 891 892/* 893 * Emulation of VAX REI instruction. 894 * 895 * This code deals with checking for and servicing 896 * ASTs (profiling, scheduling). 897 * After identifying that we need an AST we drop the IPL 898 * to allow device interrupts. 899 * 900 * This code is complicated by the fact that sendsig may have been called 901 * necessitating a stack cleanup. 902 */ 903 904ASENTRY_NOPROFILE(rei) 905 tstl _C_LABEL(astpending) | AST pending? 906 jne 1f | no, done 907 rte 9081: 909 btst #5,%sp@ | yes, are we returning to user mode? 910 jeq 2f | no, done 911 rte 9122: 913 movw #PSL_LOWIPL,%sr | lower SPL 914 clrl %sp@- | stack adjust 915 moveml #0xFFFF,%sp@- | save all registers 916 movl %usp,%a1 | including 917 movl %a1,%sp@(FR_SP) | the users SP 918Lrei: 919 clrl %sp@- | VA == none 920 clrl %sp@- | code == none 921 movl #T_ASTFLT,%sp@- | type == async system trap 922 pea %sp@(12) | fp == address of trap frame 923 jbsr _C_LABEL(trap) | go handle it 924 lea %sp@(16),%sp | pop value args 925 movl %sp@(FR_SP),%a0 | restore user SP 926 movl %a0,%usp | from save area 927 movw %sp@(FR_ADJ),%d0 | need to adjust stack? 928 jne Laststkadj | yes, go to it 929 moveml %sp@+,#0x7FFF | no, restore most user regs 930 addql #8,%sp | toss SP and stack adjust 931 rte | and do real RTE 932Laststkadj: 933 lea %sp@(FR_HW),%a1 | pointer to HW frame 934 addql #8,%a1 | source pointer 935 movl %a1,%a0 | source 936 addw %d0,%a0 | + hole size = dest pointer 937 movl %a1@-,%a0@- | copy 938 movl %a1@-,%a0@- | 8 bytes 939 movl %a0,%sp@(FR_SP) | new SSP 940 moveml %sp@+,#0x7FFF | restore user registers 941 movl %sp@,%sp | and our SP 942 rte | and do real RTE 943 944/* 945 * Primitives 946 */ 947 948/* 949 * Use common m68k process/lwp switch and context save subroutines. 950 */ 951#define FPCOPROC /* XXX: Temp. reqd. */ 952#include <m68k/m68k/switch_subr.s> 953 954 955#if defined(M68040) 956ENTRY(suline) 957 movl %sp@(4),%a0 | address to write 958 movl _C_LABEL(curpcb),%a1 | current pcb 959 movl #Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault 960 movl %sp@(8),%a1 | address of line 961 movl %a1@+,%d0 | get lword 962 movsl %d0,%a0@+ | put lword 963 nop | sync 964 movl %a1@+,%d0 | get lword 965 movsl %d0,%a0@+ | put lword 966 nop | sync 967 movl %a1@+,%d0 | get lword 968 movsl %d0,%a0@+ | put lword 969 nop | sync 970 movl %a1@+,%d0 | get lword 971 movsl %d0,%a0@+ | put lword 972 nop | sync 973 moveq #0,%d0 | indicate no fault 974 jra Lsldone 975Lslerr: 976 moveq #-1,%d0 977Lsldone: 978 movl _C_LABEL(curpcb),%a1 | current pcb 979 clrl %a1@(PCB_ONFAULT) | clear fault address 980 rts 981#endif 982 983ENTRY(ecacheon) 984 tstl _C_LABEL(ectype) 985 jeq Lnocache7 986 MMUADDR(%a0) 987 orl #MMU_CEN,%a0@(MMUCMD) 988Lnocache7: 989 rts 990 991ENTRY(ecacheoff) 992 tstl _C_LABEL(ectype) 993 jeq Lnocache8 994 MMUADDR(%a0) 995 andl #~MMU_CEN,%a0@(MMUCMD) 996Lnocache8: 997 rts 998 999/* 1000 * _delay(u_int N) 1001 * 1002 * Delay for at least (N/256) microseconds. 1003 * This routine depends on the variable: delay_divisor 1004 * which should be set based on the CPU clock rate. 1005 */ 1006ENTRY_NOPROFILE(_delay) 1007 | %d0 = arg = (usecs << 8) 1008 movl %sp@(4),%d0 1009 | %d1 = delay_divisor 1010 movl _C_LABEL(delay_divisor),%d1 1011 jra L_delay /* Jump into the loop! */ 1012 1013 /* 1014 * Align the branch target of the loop to a half-line (8-byte) 1015 * boundary to minimize cache effects. This guarantees both 1016 * that there will be no prefetch stalls due to cache line burst 1017 * operations and that the loop will run from a single cache 1018 * half-line. 1019 */ 1020 .align 8 1021L_delay: 1022 subl %d1,%d0 1023 jgt L_delay 1024 rts 1025 1026/* 1027 * Probe a memory address, and see if it causes a bus error. 1028 * This function is only to be used in physical mode, and before our 1029 * trap vectors are initialized. 1030 * Invoke with address to probe in %a0. 1031 * Alters: %a3 %d0 1032 */ 1033#define BUSERR 0xfffffffc 1034ASLOCAL(phys_badaddr) 1035 ASRELOC(_bsave,%a3) 1036 movl BUSERR,%a3@ | save ROM bus error handler 1037 ASRELOC(_ssave,%a3) 1038 movl %sp,%a3@ | and current stack pointer 1039 ASRELOC(catchbad,%a3) 1040 movl %a3,BUSERR | plug in our handler 1041 movb %a0@,%d0 | access address 1042 ASRELOC(_bsave,%a3) | no fault! 1043 movl %a3@,BUSERR 1044 clrl %d0 | return success 1045 rts 1046ASLOCAL(catchbad) 1047 ASRELOC(_bsave,%a3) | got a bus error, so restore handler 1048 movl %a3@,BUSERR 1049 ASRELOC(_ssave,%a3) 1050 movl %a3@,%sp | and stack 1051 moveq #1,%d0 | return fault 1052 rts 1053#undef BUSERR 1054 1055 .data 1056ASLOCAL(_bsave) 1057 .long 0 1058ASLOCAL(_ssave) 1059 .long 0 1060 .text 1061 1062/* 1063 * Handle the nitty-gritty of rebooting the machine. 1064 * Basically we just turn off the MMU and jump to the appropriate ROM routine. 1065 * Note that we must be running in an address range that is mapped one-to-one 1066 * logical to physical so that the PC is still valid immediately after the MMU 1067 * is turned off. We have conveniently mapped the last page of physical 1068 * memory this way. 1069 */ 1070ENTRY_NOPROFILE(doboot) 1071#if defined(M68040) 1072 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 1073 jeq Lnocache5 | yes, skip 1074#endif 1075 movl #CACHE_OFF,%d0 1076 movc %d0,%cacr | disable on-chip cache(s) 1077 tstl _C_LABEL(ectype) | external cache? 1078 jeq Lnocache5 | no, skip 1079 MMUADDR(%a0) 1080 andl #~MMU_CEN,%a0@(MMUCMD) | disable external cache 1081Lnocache5: 1082 lea MAXADDR,%a0 | last page of physical memory 1083 movl _C_LABEL(boothowto),%a0@+ | store howto 1084 movl _C_LABEL(bootdev),%a0@+ | and devtype 1085 lea Lbootcode,%a1 | start of boot code 1086 lea Lebootcode,%a3 | end of boot code 1087Lbootcopy: 1088 movw %a1@+,%a0@+ | copy a word 1089 cmpl %a3,%a1 | done yet? 1090 jcs Lbootcopy | no, keep going 1091#if defined(M68040) 1092 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 1093 jne LmotommuE | no, skip 1094 .word 0xf4f8 | cpusha bc 1095LmotommuE: 1096#endif 1097 jmp MAXADDR+8 | jump to last page 1098 1099Lbootcode: 1100 lea MAXADDR+0x800,%sp | physical SP in case of NMI 1101#if defined(M68040) 1102 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 1103 jne LmotommuF | no, skip 1104 movl #0,%d0 1105 movc %d0,%cacr | caches off 1106 .long 0x4e7b0003 | movc %d0,%tc 1107 movl %d2,MAXADDR+PAGE_SIZE-4 | restore old high page contents 1108 DOREBOOT 1109LmotommuF: 1110#endif 1111#if defined(M68K_MMU_MOTOROLA) 1112 tstl _C_LABEL(mmutype) | HP MMU? 1113 jeq LhpmmuB | yes, skip 1114 movl #0,%a0@ | value for pmove to TC (turn off MMU) 1115 pmove %a0@,%tc | disable MMU 1116 DOREBOOT 1117LhpmmuB: 1118#endif 1119#if defined(M68K_MMU_HP) 1120 MMUADDR(%a0) 1121 movl #0xFFFF0000,%a0@(MMUCMD) | totally disable MMU 1122 movl %d2,MAXADDR+PAGE_SIZE-4 | restore old high page contents 1123 DOREBOOT 1124#endif 1125Lebootcode: 1126 1127/* 1128 * Misc. global variables. 1129 */ 1130 .data 1131GLOBAL(machineid) 1132 .long HP_320 | default to 320 1133 1134GLOBAL(mmuid) 1135 .long 0 | default to nothing 1136 1137GLOBAL(mmutype) 1138 .long MMU_HP | default to HP MMU 1139 1140GLOBAL(cputype) 1141 .long CPU_68020 | default to 68020 CPU 1142 1143GLOBAL(ectype) 1144 .long EC_NONE | external cache type, default to none 1145 1146GLOBAL(fputype) 1147 .long FPU_68882 | default to 68882 FPU 1148 1149GLOBAL(prototc) 1150 .long 0 | prototype translation control 1151 1152GLOBAL(internalhpib) 1153 .long 1 | has internal HP-IB, default to yes 1154 1155GLOBAL(intiobase) 1156 .long 0 | KVA of base of internal IO space 1157 1158GLOBAL(intiolimit) 1159 .long 0 | KVA of end of internal IO space 1160 1161GLOBAL(extiobase) 1162 .long 0 | KVA of base of external IO space 1163 1164GLOBAL(CLKbase) 1165 .long 0 | KVA of base of clock registers 1166 1167GLOBAL(MMUbase) 1168 .long 0 | KVA of base of HP MMU registers 1169 1170#ifdef USELEDS 1171ASLOCAL(heartbeat) 1172 .long 0 | clock ticks since last heartbeat 1173 1174ASLOCAL(beatstatus) 1175 .long 0 | for determining a fast or slow throb 1176#endif 1177 1178#ifdef DEBUG 1179ASGLOBAL(fulltflush) 1180 .long 0 1181 1182ASGLOBAL(fullcflush) 1183 .long 0 1184#endif 1185