contributed by Ralph Campbell
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 8 Jan 1992 09:39:37 +0000 (01:39 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Wed, 8 Jan 1992 09:39:37 +0000 (01:39 -0800)
SCCS-vsn: sys/pmax/pmax/OLD/Locore.c 7.1
SCCS-vsn: sys/pmax/pmax/autoconf.c 7.1
SCCS-vsn: sys/pmax/pmax/clock.c 7.1
SCCS-vsn: sys/pmax/pmax/conf.c 7.1
SCCS-vsn: sys/pmax/pmax/cons.c 7.1
SCCS-vsn: sys/pmax/pmax/genassym.c 7.1
SCCS-vsn: sys/pmax/pmax/machdep.c 7.1
SCCS-vsn: sys/pmax/pmax/mem.c 7.1
SCCS-vsn: sys/pmax/pmax/pmap.c 7.1
SCCS-vsn: sys/pmax/pmax/swapgeneric.c 7.1
SCCS-vsn: sys/pmax/pmax/sys_machdep.c 7.1
SCCS-vsn: sys/pmax/pmax/trap.c 7.1
SCCS-vsn: sys/pmax/pmax/vm_machdep.c 7.1
SCCS-vsn: sys/pmax/pmax/clockreg.h 7.1
SCCS-vsn: sys/pmax/include/pte.h 7.1
SCCS-vsn: sys/pmax/pmax/fp.s 7.1
SCCS-vsn: sys/pmax/pmax/locore.s 7.1

17 files changed:
usr/src/sys/pmax/include/pte.h [new file with mode: 0644]
usr/src/sys/pmax/pmax/OLD/Locore.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/autoconf.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/clock.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/clockreg.h [new file with mode: 0644]
usr/src/sys/pmax/pmax/conf.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/cons.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/fp.s [new file with mode: 0644]
usr/src/sys/pmax/pmax/genassym.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/locore.s [new file with mode: 0644]
usr/src/sys/pmax/pmax/machdep.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/mem.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/pmap.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/swapgeneric.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/sys_machdep.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/trap.c [new file with mode: 0644]
usr/src/sys/pmax/pmax/vm_machdep.c [new file with mode: 0644]

diff --git a/usr/src/sys/pmax/include/pte.h b/usr/src/sys/pmax/include/pte.h
new file mode 100644 (file)
index 0000000..76fca1f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: pte.h 1.11 89/09/03$
+ *
+ *     @(#)pte.h       7.1 (Berkeley) %G%
+ */
+
+/*
+ * R2000 hardware page table entry
+ */
+
+#ifndef LOCORE
+struct pte {
+#if BYTE_ORDER == BIG_ENDIAN
+unsigned int   pg_pfnum:20,            /* HW: core page frame number or 0 */
+               pg_n:1,                 /* HW: non-cacheable bit */
+               pg_m:1,                 /* HW: modified (dirty) bit */
+               pg_v:1,                 /* HW: valid bit */
+               pg_g:1,                 /* HW: ignore pid bit */
+               :4,
+               pg_swapm:1,             /* SW: page must be forced to swap */
+               pg_fod:1,               /* SW: is fill on demand (=0) */
+               pg_prot:2;              /* SW: access control */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+unsigned int   pg_prot:2,              /* SW: access control */
+               pg_fod:1,               /* SW: is fill on demand (=0) */
+               pg_swapm:1,             /* SW: page must be forced to swap */
+               :4,
+               pg_g:1,                 /* HW: ignore pid bit */
+               pg_v:1,                 /* HW: valid bit */
+               pg_m:1,                 /* HW: modified (dirty) bit */
+               pg_n:1,                 /* HW: non-cacheable bit */
+               pg_pfnum:20;            /* HW: core page frame number or 0 */
+#endif
+};
+
+typedef union {
+       unsigned int    pt_entry;       /* for copying, etc. */
+       struct pte      pt_pte;         /* for getting to bits by name */
+} pt_entry_t;  /* Mach page table entry */
+#endif /* LOCORE */
+
+#define        PT_ENTRY_NULL   ((pt_entry_t *) 0)
+
+#define        PG_PROT         0x00000003
+#define PG_RW          0x00000000
+#define PG_RO          0x00000001
+#define PG_WIRED       0x00000002
+#define        PG_G            0x00000100
+#define        PG_V            0x00000200
+#define        PG_NV           0x00000000
+#define        PG_M            0x00000400
+#define        PG_N            0x00000800
+#define        PG_FRAME        0xfffff000
+#define PG_SHIFT       12
+#define        PG_PFNUM(x)     (((x) & PG_FRAME) >> PG_SHIFT)
+
+/*
+ * Kernel virtual address to page table entry and to physical address.
+ */
+#define        kvtopte(va) \
+       ((pt_entry_t *)PMAP_HASH_KADDR + \
+       (((vm_offset_t)(va) - VM_MIN_KERNEL_ADDRESS) >> PGSHIFT))
+#define        ptetokv(pte) \
+       ((((pt_entry_t *)(pte) - PMAP_HASH_KADDR) << PGSHIFT) + \
+       VM_MIN_KERNEL_ADDRESS)
+#define        kvtophys(va) \
+       ((kvtopte(va)->pt_entry & PG_FRAME) | ((unsigned)(va) & PGOFSET))
diff --git a/usr/src/sys/pmax/pmax/OLD/Locore.c b/usr/src/sys/pmax/pmax/OLD/Locore.c
new file mode 100644 (file)
index 0000000..1f6e9c5
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)Locore.c    7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "user.h"
+#include "vm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "buf.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "domain.h"
+#include "map.h"
+
+#include "pte.h"
+
+/*
+ * Pseudo file for lint to show what is used/defined in locore.s.
+ */
+
+int    dumpflag;
+int    intstack[3*NBPG];
+int    icode[8];
+int    szicode = sizeof (icode);
+char   MachUTLBMiss[10], MachUTLBMissEnd[1];
+char   MachException[10], MachException[1];
+
+/*
+ * Variables declared for savecore, or
+ * implicitly, such as by config or the loader.
+ */
+char   version[] = "4.3 BSD UNIX ....";
+int    etext;
+
+lowinit()
+{
+#if !defined(GPROF)
+       caddr_t cp;
+#endif
+       extern int dumpmag;
+       extern int rthashsize;
+       extern int arptab_size;
+       extern int dk_ndrive;
+       extern struct domain unixdomain;
+#ifdef INET
+       extern struct domain inetdomain;
+#endif
+#include "imp.h"
+#if NIMP > 0
+       extern struct domain impdomain;
+#endif
+#ifdef NS
+       extern struct domain nsdomain;
+#endif
+
+       /* cpp messes these up for lint so put them here */
+       unixdomain.dom_next = domains;
+       domains = &unixdomain;
+#ifdef INET
+       inetdomain.dom_next = domains;
+       domains = &inetdomain;
+#endif
+#if NIMP > 0
+       impdomain.dom_next = domains;
+       domains = &impdomain;
+#endif
+#ifdef NS
+       nsdomain.dom_next = domains;
+       domains = &nsdomain;
+#endif
+       dumpmag = 0;                    /* used only by savecore */
+       rthashsize = rthashsize;        /* used by netstat, etc. */
+       arptab_size = arptab_size;      /* used by arp command */
+       dk_ndrive = dk_ndrive;          /* used by vmstat, iostat, etc. */
+
+       /*
+        * Pseudo-uses of globals.
+        */
+       lowinit();
+       intstack[0] = intstack[1];
+       maxmem = physmem = freemem = 0;
+       u = u;
+       fixctlrmask();
+       main(0);
+       Xustray();
+
+       /*
+        * Routines called from interrupt vectors.
+        */
+       panic("Machine check");
+       printf("Write timeout");
+       consdin();
+       consdout();
+       hardclock((caddr_t)0, 0);
+       softclock((caddr_t)0, 0);
+       trap((unsigned)0, (unsigned)0, (unsigned)0, (unsigned)0);
+       memerr();
+
+       /*
+        * Miscellaneous routines called from configurable
+        * drivers.
+        */
+       disksort((struct buf *)0, (struct buf *)0);
+       (void) uwritec((struct uio *)0);
+       (void) todr();
+       if (vmemall((struct pte *)0, 0, (struct proc *)0, 0))
+               return;         /* use value */
+       boothowto = 0;
+       dumpflag = 0; dumpflag = dumpflag;
+#ifdef KADB
+       bootesym = 0; bootesym = bootesym;
+#endif
+#if !defined(GPROF)
+       cp = (caddr_t)&etext;
+       cp = cp;
+#endif
+}
+
+struct pte Sysmap[6*NPTEPG];
+#ifdef KADB
+char   Sysbase[6*NPTEPG*NBPG];
+#endif
+struct pte Usrptmap[USRPTSIZE];
+struct pte usrpt[USRPTSIZE*NPTEPG];
+struct pte Usriomap[USRIOSIZE];
+struct pte usrio[USRIOSIZE*NPTEPG];
+struct pte Forkmap[UPAGES];
+struct user forkutl;
+struct pte Xswapmap[UPAGES];
+struct user xswaputl;
+struct pte Xswap2map[UPAGES];
+struct user xswap2utl;
+struct pte Swapmap[UPAGES];
+struct user swaputl;
+struct pte Pushmap[UPAGES];
+struct user pushutl;
+struct pte Vfmap[UPAGES];
+struct user vfutl;
+struct pte Mbmap[NMBCLUSTERS/CLSIZE];
+struct mbuf mbutl[NMBCLUSTERS*CLBYTES/sizeof (struct mbuf)];
+struct pte kmempt[200];
+char   kmembase[100*NBPG];
+
+/*ARGSUSED*/
+badaddr(addr, len) char *addr; int len; { return (0); }
+
+/*ARGSUSED*/
+copyinstr(udaddr, kaddr, maxlength, lencopied)
+    caddr_t udaddr, kaddr; u_int maxlength, *lencopied;
+{ *kaddr = *udaddr; *lencopied = maxlength; return (0); }
+copyoutstr(kaddr, udaddr, maxlength, lencopied)
+    caddr_t kaddr, udaddr; u_int maxlength, *lencopied;
+{ *udaddr = *kaddr; *lencopied = maxlength; return (0); }
+copystr(kfaddr, kdaddr, maxlength, lencopied)
+    caddr_t kfaddr, kdaddr; u_int maxlength, *lencopied;
+{ *kdaddr = *kfaddr; *lencopied = maxlength; return (0); }
+
+/*ARGSUSED*/
+copyin(udaddr, kaddr, n) caddr_t udaddr, kaddr; u_int n; { return (0); }
+/*ARGSUSED*/
+copyout(kaddr, udaddr, n) caddr_t kaddr, udaddr; u_int n; { return (0); }
+
+/*ARGSUSED*/
+bzero(to, n) caddr_t to; u_int n; { }
+/*ARGSUSED*/
+bcmp(from, to, n) caddr_t from, to; u_int n; { }
+/*ARGSUSED*/
+bcopy(from, to, n) caddr_t from, to; u_int n; { }
+
+/*ARGSUSED*/
+CopyToBuffer(src, dst, length)
+       u_short *src, *dst; int length;
+{ *dst = *src; }
+/*ARGSUSED*/
+CopyFromBuffer(src, dst, length)
+       u_short *src; char *dst; int length;
+{ *dst = *src; }
+
+/*ARGSUSED*/
+savectx(lp) label_t *lp; { return (0); }
+
+/*ARGSUSED*/
+setrq(p) struct proc *p; { }
+
+/*ARGSUSED*/
+remrq(p) struct proc *p; { }
+
+swtch() { if (whichqs) whichqs = 0; }
+
+/*ARGSUSED*/
+fubyte(base) caddr_t base; { return (0); }
+#ifdef notdef
+/*ARGSUSED*/
+fuibyte(base) caddr_t base; { return (0); }
+#endif
+/*ARGSUSED*/
+subyte(base, i) caddr_t base; { return (0); }
+/*ARGSUSED*/
+suibyte(base, i) caddr_t base; { return (0); }
+/*ARGSUSED*/
+fuword(base) caddr_t base; { return (0); }
+/*ARGSUSED*/
+fuiword(base) caddr_t base; { return (0); }
+/*ARGSUSED*/
+suword(base, i) caddr_t base; { return (0); }
+/*ARGSUSED*/
+suiword(base, i) caddr_t base; { return (0); }
+
+/*ARGSUSED*/
+copyseg(udaddr, pf) caddr_t udaddr; unsigned pf; { }
+
+/*ARGSUSED*/
+clearseg(pf) unsigned pf; { }
+
+/*ARGSUSED*/
+addupc(pc, prof, ticks) unsigned pc; struct uprof *prof; int ticks; { }
+
+void MachEnableIntr() { }
+void setsoftnet() { }
+void clearsoftnet() { }
+void setsoftclock() { }
+void clearsoftclock() { }
+spl0() { return (0); }
+splsoftclock() { return (0); }
+splnet() { return (0); }
+splimp() { return (0); } /* XXX */
+splbio() { return (0); }
+spltty() { return (0); }
+splclock() { return (0); }
+splhigh() { return (0); }
+
+/*ARGSUSED*/
+splx(s) int s; { }
+
+#ifdef notdef
+/*ARGSUSED*/
+scanc(size, cp, table, mask)
+    unsigned size; char *cp, table[]; int mask;
+{ return (0); }
+
+/*ARGSUSED*/
+skpc(mask, size, cp) int mask; int size; char *cp; { return (0); }
+
+/*ARGSUSED*/
+locc(mask, size, cp) int mask; char *cp; unsigned size; { return (0); }
+#endif
+
+/*ARGSUSED*/
+_insque(p, q) caddr_t p, q; { }
+/*ARGSUSED*/
+_remque(p) caddr_t p; { }
+
+/*ARGSUSED*/
+ffs(v) long v; { return (0); }
+
+/*ARGSUSED*/
+strlen(str) char *str; { return (0); }
+
+#ifdef notdef
+imin(a, b) int a, b; { return (a < b ? a : b); }
+imax(a, b) int a, b; { return (a > b ? a : b); }
+unsigned min(a, b) u_int a, b; { return (a < b ? a : b); }
+unsigned max(a, b) u_int a, b; { return (a > b ? a : b); }
+#endif
+
+u_short ntohs(s) u_short s; { return ((u_short)s); }
+u_short htons(s) u_short s; { return ((u_short)s); }
+u_long ntohl(l) u_long l; { return ((u_long)l); }
+u_long htonl(l) u_long l; { return ((u_long)l); }
+
+void MachKernGenException() { }
+void MachUserGenException() { }
+void MachTLBModException() { }
+void MachTLBMissException() { }
+void MachEmptyWriteBuffer() { }
+/*ARGSUSED*/
+void MachTLBWriteIndexed(index, highEntry, lowEntry)
+       int index, highEntry, lowEntry; { }
+/*ARGSUSED*/
+void MachSetPID(pid) int pid; { }
+/*ARGSUSED*/
+void newptes(pte, v, size) struct pte *pte; u_int v; int size; { }
+void MachTLBFlush() { }
+/*ARGSUSED*/
+void MachTLBFlushPID(pid) int pid; { }
+/*ARGSUSED*/
+void MachTLBFlushAddr(virt) caddr_t virt; { }
+/*ARGSUSED*/
+void MachSwitchFPState(from, to) struct proc *from; struct user *to; { }
+/*ARGSUSED*/
+void MachGetCurFPState(p) struct proc *p; { }
+/*ARGSUSED*/
+void MachFPInterrupt(p) struct proc *p; { }
+/*ARGSUSED*/
+void MachFPInterrupt(statusReg, causeReg, pc)
+       unsigned statusReg, causeReg, pc; { }
+void MachConfigCache() { }
+void MachFlushCache() { }
+/*ARGSUSED*/
+void MachFlushICache(vaddr, len) caddr_t vaddr, int len; { }
diff --git a/usr/src/sys/pmax/pmax/autoconf.c b/usr/src/sys/pmax/pmax/autoconf.c
new file mode 100644 (file)
index 0000000..ea66ab2
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: autoconf.c 1.31 91/01/21$
+ *
+ *     @(#)autoconf.c  7.1 (Berkeley) %G%
+ */
+
+/*
+ * Setup the system to run on the current machine.
+ *
+ * Configure() is called at boot time.  Available
+ * devices are determined (from possibilities mentioned in ioconf.c),
+ * and the drivers are initialized.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "map.h"
+#include "buf.h"
+#include "dkstat.h"
+#include "conf.h"
+#include "dmap.h"
+#include "reboot.h"
+
+#include "../include/cpu.h"
+#include "../dev/device.h"
+
+/*
+ * The following several variables are related to
+ * the configuration process, and are used in initializing
+ * the machine.
+ */
+int    cold = 1;       /* if 1, still working on cold-start */
+int    dkn;            /* number of iostat dk numbers assigned so far */
+int    cpuspeed = 30;  /* approx # instr per usec. */
+
+/*
+ * Determine mass storage and memory configuration for a machine.
+ * Get cpu type, and then switch out to machine specific procedures
+ * which will probe adaptors to see what is out there.
+ */
+configure()
+{
+       register struct pmax_ctlr *cp;
+       register struct scsi_device *dp;
+       register struct driver *drp;
+
+       /* print what type of CPU and FPU we have */
+       switch (cpu.cpu.cp_imp) {
+       case MIPS_R2000:
+               printf("cpu0 (MIPS R2000 revision %d.%d)\n",
+                       cpu.cpu.cp_majrev, cpu.cpu.cp_minrev);
+               break;
+
+       default:
+               printf("cpu0 (implementation %d revision %d.%d)\n",
+                       cpu.cpu.cp_imp, cpu.cpu.cp_majrev, cpu.cpu.cp_minrev);
+       }
+       switch (fpu.cpu.cp_imp) {
+       case MIPS_R2010:
+               printf("fpu0 (MIPS R2010 revision %d.%d)\n",
+                       fpu.cpu.cp_majrev, fpu.cpu.cp_minrev);
+               break;
+
+       default:
+               printf("fpu0 (implementation %d revision %d.%d)\n",
+                       fpu.cpu.cp_imp, fpu.cpu.cp_majrev, fpu.cpu.cp_minrev);
+       }
+       printf("data cache size %dK inst cache size %dK\n",
+               machDataCacheSize >> 10, machInstCacheSize >> 10);
+
+       /* probe and initialize controllers */
+       for (cp = pmax_cinit; drp = cp->pmax_driver; cp++) {
+               if (!(*drp->d_init)(cp))
+                       continue;
+
+               cp->pmax_alive = 1;
+
+               /* probe and initialize devices connected to controller */
+               for (dp = scsi_dinit; drp = dp->sd_driver; dp++) {
+                       /* might want to get fancier later */
+                       if (dp->sd_cdriver != cp->pmax_driver ||
+                           dp->sd_ctlr != cp->pmax_unit)
+                               continue;       /* not connected */
+                       if (!(*drp->d_init)(dp))
+                               continue;
+                       dp->sd_alive = 1;
+                       /* if device is a disk, assign number for statistics */
+                       if (dp->sd_dk && dkn < DK_NDRIVE)
+                               dp->sd_dk = dkn++;
+                       else
+                               dp->sd_dk = -1;
+               }
+       }
+
+#if GENERIC
+       if ((boothowto & RB_ASKNAME) == 0)
+               setroot();
+       setconf();
+#else
+       setroot();
+#endif
+       swapconf();
+       cold = 0;
+}
+
+/*
+ * Configure swap space and related parameters.
+ */
+swapconf()
+{
+       register struct swdevt *swp;
+       register int nblks;
+
+       for (swp = swdevt; swp->sw_dev; swp++)
+               if (bdevsw[major(swp->sw_dev)].d_psize) {
+                       nblks =
+                         (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
+                       if (nblks != -1 &&
+                           (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+                               swp->sw_nblks = nblks;
+               }
+       dumpconf();
+}
+
+#define        DOSWAP                  /* Change swdevt and dumpdev too */
+u_long bootdev;                /* should be dev_t, but not until 32 bits */
+
+static char devname[][2] = {
+       'r','z',        /* 0 = rz */
+};
+
+#define        PARTITIONMASK   0x7
+#define        PARTITIONSHIFT  3
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * change rootdev to correspond to the load device.
+ */
+setroot()
+{
+       register struct scsi_device *dp;
+       int  majdev, mindev, unit, part, controller;
+       dev_t temp, orootdev;
+       struct swdevt *swp;
+
+       if (boothowto & RB_DFLTROOT ||
+           (bootdev & B_MAGICMASK) != B_DEVMAGIC)
+               return;
+       majdev = B_TYPE(bootdev);
+       if (majdev >= sizeof(devname) / sizeof(devname[0]))
+               return;
+       controller = B_CONTROLLER(bootdev);
+       part = B_PARTITION(bootdev);
+       unit = B_UNIT(bootdev);
+
+       for (dp = scsi_dinit; ; dp++) {
+               if (dp->sd_driver == 0)
+                       return;
+               if (dp->sd_alive && dp->sd_drive == unit &&
+                   dp->sd_ctlr == controller &&
+                   dp->sd_driver->d_name[0] == devname[majdev][0] &&
+                   dp->sd_driver->d_name[1] == devname[majdev][1]) {
+                       mindev = dp->sd_unit;
+                       break;
+               }
+       }
+       /*
+        * Form a new rootdev
+        */
+       mindev = (mindev << PARTITIONSHIFT) + part;
+       orootdev = rootdev;
+       rootdev = makedev(majdev, mindev);
+       /*
+        * If the original rootdev is the same as the one
+        * just calculated, don't need to adjust the swap configuration.
+        */
+       if (rootdev == orootdev)
+               return;
+
+       printf("Changing root device to %c%c%d%c\n",
+               devname[majdev][0], devname[majdev][1],
+               mindev >> PARTITIONSHIFT, part + 'a');
+
+#ifdef DOSWAP
+       mindev &= ~PARTITIONMASK;
+       for (swp = swdevt; swp->sw_dev; swp++) {
+               if (majdev == major(swp->sw_dev) &&
+                   mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
+                       temp = swdevt[0].sw_dev;
+                       swdevt[0].sw_dev = swp->sw_dev;
+                       swp->sw_dev = temp;
+                       break;
+               }
+       }
+       if (swp->sw_dev == 0)
+               return;
+
+       /*
+        * If dumpdev was the same as the old primary swap
+        * device, move it to the new primary swap device.
+        */
+       if (temp == dumpdev)
+               dumpdev = swdevt[0].sw_dev;
+#endif
+}
+
+/*
+ * Look at the string 'cp' and decode the boot device.
+ */
+void
+makebootdev(cp)
+       register char *cp;
+{
+       int  majdev, unit, part, ctrl;
+
+       for (majdev = 0; majdev < sizeof(devname)/sizeof(devname[0]); majdev++)
+               if (cp[0] == devname[majdev][0] &&
+                   cp[1] == devname[majdev][1] &&
+                   cp[2] == '(')
+                       goto fndmaj;
+defdev:
+       bootdev = B_DEVMAGIC;
+       return;
+
+fndmaj:
+       for (ctrl = 0, cp += 3; *cp >= '0' && *cp <= '9'; )
+               ctrl = ctrl * 10 + *cp++ - '0';
+       if (*cp == ',')
+               cp++;
+       for (unit = 0; *cp >= '0' && *cp <= '9'; )
+               unit = unit * 10 + *cp++ - '0';
+       if (*cp == ',')
+               cp++;
+       for (part = 0; *cp >= '0' && *cp <= '9'; )
+               part = part * 10 + *cp++ - '0';
+       if (*cp != ')')
+               goto defdev;
+       bootdev = (majdev << B_TYPESHIFT) |
+               (ctrl << B_CONTROLLERSHIFT) |
+               (unit << B_UNITSHIFT) |
+               (part << B_PARTITIONSHIFT);
+}
diff --git a/usr/src/sys/pmax/pmax/clock.c b/usr/src/sys/pmax/pmax/clock.c
new file mode 100644 (file)
index 0000000..c45944f
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: clock.c 1.18 91/01/21$
+ *
+ *     @(#)clock.c     7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "kernel.h"
+
+#include "../include/machConst.h"
+#include "clockreg.h"
+
+/*
+ * Machine-dependent clock routines.
+ *
+ * Startrtclock restarts the real-time clock, which provides
+ * hardclock interrupts to kern_clock.c.
+ *
+ * Inittodr initializes the time of day hardware which provides
+ * date functions.  Its primary function is to use some file
+ * system information in case the hardare clock lost state.
+ *
+ * Resettodr restores the time of day hardware after a time change.
+ */
+
+/*
+ * Start the real-time clock.
+ */
+startrtclock()
+{
+       register volatile struct chiptime *c;
+       extern int tickadj;
+
+       tick = 15625;           /* number of micro-seconds between interrupts */
+       hz = 1000000 / 15625;   /* about 64 */
+       tickadj = 240000 / (60000000 / 15625);
+       c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
+       c->rega = REGA_TIME_BASE | SELECTED_RATE;
+       c->regb = REGB_PER_INT_ENA | REGB_DATA_MODE | REGB_HOURS_FORMAT;
+}
+
+/*
+ * This code is defunct after 2099.
+ * Will Unix still be here then??
+ */
+static short dayyr[12] = {
+       0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.  Base provides the time to within six months,
+ * and the time of year clock (if any) provides the rest.
+ */
+inittodr(base)
+       time_t base;
+{
+       register volatile struct chiptime *c;
+       register int days, yr;
+       int sec, min, hour, day, mon, year;
+       long deltat, badbase = 0;
+       int s;
+
+       if (base < 5*SECYR) {
+               printf("WARNING: preposterous time in file system\n");
+               /* read the system clock anyway */
+               base = 6*SECYR + 186*SECDAY + SECDAY/2;
+               badbase = 1;
+       }
+
+       s = splclock();
+       c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
+       /* don't read clock registers while they are being updated */
+       while ((c->rega & REGA_UIP) == 1)
+               ;
+       sec = c->sec;
+       min = c->min;
+       hour = c->hour;
+       day = c->day;
+       mon = c->mon;
+       year = c->year + 19;
+       splx(s);
+       /* simple sanity checks */
+       if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
+           hour > 23 || min > 59 || sec > 59) {
+               printf("WARNING: preposterous clock chip time");
+               /*
+                * Believe the time in the file system for lack of
+                * anything better, resetting the TODR.
+                */
+               time.tv_sec = base;
+               if (!badbase)
+                       resettodr();
+               return (0);
+       }
+       days = 0;
+       for (yr = 70; yr < year; yr++)
+               days += LEAPYEAR(yr) ? 366 : 365;
+       days += dayyr[mon - 1] + day - 1;
+       if (LEAPYEAR(yr) && mon > 2)
+               days++;
+       /* now have days since Jan 1, 1970; the rest is easy... */
+       time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
+
+       if (!badbase) {
+               /*
+                * See if we gained/lost two or more days;
+                * if so, assume something is amiss.
+                */
+               deltat = time.tv_sec - base;
+               if (deltat < 0)
+                       deltat = -deltat;
+               if (deltat < 2 * SECDAY)
+                       return;
+               printf("WARNING: clock %s %d days",
+                   time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
+       }
+       printf(" -- CHECK AND RESET THE DATE!\n");
+}
+
+/*
+ * Reset the TODR based on the time value; used when the TODR
+ * has a preposterous value and also when the time is reset
+ * by the stime system call.  Also called when the TODR goes past
+ * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
+ * to wrap the TODR around.
+ */
+resettodr()
+{
+       register volatile struct chiptime *c;
+       register int t, t2, t3;
+
+       /* compute the year */
+       t2 = time.tv_sec / SECDAY;
+       t = 69;
+       while (t2 >= 0) {       /* whittle off years */
+               t3 = t2;
+               t++;
+               t2 -= LEAPYEAR(t) ? 366 : 365;
+       }
+       c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
+       c->regb |= REGB_SET_TIME;
+       c->year = t - 19;
+
+       /* t3 = month + day; separate */
+       t = LEAPYEAR(t);
+       for (t2 = 1; t2 < 12; t2++)
+               if (t3 < dayyr[t2] + (t && t2 > 1))
+                       break;
+
+       /* t2 is month */
+       c->mon = t2;
+       t3 = t3 - dayyr[t2 - 1] + 1;
+       if (t && t2 > 2)
+               t3--;
+       c->day = t3;
+
+       /* the rest is easy */
+       t = time.tv_sec % SECDAY;
+       c->hour = t / 3600;
+       t %= 3600;
+       c->min = t / 60;
+       c->sec = t % 60;
+       c->regb &= ~REGB_SET_TIME;
+}
diff --git a/usr/src/sys/pmax/pmax/clockreg.h b/usr/src/sys/pmax/pmax/clockreg.h
new file mode 100644 (file)
index 0000000..8a38b4e
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: clockreg.h 1.14 91/01/18$
+ *
+ *     @(#)clockreg.h  7.1 (Berkeley) %G%
+ */
+
+/*
+ * This file contains definitions for the MC 146818 real-time clock.
+ *
+ * For a detailed explanation of the chip, see the "PMAX Desktop
+ * Workstation Functional Specification, Revision 1.1" pages 62-66.
+ */
+#define        SECMIN  ((unsigned)60)                  /* seconds per minute */
+#define        SECHOUR ((unsigned)(60*SECMIN))         /* seconds per hour */
+#define        SECDAY  ((unsigned)(24*SECHOUR))        /* seconds per day */
+#define        SECYR   ((unsigned)(365*SECDAY))        /* seconds per common year */
+
+#define        YRREF           1970
+#define        LEAPYEAR(year)  (((year) % 4) == 0)
+
+/*
+ * Definitions for MC146818 real time clock
+ */
+struct chiptime {
+       u_char  sec;            /* current seconds */
+       char    dummy0[3];
+       u_char  alarm_sec;      /* alarm seconds */
+       char    dummy1[3];
+       u_char  min;            /* current minutes */
+       char    dummy2[3];
+       u_char  alarm_min;      /* alarm minutes */
+       char    dummy3[3];
+       u_char  hour;           /* current hours */
+       char    dummy4[3];
+       u_char  alarm_hour;     /* alarm hours */
+       char    dummy5[3];
+       u_char  dayw;           /* day of the week */
+       char    dummy6[3];
+       u_char  day;            /* day of the month */
+       char    dummy7[3];
+       u_char  mon;            /* month */
+       char    dummy8[3];
+       u_char  year;           /* year */
+       char    dummy9[3];
+       u_char  rega;           /* register a */
+       char    dummy10[3];
+       u_char  regb;           /* register b */
+       char    dummy11[3];
+       u_char  regc;           /* register c */
+       char    dummy12[3];
+       u_char  regd;           /* register d */
+       char    dummy13[3];
+       u_char  nvram[50*4];    /* battery backed-up ram */
+};
+
+/*
+ * Control register A fields.
+ */
+#define REGA_UIP               0x80
+#define REGA_TIME_DIV          0x70
+#define REGA_RATE_SELECT       0x0F
+
+/*
+ * Time base to use in the REGA_TIME_DIV field.
+ */
+#define REGA_TIME_BASE         0x20
+
+/*
+ * Set the interval at 15.625 ms.
+ */
+#define SELECTED_RATE          0xA
+
+/*
+ * Control register B fields.
+ */
+#define REGB_SET_TIME          0x80
+#define REGB_PER_INT_ENA       0x40
+#define REGB_UPDATE_INT_ENA    0x10
+#define REGB_DATA_MODE         0x04
+#define REGB_HOURS_FORMAT      0x02
+
+/*
+ * Control register C fields.
+ */
+#define REGC_INT_PENDING       0x80
+#define REGC_PER_INT_PENDING   0x40
+#define REGC_UPDATE_INT_PENDING        0x10
+
+/*
+ * Control register D fields.
+ */
+#define REGD_VALID_TIME                0x80
+
+/*
+ * The RTC registers can only be accessed one byte at a time.
+ * This routine is used to write words into the non-volatile storage.
+ */
+
+#define BYTECOPY(a,b,num) { \
+       int i; \
+       for (i = 0; i < (num); i++) \
+               ((char *) (b))[i] = ((char *) (a))[i]; \
+}
diff --git a/usr/src/sys/pmax/pmax/conf.c b/usr/src/sys/pmax/pmax/conf.c
new file mode 100644 (file)
index 0000000..0ba53e3
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)conf.c      7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "conf.h"
+
+int    rawread         __P((dev_t, struct uio *, int));
+int    rawwrite        __P((dev_t, struct uio *, int));
+int    swstrategy      __P((struct buf *));
+int    ttselect        __P((dev_t, int, struct proc *));
+
+#define        dev_type_open(n)        int n __P((dev_t, int, int, struct proc *))
+#define        dev_type_close(n)       int n __P((dev_t, int, int, struct proc *))
+#define        dev_type_strategy(n)    int n __P((struct buf *))
+#define        dev_type_ioctl(n) \
+       int n __P((dev_t, int, caddr_t, int, struct proc *))
+
+/* bdevsw-specific types */
+#define        dev_type_dump(n)        int n __P((dev_t))
+#define        dev_type_size(n)        int n __P((dev_t))
+
+#define        dev_decl(n,t)   __CONCAT(dev_type_,t)(__CONCAT(n,t))
+#define        dev_init(c,n,t) \
+       (c > 0 ? __CONCAT(n,t) : (__CONCAT(dev_type_,t)((*))) enxio)
+
+/* bdevsw-specific initializations */
+#define        dev_size_init(c,n)      (c > 0 ? __CONCAT(n,size) : 0)
+
+#define        bdev_decl(n) \
+       dev_decl(n,open); dev_decl(n,close); dev_decl(n,strategy); \
+       dev_decl(n,ioctl); dev_decl(n,dump); dev_decl(n,size)
+
+#define        bdev_disk_init(c,n) { \
+       dev_init(c,n,open), (dev_type_close((*))) nullop, \
+       dev_init(c,n,strategy), dev_init(c,n,ioctl), \
+       dev_init(c,n,dump), dev_size_init(c,n), 0 }
+
+#define        bdev_tape_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), \
+       dev_init(c,n,strategy), dev_init(c,n,ioctl), \
+       dev_init(c,n,dump), 0, B_TAPE }
+
+#define        bdev_swap_init() { \
+       (dev_type_open((*))) enodev, (dev_type_close((*))) enodev, \
+       swstrategy, (dev_type_ioctl((*))) enodev, \
+       (dev_type_dump((*))) enodev, 0, 0 }
+
+#define        bdev_notdef()   bdev_tape_init(0,no)
+bdev_decl(no); /* dummy declarations */
+
+#include "rz.h"
+#include "vn.h"
+
+bdev_decl(rz);
+bdev_decl(vn);
+
+struct bdevsw  bdevsw[] =
+{
+       bdev_disk_init(NRZ,rz), /* 0: SCSI disk */
+       bdev_swap_init(),       /* 1: swap pseudo-device */
+       bdev_disk_init(NVN,vn), /* 2: vnode disk driver (swap to files) */
+};
+
+int    nblkdev = sizeof (bdevsw) / sizeof (bdevsw[0]);
+
+/* cdevsw-specific types */
+#define        dev_type_read(n)        int n __P((dev_t, struct uio *, int))
+#define        dev_type_write(n)       int n __P((dev_t, struct uio *, int))
+#define        dev_type_stop(n)        int n __P((struct tty *, int))
+#define        dev_type_reset(n)       int n __P((int))
+#define        dev_type_select(n)      int n __P((dev_t, int, struct proc *))
+#define        dev_type_map(n)         int n __P(())
+
+#define        cdev_decl(n) \
+       dev_decl(n,open); dev_decl(n,close); dev_decl(n,read); \
+       dev_decl(n,write); dev_decl(n,ioctl); dev_decl(n,stop); \
+       dev_decl(n,reset); dev_decl(n,select); dev_decl(n,map); \
+       dev_decl(n,strategy); extern struct tty __CONCAT(n,_tty)[]
+
+#define        dev_tty_init(c,n)       (c > 0 ? __CONCAT(n,_tty) : 0)
+
+/* open, read, write, ioctl, strategy */
+#define        cdev_disk_init(c,n) { \
+       dev_init(c,n,open), (dev_type_close((*))) nullop, dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) nullop, 0, seltrue, (dev_type_map((*))) enodev, \
+       dev_init(c,n,strategy) }
+
+/* open, close, read, write, ioctl, strategy */
+#define        cdev_tape_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) nullop, 0, seltrue, (dev_type_map((*))) enodev, \
+       dev_init(c,n,strategy) }
+
+/* open, close, read, write, ioctl, stop, tty */
+#define        cdev_tty_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), dev_init(c,n,stop), \
+       (dev_type_reset((*))) nullop, dev_tty_init(c,n), ttselect, \
+       (dev_type_map((*))) enodev, 0 }
+
+#define        cdev_notdef() { \
+       (dev_type_open((*))) enodev, (dev_type_close((*))) enodev, \
+       (dev_type_read((*))) enodev, (dev_type_write((*))) enodev, \
+       (dev_type_ioctl((*))) enodev, (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) nullop, 0, seltrue, \
+       (dev_type_map((*))) enodev, 0 }
+
+cdev_decl(no);                 /* dummy declarations */
+
+cdev_decl(dc);
+/* open, close, read, write, ioctl, select -- XXX should be a tty */
+#define        cdev_dc_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
+       (dev_type_reset((*))) nullop, 0, ttselect, \
+       (dev_type_map((*))) enodev, 0 }
+
+cdev_decl(ctty);
+/* open, read, write, ioctl, select -- XXX should be a tty */
+#define        cdev_ctty_init(c,n) { \
+       dev_init(c,n,open), (dev_type_close((*))) nullop, dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
+       (dev_type_reset((*))) nullop, 0, dev_init(c,n,select), \
+       (dev_type_map((*))) enodev, 0 }
+
+dev_type_read(mmrw);
+/* read/write */
+#define        cdev_mm_init(c,n) { \
+       (dev_type_open((*))) nullop, (dev_type_close((*))) nullop, mmrw, \
+       mmrw, (dev_type_ioctl((*))) enodev, (dev_type_stop((*))) nullop, \
+       (dev_type_reset((*))) nullop, 0, seltrue, (dev_type_map((*))) enodev, 0 }
+
+/* read, write, strategy */
+#define        cdev_swap_init(c,n) { \
+       (dev_type_open((*))) nullop, (dev_type_close((*))) nullop, rawread, \
+       rawwrite, (dev_type_ioctl((*))) enodev, (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) nullop, 0, (dev_type_select((*))) enodev, \
+       (dev_type_map((*))) enodev, dev_init(c,n,strategy) }
+
+#include "pty.h"
+#define        pts_tty         pt_tty
+#define        ptsioctl        ptyioctl
+cdev_decl(pts);
+#define        ptc_tty         pt_tty
+#define        ptcioctl        ptyioctl
+cdev_decl(ptc);
+
+/* open, close, read, write, ioctl, tty, select */
+#define        cdev_ptc_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
+       (dev_type_reset((*))) nullop, dev_tty_init(c,n), dev_init(c,n,select), \
+       (dev_type_map((*))) enodev, 0 }
+
+cdev_decl(log);
+/* open, close, read, ioctl, select -- XXX should be a generic device */
+#define        cdev_log_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+       (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+       (dev_type_stop((*))) enodev, (dev_type_reset((*))) nullop, 0, \
+       dev_init(c,n,select), (dev_type_map((*))) enodev, 0 }
+
+dev_type_open(fdopen);
+/* open */
+#define        cdev_fd_init(c,n) { \
+       dev_init(c,n,open), (dev_type_close((*))) enodev, \
+       (dev_type_read((*))) enodev, (dev_type_write((*))) enodev, \
+       (dev_type_ioctl((*))) enodev, (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) enodev, 0, (dev_type_select((*))) enodev, \
+       (dev_type_map((*))) enodev, 0 }
+
+#include "pm.h"
+cdev_decl(pm);
+#define        cdev_pm_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), \
+       (dev_type_read((*))) enodev, (dev_type_write((*))) enodev, \
+       dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) enodev, 0, dev_init(c,n,select), \
+       (dev_type_map((*))) enodev, 0 }
+
+cdev_decl(rz);
+
+#include "tz.h"
+cdev_decl(tz);
+
+cdev_decl(vn);
+/* open, read, write, ioctl -- XXX should be a disk */
+#define        cdev_vn_init(c,n) { \
+       dev_init(c,n,open), (dev_type_close((*))) nullop, dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) nullop, 0, seltrue, (dev_type_map((*))) enodev, \
+       0 }
+
+#include "bpfilter.h"
+cdev_decl(bpf);
+/* open, close, read, write, ioctl, select -- XXX should be generic device */
+#define        cdev_bpf_init(c,n) { \
+       dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+       dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) enodev, \
+       (dev_type_reset((*))) enodev, 0, dev_init(c,n,select), \
+       (dev_type_map((*))) enodev, 0 }
+
+struct cdevsw  cdevsw[] =
+{
+       cdev_dc_init(1,dc),             /* 0: virtual console */
+       cdev_ctty_init(1,ctty),         /* 1: controlling terminal */
+       cdev_mm_init(1,mm),             /* 2: /dev/{null,mem,kmem,...} */
+       cdev_swap_init(1,sw),           /* 3: /dev/drum (swap pseudo-device) */
+       cdev_tty_init(NPTY,pts),        /* 4: pseudo-tty slave */
+       cdev_ptc_init(NPTY,ptc),        /* 5: pseudo-tty master */
+       cdev_log_init(1,log),           /* 6: /dev/klog */
+       cdev_fd_init(1,fd),             /* 7: file descriptor pseudo-dev */
+       cdev_pm_init(NPM,pm),           /* 8: frame buffer */
+       cdev_disk_init(NRZ,rz),         /* 9: SCSI disk */
+       cdev_tape_init(NTZ,tz),         /* 10: SCSI tape */
+       cdev_vn_init(NVN,vn),           /* 11: vnode disk */
+       cdev_bpf_init(NBPFILTER,bpf),   /* 12: berkeley packet filter */
+};
+
+int    nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]);
+
+int    mem_no = 2;     /* major device number of memory special file */
+
+/*
+ * Swapdev is a fake device implemented
+ * in sw.c used only internally to get to swstrategy.
+ * It cannot be provided to the users, because the
+ * swstrategy routine munches the b_dev and b_blkno entries
+ * before calling the appropriate driver.  This would horribly
+ * confuse, e.g. the hashing routines. Instead, /dev/drum is
+ * provided as a character (raw) device.
+ */
+dev_t  swapdev = makedev(1, 0);
diff --git a/usr/src/sys/pmax/pmax/cons.c b/usr/src/sys/pmax/pmax/cons.c
new file mode 100644 (file)
index 0000000..05ac90f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: cons.c 1.1 90/07/09$
+ *
+ *     @(#)cons.c      7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "buf.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "file.h"
+#include "conf.h"
+
+#include "../include/machMon.h"
+
+/*
+ * Console output may be redirected to another tty
+ * (e.g. a window); if so, constty will point to the current
+ * virtual console.
+ */
+struct tty *constty;           /* virtual console output device */
+
+/*
+ * Get character from console.
+ */
+cngetc()
+{
+       int (*f)() = (int (*)())MACH_MON_GETCHAR;
+
+       return (*f)();
+}
+
+#include "pm.h"
+
+/*
+ * Print a character on console.
+ */
+cnputc(c)
+       register int c;
+{
+#if NPM > 0
+       pmPutc(c);
+#else
+       int s;
+       void (*f)() = (void (*)())MACH_MON_PUTCHAR;
+
+       s = splhigh();
+       (*f)(c);
+       splx(s);
+#endif
+}
diff --git a/usr/src/sys/pmax/pmax/fp.s b/usr/src/sys/pmax/pmax/fp.s
new file mode 100644 (file)
index 0000000..1b66c4a
--- /dev/null
@@ -0,0 +1,3142 @@
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)fp.s        7.1 (Berkeley) %G%
+ */
+
+/*
+ * Standard header stuff.
+ */
+
+#include "machine/regdef.h"
+#include "machine/machAsmDefs.h"
+#include "machine/machConst.h"
+#include "assym.h"
+
+#define SEXP_INF       0xff
+#define DEXP_INF       0x7ff
+#define SEXP_BIAS      127
+#define DEXP_BIAS      1023
+#define SEXP_MIN       -126
+#define DEXP_MIN       -1022
+#define SEXP_MAX       127
+#define DEXP_MAX       1023
+#define WEXP_MAX       30              /* maximum unbiased exponent for int */
+#define WEXP_MIN       -1              /* minimum unbiased exponent for int */
+#define SFRAC_BITS     23
+#define DFRAC_BITS     52
+#define SIMPL_ONE      0x00800000
+#define DIMPL_ONE      0x00100000
+#define SLEAD_ZEROS    31 - 23
+#define DLEAD_ZEROS    31 - 20
+#define STICKYBIT      1
+#define GUARDBIT       0x80000000
+#define SSIGNAL_NAN    0x00400000
+#define DSIGNAL_NAN    0x00040000
+#define SQUIET_NAN     0x003fffff
+#define DQUIET_NAN0    0x0007ffff
+#define DQUIET_NAN1    0xffffffff
+#define INT_MIN                0x80000000
+#define INT_MAX                0x7fffffff
+
+#define COND_UNORDERED 0x1
+#define COND_EQUAL     0x2
+#define COND_LESS      0x4
+#define COND_SIGNAL    0x8
+
+/*----------------------------------------------------------------------------
+ *
+ * MachEmulateFP --
+ *
+ *     Emulate unimplemented floating point operations.
+ *     This routine should only be called by MachFPInterrupt().
+ *
+ *     MachEmulateFP(instr)
+ *             unsigned instr;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Floating point registers are modified according to instruction.
+ *
+ *----------------------------------------------------------------------------
+ */
+NON_LEAF(MachEmulateFP, STAND_FRAME_SIZE, ra)
+       subu    sp, sp, STAND_FRAME_SIZE
+       sw      ra, STAND_RA_OFFSET(sp)
+/*
+ * Decode the FMT field (bits 24-21) and FUNCTION field (bits 5-0).
+ */
+       srl     v0, a0, 21 - 2                  # get FMT field
+       and     v0, v0, 0xF << 2                # mask FMT field
+       and     v1, a0, 0x3F                    # mask FUNC field
+       sll     v1, v1, 5                       # align for table lookup
+       bgt     v0, 4 << 2, ill                 # illegal format
+
+       or      v1, v1, v0
+       cfc1    a1, MACH_FPC_CSR                # get exception register
+       lw      a3, func_fmt_tbl(v1)            # switch on FUNC & FMT
+       and     a1, a1, ~MACH_FPC_EXCEPTION_UNIMPL      # clear exception
+       ctc1    a1, MACH_FPC_CSR
+       j       a3
+
+       .rdata
+func_fmt_tbl:
+       .word   add_s           # 0
+       .word   add_d           # 0
+       .word   ill             # 0
+       .word   ill             # 0
+       .word   ill             # 0
+       .word   ill             # 0
+       .word   ill             # 0
+       .word   ill             # 0
+       .word   sub_s           # 1
+       .word   sub_d           # 1
+       .word   ill             # 1
+       .word   ill             # 1
+       .word   ill             # 1
+       .word   ill             # 1
+       .word   ill             # 1
+       .word   ill             # 1
+       .word   mul_s           # 2
+       .word   mul_d           # 2
+       .word   ill             # 2
+       .word   ill             # 2
+       .word   ill             # 2
+       .word   ill             # 2
+       .word   ill             # 2
+       .word   ill             # 2
+       .word   div_s           # 3
+       .word   div_d           # 3
+       .word   ill             # 3
+       .word   ill             # 3
+       .word   ill             # 3
+       .word   ill             # 3
+       .word   ill             # 3
+       .word   ill             # 3
+       .word   ill             # 4
+       .word   ill             # 4
+       .word   ill             # 4
+       .word   ill             # 4
+       .word   ill             # 4
+       .word   ill             # 4
+       .word   ill             # 4
+       .word   ill             # 4
+       .word   abs_s           # 5
+       .word   abs_d           # 5
+       .word   ill             # 5
+       .word   ill             # 5
+       .word   ill             # 5
+       .word   ill             # 5
+       .word   ill             # 5
+       .word   ill             # 5
+       .word   mov_s           # 6
+       .word   mov_d           # 6
+       .word   ill             # 6
+       .word   ill             # 6
+       .word   ill             # 6
+       .word   ill             # 6
+       .word   ill             # 6
+       .word   ill             # 6
+       .word   neg_s           # 7
+       .word   neg_d           # 7
+       .word   ill             # 7
+       .word   ill             # 7
+       .word   ill             # 7
+       .word   ill             # 7
+       .word   ill             # 7
+       .word   ill             # 7
+       .word   ill             # 8
+       .word   ill             # 8
+       .word   ill             # 8
+       .word   ill             # 8
+       .word   ill             # 8
+       .word   ill             # 8
+       .word   ill             # 8
+       .word   ill             # 8
+       .word   ill             # 9
+       .word   ill             # 9
+       .word   ill             # 9
+       .word   ill             # 9
+       .word   ill             # 9
+       .word   ill             # 9
+       .word   ill             # 9
+       .word   ill             # 9
+       .word   ill             # 10
+       .word   ill             # 10
+       .word   ill             # 10
+       .word   ill             # 10
+       .word   ill             # 10
+       .word   ill             # 10
+       .word   ill             # 10
+       .word   ill             # 10
+       .word   ill             # 11
+       .word   ill             # 11
+       .word   ill             # 11
+       .word   ill             # 11
+       .word   ill             # 11
+       .word   ill             # 11
+       .word   ill             # 11
+       .word   ill             # 11
+       .word   ill             # 12
+       .word   ill             # 12
+       .word   ill             # 12
+       .word   ill             # 12
+       .word   ill             # 12
+       .word   ill             # 12
+       .word   ill             # 12
+       .word   ill             # 12
+       .word   ill             # 13
+       .word   ill             # 13
+       .word   ill             # 13
+       .word   ill             # 13
+       .word   ill             # 13
+       .word   ill             # 13
+       .word   ill             # 13
+       .word   ill             # 13
+       .word   ill             # 14
+       .word   ill             # 14
+       .word   ill             # 14
+       .word   ill             # 14
+       .word   ill             # 14
+       .word   ill             # 14
+       .word   ill             # 14
+       .word   ill             # 14
+       .word   ill             # 15
+       .word   ill             # 15
+       .word   ill             # 15
+       .word   ill             # 15
+       .word   ill             # 15
+       .word   ill             # 15
+       .word   ill             # 15
+       .word   ill             # 15
+       .word   ill             # 16
+       .word   ill             # 16
+       .word   ill             # 16
+       .word   ill             # 16
+       .word   ill             # 16
+       .word   ill             # 16
+       .word   ill             # 16
+       .word   ill             # 16
+       .word   ill             # 17
+       .word   ill             # 17
+       .word   ill             # 17
+       .word   ill             # 17
+       .word   ill             # 17
+       .word   ill             # 17
+       .word   ill             # 17
+       .word   ill             # 17
+       .word   ill             # 18
+       .word   ill             # 18
+       .word   ill             # 18
+       .word   ill             # 18
+       .word   ill             # 18
+       .word   ill             # 18
+       .word   ill             # 18
+       .word   ill             # 18
+       .word   ill             # 19
+       .word   ill             # 19
+       .word   ill             # 19
+       .word   ill             # 19
+       .word   ill             # 19
+       .word   ill             # 19
+       .word   ill             # 19
+       .word   ill             # 19
+       .word   ill             # 20
+       .word   ill             # 20
+       .word   ill             # 20
+       .word   ill             # 20
+       .word   ill             # 20
+       .word   ill             # 20
+       .word   ill             # 20
+       .word   ill             # 20
+       .word   ill             # 21
+       .word   ill             # 21
+       .word   ill             # 21
+       .word   ill             # 21
+       .word   ill             # 21
+       .word   ill             # 21
+       .word   ill             # 21
+       .word   ill             # 21
+       .word   ill             # 22
+       .word   ill             # 22
+       .word   ill             # 22
+       .word   ill             # 22
+       .word   ill             # 22
+       .word   ill             # 22
+       .word   ill             # 22
+       .word   ill             # 22
+       .word   ill             # 23
+       .word   ill             # 23
+       .word   ill             # 23
+       .word   ill             # 23
+       .word   ill             # 23
+       .word   ill             # 23
+       .word   ill             # 23
+       .word   ill             # 23
+       .word   ill             # 24
+       .word   ill             # 24
+       .word   ill             # 24
+       .word   ill             # 24
+       .word   ill             # 24
+       .word   ill             # 24
+       .word   ill             # 24
+       .word   ill             # 24
+       .word   ill             # 25
+       .word   ill             # 25
+       .word   ill             # 25
+       .word   ill             # 25
+       .word   ill             # 25
+       .word   ill             # 25
+       .word   ill             # 25
+       .word   ill             # 25
+       .word   ill             # 26
+       .word   ill             # 26
+       .word   ill             # 26
+       .word   ill             # 26
+       .word   ill             # 26
+       .word   ill             # 26
+       .word   ill             # 26
+       .word   ill             # 26
+       .word   ill             # 27
+       .word   ill             # 27
+       .word   ill             # 27
+       .word   ill             # 27
+       .word   ill             # 27
+       .word   ill             # 27
+       .word   ill             # 27
+       .word   ill             # 27
+       .word   ill             # 28
+       .word   ill             # 28
+       .word   ill             # 28
+       .word   ill             # 28
+       .word   ill             # 28
+       .word   ill             # 28
+       .word   ill             # 28
+       .word   ill             # 28
+       .word   ill             # 29
+       .word   ill             # 29
+       .word   ill             # 29
+       .word   ill             # 29
+       .word   ill             # 29
+       .word   ill             # 29
+       .word   ill             # 29
+       .word   ill             # 29
+       .word   ill             # 30
+       .word   ill             # 30
+       .word   ill             # 30
+       .word   ill             # 30
+       .word   ill             # 30
+       .word   ill             # 30
+       .word   ill             # 30
+       .word   ill             # 30
+       .word   ill             # 31
+       .word   ill             # 31
+       .word   ill             # 31
+       .word   ill             # 31
+       .word   ill             # 31
+       .word   ill             # 31
+       .word   ill             # 31
+       .word   ill             # 31
+       .word   ill             # 32
+       .word   cvt_s_d         # 32
+       .word   ill             # 32
+       .word   ill             # 32
+       .word   cvt_s_w         # 32
+       .word   ill             # 32
+       .word   ill             # 32
+       .word   ill             # 32
+       .word   cvt_d_s         # 33
+       .word   ill             # 33
+       .word   ill             # 33
+       .word   ill             # 33
+       .word   cvt_d_w         # 33
+       .word   ill             # 33
+       .word   ill             # 33
+       .word   ill             # 33
+       .word   ill             # 34
+       .word   ill             # 34
+       .word   ill             # 34
+       .word   ill             # 34
+       .word   ill             # 34
+       .word   ill             # 34
+       .word   ill             # 34
+       .word   ill             # 34
+       .word   ill             # 35
+       .word   ill             # 35
+       .word   ill             # 35
+       .word   ill             # 35
+       .word   ill             # 35
+       .word   ill             # 35
+       .word   ill             # 35
+       .word   ill             # 35
+       .word   cvt_w_s         # 36
+       .word   cvt_w_d         # 36
+       .word   ill             # 36
+       .word   ill             # 36
+       .word   ill             # 36
+       .word   ill             # 36
+       .word   ill             # 36
+       .word   ill             # 36
+       .word   ill             # 37
+       .word   ill             # 37
+       .word   ill             # 37
+       .word   ill             # 37
+       .word   ill             # 37
+       .word   ill             # 37
+       .word   ill             # 37
+       .word   ill             # 37
+       .word   ill             # 38
+       .word   ill             # 38
+       .word   ill             # 38
+       .word   ill             # 38
+       .word   ill             # 38
+       .word   ill             # 38
+       .word   ill             # 38
+       .word   ill             # 38
+       .word   ill             # 39
+       .word   ill             # 39
+       .word   ill             # 39
+       .word   ill             # 39
+       .word   ill             # 39
+       .word   ill             # 39
+       .word   ill             # 39
+       .word   ill             # 39
+       .word   ill             # 40
+       .word   ill             # 40
+       .word   ill             # 40
+       .word   ill             # 40
+       .word   ill             # 40
+       .word   ill             # 40
+       .word   ill             # 40
+       .word   ill             # 40
+       .word   ill             # 41
+       .word   ill             # 41
+       .word   ill             # 41
+       .word   ill             # 41
+       .word   ill             # 41
+       .word   ill             # 41
+       .word   ill             # 41
+       .word   ill             # 41
+       .word   ill             # 42
+       .word   ill             # 42
+       .word   ill             # 42
+       .word   ill             # 42
+       .word   ill             # 42
+       .word   ill             # 42
+       .word   ill             # 42
+       .word   ill             # 42
+       .word   ill             # 43
+       .word   ill             # 43
+       .word   ill             # 43
+       .word   ill             # 43
+       .word   ill             # 43
+       .word   ill             # 43
+       .word   ill             # 43
+       .word   ill             # 43
+       .word   ill             # 44
+       .word   ill             # 44
+       .word   ill             # 44
+       .word   ill             # 44
+       .word   ill             # 44
+       .word   ill             # 44
+       .word   ill             # 44
+       .word   ill             # 44
+       .word   ill             # 45
+       .word   ill             # 45
+       .word   ill             # 45
+       .word   ill             # 45
+       .word   ill             # 45
+       .word   ill             # 45
+       .word   ill             # 45
+       .word   ill             # 45
+       .word   ill             # 46
+       .word   ill             # 46
+       .word   ill             # 46
+       .word   ill             # 46
+       .word   ill             # 46
+       .word   ill             # 46
+       .word   ill             # 46
+       .word   ill             # 46
+       .word   ill             # 47
+       .word   ill             # 47
+       .word   ill             # 47
+       .word   ill             # 47
+       .word   ill             # 47
+       .word   ill             # 47
+       .word   ill             # 47
+       .word   ill             # 47
+       .word   cmp_s           # 48
+       .word   cmp_d           # 48
+       .word   ill             # 48
+       .word   ill             # 48
+       .word   ill             # 48
+       .word   ill             # 48
+       .word   ill             # 48
+       .word   ill             # 48
+       .word   cmp_s           # 49
+       .word   cmp_d           # 49
+       .word   ill             # 49
+       .word   ill             # 49
+       .word   ill             # 49
+       .word   ill             # 49
+       .word   ill             # 49
+       .word   ill             # 49
+       .word   cmp_s           # 50
+       .word   cmp_d           # 50
+       .word   ill             # 50
+       .word   ill             # 50
+       .word   ill             # 50
+       .word   ill             # 50
+       .word   ill             # 50
+       .word   ill             # 50
+       .word   cmp_s           # 51
+       .word   cmp_d           # 51
+       .word   ill             # 51
+       .word   ill             # 51
+       .word   ill             # 51
+       .word   ill             # 51
+       .word   ill             # 51
+       .word   ill             # 51
+       .word   cmp_s           # 52
+       .word   cmp_d           # 52
+       .word   ill             # 52
+       .word   ill             # 52
+       .word   ill             # 52
+       .word   ill             # 52
+       .word   ill             # 52
+       .word   ill             # 52
+       .word   cmp_s           # 53
+       .word   cmp_d           # 53
+       .word   ill             # 53
+       .word   ill             # 53
+       .word   ill             # 53
+       .word   ill             # 53
+       .word   ill             # 53
+       .word   ill             # 53
+       .word   cmp_s           # 54
+       .word   cmp_d           # 54
+       .word   ill             # 54
+       .word   ill             # 54
+       .word   ill             # 54
+       .word   ill             # 54
+       .word   ill             # 54
+       .word   ill             # 54
+       .word   cmp_s           # 55
+       .word   cmp_d           # 55
+       .word   ill             # 55
+       .word   ill             # 55
+       .word   ill             # 55
+       .word   ill             # 55
+       .word   ill             # 55
+       .word   ill             # 55
+       .word   cmp_s           # 56
+       .word   cmp_d           # 56
+       .word   ill             # 56
+       .word   ill             # 56
+       .word   ill             # 56
+       .word   ill             # 56
+       .word   ill             # 56
+       .word   ill             # 56
+       .word   cmp_s           # 57
+       .word   cmp_d           # 57
+       .word   ill             # 57
+       .word   ill             # 57
+       .word   ill             # 57
+       .word   ill             # 57
+       .word   ill             # 57
+       .word   ill             # 57
+       .word   cmp_s           # 58
+       .word   cmp_d           # 58
+       .word   ill             # 58
+       .word   ill             # 58
+       .word   ill             # 58
+       .word   ill             # 58
+       .word   ill             # 58
+       .word   ill             # 58
+       .word   cmp_s           # 59
+       .word   cmp_d           # 59
+       .word   ill             # 59
+       .word   ill             # 59
+       .word   ill             # 59
+       .word   ill             # 59
+       .word   ill             # 59
+       .word   ill             # 59
+       .word   cmp_s           # 60
+       .word   cmp_d           # 60
+       .word   ill             # 60
+       .word   ill             # 60
+       .word   ill             # 60
+       .word   ill             # 60
+       .word   ill             # 60
+       .word   ill             # 60
+       .word   cmp_s           # 61
+       .word   cmp_d           # 61
+       .word   ill             # 61
+       .word   ill             # 61
+       .word   ill             # 61
+       .word   ill             # 61
+       .word   ill             # 61
+       .word   ill             # 61
+       .word   cmp_s           # 62
+       .word   cmp_d           # 62
+       .word   ill             # 62
+       .word   ill             # 62
+       .word   ill             # 62
+       .word   ill             # 62
+       .word   ill             # 62
+       .word   ill             # 62
+       .word   cmp_s           # 63
+       .word   cmp_d           # 63
+       .word   ill             # 63
+       .word   ill             # 63
+       .word   ill             # 63
+       .word   ill             # 63
+       .word   ill             # 63
+       .word   ill             # 63
+       .text
+
+/*
+ * Single precision subtract.
+ */
+sub_s:
+       jal     get_fs_sgl
+       jal     get_ft_sgl
+       xor     t4, t4, 1                       # negate FT sign bit
+       b       add_sub_s
+/*
+ * Single precision add.
+ */
+add_s:
+       jal     get_fs_sgl
+       jal     get_ft_sgl
+add_sub_s:
+       bne     t1, SEXP_INF, 1f                # is FS an infinity?
+       bne     t5, SEXP_INF, result_fs_s       # if FT is not inf, result=FS
+       bne     t0, t4, invalid_s               # both infinities same sign?
+       b       result_fs_s                     # result is in FS
+1:
+       beq     t5, SEXP_INF, result_ft_s       # if FT is inf, result=FT
+       bne     t1, zero, 4f                    # is FS a denormalized num?
+       beq     t2, zero, 3f                    # is FS zero?
+       bne     t5, zero, 2f                    # is FT a denormalized num?
+       beq     t6, zero, result_fs_s           # FT is zero, result=FS
+       jal     renorm_fs_s
+       jal     renorm_ft_s
+       b       5f
+2:
+       jal     renorm_fs_s
+       subu    t5, t5, SEXP_BIAS               # unbias FT exponent
+       or      t6, t6, SIMPL_ONE               # set implied one bit
+       b       5f
+3:
+       bne     t5, zero, result_ft_s           # if FT != 0, result=FT
+       bne     t6, zero, result_ft_s
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       bne     v0, MACH_FPC_ROUND_RM, 1f       # round to -infinity?
+       or      t0, t0, t4                      # compute result sign
+       b       result_fs_s
+1:
+       and     t0, t0, t4                      # compute result sign
+       b       result_fs_s
+4:
+       bne     t5, zero, 2f                    # is FT a denormalized num?
+       beq     t6, zero, result_fs_s           # FT is zero, result=FS
+       subu    t1, t1, SEXP_BIAS               # unbias FS exponent
+       or      t2, t2, SIMPL_ONE               # set implied one bit
+       jal     renorm_ft_s
+       b       5f
+2:
+       subu    t1, t1, SEXP_BIAS               # unbias FS exponent
+       or      t2, t2, SIMPL_ONE               # set implied one bit
+       subu    t5, t5, SEXP_BIAS               # unbias FT exponent
+       or      t6, t6, SIMPL_ONE               # set implied one bit
+/*
+ * Perform the addition.
+ */
+5:
+       move    t8, zero                        # no shifted bits (sticky reg)
+       beq     t1, t5, 4f                      # no shift needed
+       subu    v0, t1, t5                      # v0 = difference of exponents
+       move    v1, v0                          # v1 = abs(difference)
+       bge     v0, zero, 1f
+       negu    v1
+1:
+       ble     v1, SFRAC_BITS+2, 2f            # is difference too great?
+       li      t8, STICKYBIT                   # set the sticky bit
+       bge     v0, zero, 1f                    # check which exp is larger
+       move    t1, t5                          # result exp is FT's
+       move    t2, zero                        # FS's fraction shifted is zero
+       b       4f
+1:
+       move    t6, zero                        # FT's fraction shifted is zero
+       b       4f
+2:
+       li      t9, 32                          # compute 32 - abs(exp diff)
+       subu    t9, t9, v1
+       bgt     v0, zero, 3f                    # if FS > FT, shift FT's frac
+       move    t1, t5                          # FT > FS, result exp is FT's
+       sll     t8, t2, t9                      # save bits shifted out
+       srl     t2, t2, v1                      # shift FS's fraction
+       b       4f
+3:
+       sll     t8, t6, t9                      # save bits shifted out
+       srl     t6, t6, v1                      # shift FT's fraction
+4:
+       bne     t0, t4, 1f                      # if signs differ, subtract
+       addu    t2, t2, t6                      # add fractions
+       b       norm_s
+1:
+       blt     t2, t6, 3f                      # subtract larger from smaller
+       bne     t2, t6, 2f                      # if same, result=0
+       move    t1, zero                        # result=0
+       move    t2, zero
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       bne     v0, MACH_FPC_ROUND_RM, 1f       # round to -infinity?
+       or      t0, t0, t4                      # compute result sign
+       b       result_fs_s
+1:
+       and     t0, t0, t4                      # compute result sign
+       b       result_fs_s
+2:
+       sltu    t9, zero, t8                    # compute t2:zero - t6:t8
+       subu    t8, zero, t8
+       subu    t2, t2, t6                      # subtract fractions
+       subu    t2, t2, t9                      # subtract barrow
+       b       norm_s
+3:
+       move    t0, t4                          # sign of result = FT's
+       sltu    t9, zero, t8                    # compute t6:zero - t2:t8
+       subu    t8, zero, t8
+       subu    t2, t6, t2                      # subtract fractions
+       subu    t2, t2, t9                      # subtract barrow
+       b       norm_s
+
+/*
+ * Double precision subtract.
+ */
+sub_d:
+       jal     get_fs_dbl
+       jal     get_ft_dbl
+       xor     t4, t4, 1                       # negate sign bit
+       b       add_sub_d
+/*
+ * Double precision add.
+ */
+add_d:
+       jal     get_fs_dbl
+       jal     get_ft_dbl
+add_sub_d:
+       bne     t1, DEXP_INF, 1f                # is FS an infinity?
+       bne     t5, DEXP_INF, result_fs_d       # if FT is not inf, result=FS
+       bne     t0, t4, invalid_d               # both infinities same sign?
+       b       result_fs_d                     # result is in FS
+1:
+       beq     t5, DEXP_INF, result_ft_d       # if FT is inf, result=FT
+       bne     t1, zero, 4f                    # is FS a denormalized num?
+       bne     t2, zero, 1f                    # is FS zero?
+       beq     t3, zero, 3f
+1:
+       bne     t5, zero, 2f                    # is FT a denormalized num?
+       bne     t6, zero, 1f
+       beq     t7, zero, result_fs_d           # FT is zero, result=FS
+1:
+       jal     renorm_fs_d
+       jal     renorm_ft_d
+       b       5f
+2:
+       jal     renorm_fs_d
+       subu    t5, t5, DEXP_BIAS               # unbias FT exponent
+       or      t6, t6, DIMPL_ONE               # set implied one bit
+       b       5f
+3:
+       bne     t5, zero, result_ft_d           # if FT != 0, result=FT
+       bne     t6, zero, result_ft_d
+       bne     t7, zero, result_ft_d
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       bne     v0, MACH_FPC_ROUND_RM, 1f       # round to -infinity?
+       or      t0, t0, t4                      # compute result sign
+       b       result_fs_d
+1:
+       and     t0, t0, t4                      # compute result sign
+       b       result_fs_d
+4:
+       bne     t5, zero, 2f                    # is FT a denormalized num?
+       bne     t6, zero, 1f
+       beq     t7, zero, result_fs_d           # FT is zero, result=FS
+1:
+       subu    t1, t1, DEXP_BIAS               # unbias FS exponent
+       or      t2, t2, DIMPL_ONE               # set implied one bit
+       jal     renorm_ft_d
+       b       5f
+2:
+       subu    t1, t1, DEXP_BIAS               # unbias FS exponent
+       or      t2, t2, DIMPL_ONE               # set implied one bit
+       subu    t5, t5, DEXP_BIAS               # unbias FT exponent
+       or      t6, t6, DIMPL_ONE               # set implied one bit
+/*
+ * Perform the addition.
+ */
+5:
+       move    t8, zero                        # no shifted bits (sticky reg)
+       beq     t1, t5, 4f                      # no shift needed
+       subu    v0, t1, t5                      # v0 = difference of exponents
+       move    v1, v0                          # v1 = abs(difference)
+       bge     v0, zero, 1f
+       negu    v1
+1:
+       ble     v1, DFRAC_BITS+2, 2f            # is difference too great?
+       li      t8, STICKYBIT                   # set the sticky bit
+       bge     v0, zero, 1f                    # check which exp is larger
+       move    t1, t5                          # result exp is FT's
+       move    t2, zero                        # FS's fraction shifted is zero
+       move    t3, zero
+       b       4f
+1:
+       move    t6, zero                        # FT's fraction shifted is zero
+       move    t7, zero
+       b       4f
+2:
+       li      t9, 32
+       bge     v0, zero, 3f                    # if FS > FT, shift FT's frac
+       move    t1, t5                          # FT > FS, result exp is FT's
+       blt     v1, t9, 1f                      # shift right by < 32?
+       subu    v1, v1, t9
+       subu    t9, t9, v1
+       sll     t8, t2, t9                      # save bits shifted out
+       sltu    t9, zero, t3                    # don't lose any one bits
+       or      t8, t8, t9                      # save sticky bit
+       srl     t3, t2, v1                      # shift FS's fraction
+       move    t2, zero
+       b       4f
+1:
+       subu    t9, t9, v1
+       sll     t8, t3, t9                      # save bits shifted out
+       srl     t3, t3, v1                      # shift FS's fraction
+       sll     t9, t2, t9                      # save bits shifted out of t2
+       or      t3, t3, t9                      # and put into t3
+       srl     t2, t2, v1
+       b       4f
+3:
+       blt     v1, t9, 1f                      # shift right by < 32?
+       subu    v1, v1, t9
+       subu    t9, t9, v1
+       sll     t8, t6, t9                      # save bits shifted out
+       srl     t7, t6, v1                      # shift FT's fraction
+       move    t6, zero
+       b       4f
+1:
+       subu    t9, t9, v1
+       sll     t8, t7, t9                      # save bits shifted out
+       srl     t7, t7, v1                      # shift FT's fraction
+       sll     t9, t6, t9                      # save bits shifted out of t2
+       or      t7, t7, t9                      # and put into t3
+       srl     t6, t6, v1
+4:
+       bne     t0, t4, 1f                      # if signs differ, subtract
+       addu    t3, t3, t7                      # add fractions
+       sltu    t9, t3, t7                      # compute carry
+       addu    t2, t2, t6                      # add fractions
+       addu    t2, t2, t9                      # add carry
+       b       norm_d
+1:
+       blt     t2, t6, 3f                      # subtract larger from smaller
+       bne     t2, t6, 2f
+       bltu    t3, t7, 3f
+       bne     t3, t7, 2f                      # if same, result=0
+       move    t1, zero                        # result=0
+       move    t2, zero
+       move    t3, zero
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       bne     v0, MACH_FPC_ROUND_RM, 1f       # round to -infinity?
+       or      t0, t0, t4                      # compute result sign
+       b       result_fs_d
+1:
+       and     t0, t0, t4                      # compute result sign
+       b       result_fs_d
+2:
+       beq     t8, zero, 1f                    # compute t2:t3:zero - t6:t7:t8
+       subu    t8, zero, t8
+       sltu    v0, t3, 1                       # compute barrow out
+       subu    t3, t3, 1                       # subtract barrow
+       subu    t2, t2, v0
+1:
+       sltu    v0, t3, t7
+       subu    t3, t3, t7                      # subtract fractions
+       subu    t2, t2, t6                      # subtract fractions
+       subu    t2, t2, v0                      # subtract barrow
+       b       norm_d
+3:
+       move    t0, t4                          # sign of result = FT's
+       beq     t8, zero, 1f                    # compute t6:t7:zero - t2:t3:t8
+       subu    t8, zero, t8
+       sltu    v0, t7, 1                       # compute barrow out
+       subu    t7, t7, 1                       # subtract barrow
+       subu    t6, t6, v0
+1:
+       sltu    v0, t7, t3
+       subu    t3, t7, t3                      # subtract fractions
+       subu    t2, t6, t2                      # subtract fractions
+       subu    t2, t2, v0                      # subtract barrow
+       b       norm_d
+
+/*
+ * Single precision multiply.
+ */
+mul_s:
+       jal     get_fs_sgl
+       jal     get_ft_sgl
+       xor     t0, t0, t4                      # compute sign of result
+       move    t4, t0                          # put in FT too
+       bne     t1, SEXP_INF, 1f                # is FS an infinity?
+       beq     t5, SEXP_INF, result_fs_s       # FS is inf, is FT an infinity?
+       bne     t5, zero, result_fs_s           # inf * zero? if no, result=FS
+       beq     t6, zero, invalid_s             # if yes, invalid operation
+       b       result_fs_s
+1:
+       bne     t5, SEXP_INF, 1f                # FS != inf, is FT an infinity?
+       bne     t1, zero, result_ft_s           # zero * inf? if no, result=FT
+       beq     t2, zero, invalid_s             # if yes, invalid operation
+       b       result_ft_s
+1:
+       bne     t1, zero, 1f                    # is FS zero?
+       beq     t2, zero, result_fs_s           # result is zero
+       jal     renorm_fs_s
+       b       2f
+1:
+       subu    t1, t1, SEXP_BIAS               # unbias FS exponent
+       or      t2, t2, SIMPL_ONE               # set implied one bit
+2:
+       bne     t5, zero, 1f                    # is FT zero?
+       beq     t6, zero, result_ft_s           # result is zero
+       jal     renorm_ft_s
+       b       2f
+1:
+       subu    t5, t5, SEXP_BIAS               # unbias FT exponent
+       or      t6, t6, SIMPL_ONE               # set implied one bit
+2:
+       addu    t1, t1, t5                      # compute result exponent
+       addu    t1, t1, 9                       # ???
+       multu   t2, t6                          # multiply fractions
+       mflo    t8
+       mfhi    t2
+       b       norm_s
+
+/*
+ * Double precision multiply.
+ */
+mul_d:
+       jal     get_fs_dbl
+       jal     get_ft_dbl
+       xor     t0, t0, t4                      # compute sign of result
+       move    t4, t0                          # put in FT too
+       bne     t1, DEXP_INF, 1f                # is FS an infinity?
+       beq     t5, DEXP_INF, result_fs_d       # FS is inf, is FT an infinity?
+       bne     t5, zero, result_fs_d           # inf * zero? if no, result=FS
+       bne     t6, zero, result_fs_d
+       beq     t7, zero, invalid_d             # if yes, invalid operation
+       b       result_fs_d
+1:
+       bne     t5, DEXP_INF, 1f                # FS != inf, is FT an infinity?
+       bne     t1, zero, result_ft_d           # zero * inf? if no, result=FT
+       bne     t2, zero, result_ft_d
+       beq     t3, zero, invalid_d             # if yes, invalid operation
+       b       result_ft_d
+1:
+       bne     t1, zero, 2f                    # is FS zero?
+       bne     t2, zero, 1f
+       beq     t3, zero, result_fs_d           # result is zero
+1:
+       jal     renorm_fs_d
+       b       3f
+2:
+       subu    t1, t1, DEXP_BIAS               # unbias FS exponent
+       or      t2, t2, DIMPL_ONE               # set implied one bit
+3:
+       bne     t5, zero, 2f                    # is FT zero?
+       bne     t6, zero, 1f
+       beq     t7, zero, result_ft_d           # result is zero
+1:
+       jal     renorm_ft_d
+       b       3f
+2:
+       subu    t5, t5, DEXP_BIAS               # unbias FT exponent
+       or      t6, t6, DIMPL_ONE               # set implied one bit
+3:
+       addu    t1, t1, t5                      # compute result exponent
+       addu    t1, t1, 12                      # ???
+       multu   t3, t7                          # multiply fractions (low * low)
+       move    t4, t2                          # free up t2,t3 for result
+       move    t5, t3
+       mflo    a3                              # save low order bits
+       mfhi    t8
+       not     v0, t8
+       multu   t4, t7                          # multiply FS(high) * FT(low)
+       mflo    v1
+       mfhi    t3                              # init low result
+       sltu    v0, v0, v1                      # compute carry
+       addu    t8, v1
+       multu   t5, t6                          # multiply FS(low) * FT(high)
+       addu    t3, t3, v0                      # add carry
+       not     v0, t8
+       mflo    v1
+       mfhi    t2
+       sltu    v0, v0, v1
+       addu    t8, v1
+       multu   t4, t6                          # multiply FS(high) * FT(high)
+       addu    t3, v0
+       not     v1, t3
+       sltu    v1, v1, t2
+       addu    t3, t2
+       not     v0, t3
+       mfhi    t2
+       addu    t2, v1
+       mflo    v1
+       sltu    v0, v0, v1
+       addu    t2, v0
+       addu    t3, v1
+       sltu    a3, zero, a3                    # reduce t8,a3 to just t8
+       or      t8, a3
+       b       norm_d
+
+/*
+ * Single precision divide.
+ */
+div_s:
+       jal     get_fs_sgl
+       jal     get_ft_sgl
+       xor     t0, t0, t4                      # compute sign of result
+       bne     t1, SEXP_INF, 1f                # is FS an infinity?
+       beq     t5, SEXP_INF, invalid_s         # is FT an infinity?
+       b       result_fs_s                     # result=infinity
+1:
+       bne     t5, SEXP_INF, 1f                # is FT an infinity?
+       move    t2, zero                        # result = zero
+       b       result_fs_s
+1:
+       bne     t1, zero, 2f                    # is FS zero?
+       bne     t2, zero, 1f
+       bne     t5, zero, result_fs_s           # FS=zero, is FT zero?
+       beq     t6, zero, invalid_s             # 0 / 0
+       b       result_fs_s                     # result = zero
+1:
+       jal     renorm_fs_s
+       b       3f
+2:
+       subu    t1, t1, SEXP_BIAS               # unbias FS exponent
+       or      t2, t2, SIMPL_ONE               # set implied one bit
+3:
+       bne     t5, zero, 2f                    # is FT zero?
+       bne     t6, zero, 1f
+       or      a1, a1, MACH_FPC_EXCEPTION_DIV0 | MACH_FPC_STICKY_DIV0
+       and     v0, a1, MACH_FPC_ENABLE_DIV0    # trap enabled?
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       li      t1, SEXP_INF                    # result is infinity
+       move    t2, zero
+       b       result_fs_s
+1:
+       jal     renorm_ft_s
+       b       3f
+2:
+       subu    t5, t5, SEXP_BIAS               # unbias FT exponent
+       or      t6, t6, SIMPL_ONE               # set implied one bit
+3:
+       subu    t1, t1, t5                      # compute exponent
+       subu    t1, t1, 3                       # compensate for result position
+       li      v0, SFRAC_BITS+3                # number of bits to divide
+       move    t8, t2                          # init dividend
+       move    t2, zero                        # init result
+1:
+       bltu    t8, t6, 3f                      # is dividend >= divisor?
+2:
+       subu    t8, t8, t6                      # subtract divisor from dividend
+       or      t2, t2, 1                       # remember that we did
+       bne     t8, zero, 3f                    # if not done, continue
+       sll     t2, t2, v0                      # shift result to final position
+       b       norm_s
+3:
+       sll     t8, t8, 1                       # shift dividend
+       sll     t2, t2, 1                       # shift result
+       subu    v0, v0, 1                       # are we done?
+       bne     v0, zero, 1b                    # no, continue
+       b       norm_s
+
+/*
+ * Double precision divide.
+ */
+div_d:
+       jal     get_fs_dbl
+       jal     get_ft_dbl
+       xor     t0, t0, t4                      # compute sign of result
+       bne     t1, DEXP_INF, 1f                # is FS an infinity?
+       beq     t5, DEXP_INF, invalid_d         # is FT an infinity?
+       b       result_fs_d                     # result=infinity
+1:
+       bne     t5, DEXP_INF, 1f                # is FT an infinity?
+       move    t2, zero                        # x / infinity == zero
+       move    t3, zero
+       b       result_fs_d
+1:
+       bne     t1, zero, 2f                    # is FS zero?
+       bne     t2, zero, 1f
+       bne     t3, zero, 1f
+       bne     t5, zero, result_fs_d           # FS=zero, is FT zero?
+       bne     t6, zero, result_fs_d
+       beq     t7, zero, invalid_d             # 0 / 0
+       b       result_fs_d                     # result = zero
+1:
+       jal     renorm_fs_d
+       b       3f
+2:
+       subu    t1, t1, DEXP_BIAS               # unbias FS exponent
+       or      t2, t2, DIMPL_ONE               # set implied one bit
+3:
+       bne     t5, zero, 2f                    # is FT zero?
+       bne     t6, zero, 1f
+       bne     t7, zero, 1f
+       or      a1, a1, MACH_FPC_EXCEPTION_DIV0 | MACH_FPC_STICKY_DIV0
+       and     v0, a1, MACH_FPC_ENABLE_DIV0    # trap enabled?
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # Save exceptions
+       li      t1, DEXP_INF                    # result is infinity
+       move    t2, zero
+       move    t3, zero
+       b       result_fs_d
+1:
+       jal     renorm_ft_d
+       b       3f
+2:
+       subu    t5, t5, DEXP_BIAS               # unbias FT exponent
+       or      t6, t6, DIMPL_ONE               # set implied one bit
+3:
+       subu    t1, t1, t5                      # compute exponent
+       subu    t1, t1, 3                       # compensate for result position
+       li      v0, DFRAC_BITS+3                # number of bits to divide
+       move    t8, t2                          # init dividend
+       move    t9, t3
+       move    t2, zero                        # init result
+       move    t3, zero
+1:
+       bltu    t8, t6, 3f                      # is dividend >= divisor?
+       bne     t8, t6, 2f
+       bltu    t9, t7, 3f
+2:
+       sltu    v1, t9, t7                      # subtract divisor from dividend
+       subu    t9, t9, t7
+       subu    t8, t8, t6
+       subu    t8, t8, v1
+       or      t3, t3, 1                       # remember that we did
+       bne     t8, zero, 3f                    # if not done, continue
+       bne     t9, zero, 3f
+       li      v1, 32                          # shift result to final position
+       subu    v1, v1, v0
+       sll     t2, t2, v0                      # shift upper part
+       srl     t9, t3, v1                      # save bits shifted out
+       or      t2, t2, t9                      # and put into upper part
+       sll     t3, t3, v0
+       b       norm_d
+3:
+       sll     t8, t8, 1                       # shift dividend
+       srl     v1, t9, 31                      # save bit shifted out
+       or      t8, t8, v1                      # and put into upper part
+       sll     t9, t9, 1
+       sll     t2, t2, 1                       # shift result
+       srl     v1, t3, 31                      # save bit shifted out
+       or      t2, t2, v1                      # and put into upper part
+       sll     t3, t3, 1
+       subu    v0, v0, 1                       # are we done?
+       bne     v0, zero, 1b                    # no, continue
+       b       norm_d
+
+/*
+ * Single precision absolute value.
+ */
+abs_s:
+       jal     get_fs_sgl
+       move    t0, zero                        # set sign positive
+       b       result_fs_s
+
+/*
+ * Double precision absolute value.
+ */
+abs_d:
+       jal     get_fs_dbl
+       move    t0, zero                        # set sign positive
+       b       result_fs_d
+
+/*
+ * Single precision move.
+ */
+mov_s:
+       jal     get_fs_sgl
+       b       result_fs_s
+
+/*
+ * Double precision move.
+ */
+mov_d:
+       jal     get_fs_dbl
+       b       result_fs_d
+
+/*
+ * Single precision negate.
+ */
+neg_s:
+       jal     get_fs_sgl
+       xor     t0, t0, 1                       # reverse sign
+       b       result_fs_s
+
+/*
+ * Double precision negate.
+ */
+neg_d:
+       jal     get_fs_dbl
+       xor     t0, t0, 1                       # reverse sign
+       b       result_fs_d
+
+/*
+ * Convert double to single.
+ */
+cvt_s_d:
+       jal     get_fs_dbl
+       bne     t1, DEXP_INF, 1f                # is FS an infinity?
+       li      t1, SEXP_INF                    # convert to single
+       sll     t2, t2, 3                       # convert D fraction to S
+       srl     t8, t3, 32 - 3
+       or      t2, t2, t8
+       b       result_fs_s
+1:
+       bne     t1, zero, 2f                    # is FS zero?
+       bne     t2, zero, 1f
+       beq     t3, zero, result_fs_s           # result=0
+1:
+       jal     renorm_fs_d
+       subu    t1, t1, 3                       # correct exp for shift below
+       b       3f
+2:
+       subu    t1, t1, DEXP_BIAS               # unbias exponent
+       or      t2, t2, DIMPL_ONE               # add implied one bit
+3:
+       sll     t2, t2, 3                       # convert D fraction to S
+       srl     t8, t3, 32 - 3
+       or      t2, t2, t8
+       sll     t8, t3, 3
+       b       norm_noshift_s
+
+/*
+ * Convert integer to single.
+ */
+cvt_s_w:
+       jal     get_fs_int
+       bne     t2, zero, 1f                    # check for zero
+       move    t1, zero
+       b       result_fs_s
+/*
+ * Find out how many leading zero bits are in t2 and put in t9.
+ */
+1:
+       move    v0, t2
+       move    t9, zero
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t2 the correct number of bits.
+ */
+1:
+       subu    t9, t9, SLEAD_ZEROS             # don't count leading zeros
+       li      t1, 23                          # init exponent
+       subu    t1, t1, t9                      # compute exponent
+       beq     t9, zero, 1f
+       li      v0, 32
+       blt     t9, zero, 2f                    # if shift < 0, shift right
+       subu    v0, v0, t9
+       sll     t2, t2, t9                      # shift left
+1:
+       add     t1, t1, SEXP_BIAS               # bias exponent
+       and     t2, t2, ~SIMPL_ONE              # clear implied one bit
+       b       result_fs_s
+2:
+       negu    t9                              # shift right by t9
+       subu    v0, v0, t9
+       sll     t8, t2, v0                      # save bits shifted out
+       srl     t2, t2, t9
+       b       norm_noshift_s
+
+/*
+ * Convert single to double.
+ */
+cvt_d_s:
+       jal     get_fs_sgl
+       bne     t1, SEXP_INF, 1f                # is FS an infinity?
+       li      t1, DEXP_INF                    # convert to double
+       b       2f
+1:
+       bne     t1, zero, 2f                    # is FS denormalized or zero?
+       beq     t2, zero, result_fs_d           # is FS zero?
+       jal     renorm_fs_s
+       move    t8, zero
+       b       norm_d
+2:
+       addu    t1, t1, DEXP_BIAS - SEXP_BIAS   # bias exponent correctly
+       sll     t3, t2, 32 - 3                  # convert S fraction to D
+       srl     t2, t2, 3
+       b       result_fs_d
+
+/*
+ * Convert integer to double.
+ */
+cvt_d_w:
+       jal     get_fs_int
+       bne     t2, zero, 1f                    # check for zero
+       move    t1, zero                        # result=0
+       move    t3, zero
+       b       result_fs_d
+/*
+ * Find out how many leading zero bits are in t2 and put in t9.
+ */
+1:
+       move    v0, t2
+       move    t9, zero
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t2 the correct number of bits.
+ */
+1:
+       subu    t9, t9, DLEAD_ZEROS             # don't count leading zeros
+       li      t1, DEXP_BIAS + 23              # init exponent
+       subu    t1, t1, t9                      # compute exponent
+       beq     t9, zero, 1f
+       li      v0, 32
+       blt     t9, zero, 2f                    # if shift < 0, shift right
+       subu    v0, v0, t9
+       sll     t2, t2, t9                      # shift left
+1:
+       and     t2, t2, ~DIMPL_ONE              # clear implied one bit
+       b       result_fs_d
+2:
+       negu    t9                              # shift right by t9
+       subu    v0, v0, t9
+       sll     t3, t2, v0
+       srl     t2, t2, t9
+       and     t2, t2, ~DIMPL_ONE              # clear implied one bit
+       b       result_fs_d
+
+/*
+ * Convert single to integer.
+ */
+cvt_w_s:
+       jal     get_fs_sgl
+       bne     t1, SEXP_INF, 1f                # is FS an infinity?
+       bne     t2, zero, invalid_w             # invalid conversion
+1:
+       bne     t1, zero, 1f                    # is FS zero?
+       beq     t2, zero, result_fs_w           # result is zero
+       move    t2, zero                        # result is an inexact zero
+       b       inexact_w
+1:
+       subu    t1, t1, SEXP_BIAS               # unbias exponent
+       or      t2, t2, SIMPL_ONE               # add implied one bit
+       sll     t3, t2, 32 - 3                  # convert S fraction to D
+       srl     t2, t2, 3
+       b       cvt_w
+
+/*
+ * Convert double to integer.
+ */
+cvt_w_d:
+       jal     get_fs_dbl
+       bne     t1, DEXP_INF, 1f                # is FS an infinity?
+       bne     t2, zero, invalid_w             # invalid conversion
+       bne     t3, zero, invalid_w             # invalid conversion
+1:
+       bne     t1, zero, 2f                    # is FS zero?
+       bne     t2, zero, 1f
+       beq     t3, zero, result_fs_w           # result is zero
+1:
+       move    t2, zero                        # result is an inexact zero
+       b       inexact_w
+2:
+       subu    t1, t1, DEXP_BIAS               # unbias exponent
+       or      t2, t2, DIMPL_ONE               # add implied one bit
+cvt_w:
+       blt     t1, WEXP_MIN, underflow_w       # is exponent too small?
+       li      v0, WEXP_MAX+1
+       bgt     t1, v0, overflow_w              # is exponent too large?
+       bne     t1, v0, 1f                      # special check for INT_MIN
+       beq     t0, zero, overflow_w            # if positive, overflow
+       bne     t2, DIMPL_ONE, overflow_w
+       bne     t3, zero, overflow_w
+       li      t2, INT_MIN                     # result is INT_MIN
+       b       result_fs_w
+1:
+       subu    v0, t1, 20                      # compute amount to shift
+       beq     v0, zero, 2f                    # is shift needed?
+       li      v1, 32
+       blt     v0, zero, 1f                    # if shift < 0, shift right
+       subu    v1, v1, v0                      # shift left
+       sll     t2, t2, v0
+       srl     t9, t3, v1                      # save bits shifted out of t3
+       or      t2, t2, t9                      # and put into t2
+       sll     t3, t3, v0                      # shift FS's fraction
+       b       2f
+1:
+       negu    v0                              # shift right by v0
+       subu    v1, v1, v0
+       sll     t8, t3, v1                      # save bits shifted out
+       sltu    t8, zero, t8                    # don't lose any one's
+       srl     t3, t3, v0                      # shift FS's fraction
+       or      t3, t3, t8
+       sll     t9, t2, v1                      # save bits shifted out of t2
+       or      t3, t3, t9                      # and put into t3
+       srl     t2, t2, v0
+/*
+ * round result (t0 is sign, t2 is integer part, t3 is fractional part).
+ */
+2:
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       beq     v0, MACH_FPC_ROUND_RN, 3f       # round to nearest
+       beq     v0, MACH_FPC_ROUND_RZ, 5f       # round to zero (truncate)
+       beq     v0, MACH_FPC_ROUND_RP, 1f       # round to +infinity
+       beq     t0, zero, 5f                    # if sign is positive, truncate
+       b       2f
+1:
+       bne     t0, zero, 5f                    # if sign is negative, truncate
+2:
+       beq     t3, zero, 5f                    # if no fraction bits, continue
+       addu    t2, t2, 1                       # add rounding bit
+       blt     t2, zero, overflow_w            # overflow?
+       b       5f
+3:
+       li      v0, GUARDBIT                    # load guard bit for rounding
+       addu    v0, v0, t3                      # add remainder
+       sltu    v1, v0, t3                      # compute carry out
+       beq     v1, zero, 4f                    # if no carry, continue
+       addu    t2, t2, 1                       # add carry to result
+       blt     t2, zero, overflow_w            # overflow?
+4:
+       bne     v0, zero, 5f                    # if rounded remainder is zero
+       and     t2, t2, ~1                      #  clear LSB (round to nearest)
+5:
+       beq     t0, zero, 1f                    # result positive?
+       negu    t2                              # convert to negative integer
+1:
+       beq     t3, zero, result_fs_w           # is result exact?
+/*
+ * Handle inexact exception.
+ */
+inexact_w:
+       or      a1, a1, MACH_FPC_EXCEPTION_INEXACT | MACH_FPC_STICKY_INEXACT
+       and     v0, a1, MACH_FPC_ENABLE_INEXACT
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       b       result_fs_w
+
+/*
+ * Conversions to integer which overflow will trap (if enabled),
+ * or generate an inexact trap (if enabled),
+ * or generate an invalid exception.
+ */
+overflow_w:
+       or      a1, a1, MACH_FPC_EXCEPTION_OVERFLOW | MACH_FPC_STICKY_OVERFLOW
+       and     v0, a1, MACH_FPC_ENABLE_OVERFLOW
+       bne     v0, zero, fpe_trap
+       and     v0, a1, MACH_FPC_ENABLE_INEXACT
+       bne     v0, zero, inexact_w             # inexact traps enabled?
+       b       invalid_w
+
+/*
+ * Conversions to integer which underflow will trap (if enabled),
+ * or generate an inexact trap (if enabled),
+ * or generate an invalid exception.
+ */
+underflow_w:
+       or      a1, a1, MACH_FPC_EXCEPTION_UNDERFLOW | MACH_FPC_STICKY_UNDERFLOW
+       and     v0, a1, MACH_FPC_ENABLE_UNDERFLOW
+       bne     v0, zero, fpe_trap
+       and     v0, a1, MACH_FPC_ENABLE_INEXACT
+       bne     v0, zero, inexact_w             # inexact traps enabled?
+       b       invalid_w
+
+/*
+ * Compare single.
+ */
+cmp_s:
+       jal     get_fs_sgl
+       jal     get_ft_sgl
+       bne     t1, SEXP_INF, 1f                # is FS an infinity?
+       bne     t2, zero, unordered             # FS is a NAN
+       b       2f
+1:
+       bne     t5, SEXP_INF, 2f                # is FT an infinity?
+       bne     t6, zero, unordered             # FT is a NAN
+2:
+       sll     t1, t1, 23                      # reassemble exp & frac
+       or      t1, t1, t2
+       sll     t5, t5, 23                      # reassemble exp & frac
+       or      t5, t5, t6
+       beq     t0, zero, 1f                    # is FS positive?
+       negu    t1
+1:
+       beq     t4, zero, 1f                    # is FT positive?
+       negu    t5
+1:
+       li      v0, COND_LESS
+       blt     t1, t5, test_cond               # is FS < FT?
+       li      v0, COND_EQUAL
+       beq     t1, t5, test_cond               # is FS == FT?
+       move    v0, zero                        # FS > FT
+       b       test_cond
+
+/*
+ * Compare double.
+ */
+cmp_d:
+       jal     get_fs_dbl
+       jal     get_ft_dbl
+       bne     t1, DEXP_INF, 1f                # is FS an infinity?
+       bne     t2, zero, unordered
+       bne     t3, zero, unordered             # FS is a NAN
+       b       2f
+1:
+       bne     t5, DEXP_INF, 2f                # is FT an infinity?
+       bne     t6, zero, unordered
+       bne     t7, zero, unordered             # FT is a NAN
+2:
+       sll     t1, t1, 20                      # reassemble exp & frac
+       or      t1, t1, t2
+       sll     t5, t5, 20                      # reassemble exp & frac
+       or      t5, t5, t6
+       beq     t0, zero, 1f                    # is FS positive?
+       not     t3                              # negate t1,t3
+       not     t1
+       addu    t3, t3, 1
+       seq     v0, t3, zero                    # compute carry
+       addu    t1, t1, v0
+1:
+       beq     t4, zero, 1f                    # is FT positive?
+       not     t7                              # negate t5,t7
+       not     t5
+       addu    t7, t7, 1
+       seq     v0, t7, zero                    # compute carry
+       addu    t5, t5, v0
+1:
+       li      v0, COND_LESS
+       blt     t1, t5, test_cond               # is FS(MSW) < FT(MSW)?
+       move    v0, zero
+       bne     t1, t5, test_cond               # is FS(MSW) > FT(MSW)?
+       li      v0, COND_LESS
+       bltu    t3, t7, test_cond               # is FS(LSW) < FT(LSW)?
+       li      v0, COND_EQUAL
+       beq     t3, t7, test_cond               # is FS(LSW) == FT(LSW)?
+1:
+       move    v0, zero                        # FS > FT
+
+test_cond:
+       and     v0, v0, a0                      # condition match instruction?
+       b       set_cond
+unordered:
+       and     v0, a0, COND_SIGNAL
+       beq     v0, zero, 1f                    # is this a signalling cmp?
+       or      a1, a1, MACH_FPC_EXCEPTION_INVALID | MACH_FPC_STICKY_INVALID
+       and     v0, a1, MACH_FPC_ENABLE_INVALID
+       bne     v0, zero, fpe_trap
+1:
+       and     v0, a0, COND_UNORDERED          # this cmp match unordered?
+set_cond:
+       bne     v0, zero, 1f
+       and     a1, a1, ~MACH_FPC_COND_BIT      # clear condition bit
+       b       2f
+1:
+       or      a1, a1, MACH_FPC_COND_BIT       # set condition bit
+2:
+       ctc1    a1, MACH_FPC_CSR                # save condition bit
+       b       done
+
+/*
+ * Determine the amount to shift the fraction in order to restore the
+ * normalized position. After that, round and handle exceptions.
+ */
+norm_s:
+       move    v0, t2
+       move    t9, zero                        # t9 = num of leading zeros
+       bne     t2, zero, 1f
+       move    v0, t8
+       addu    t9, 32
+1:
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t2,t8 the correct number of bits.
+ */
+1:
+       subu    t9, t9, SLEAD_ZEROS             # don't count leading zeros
+       subu    t1, t1, t9                      # adjust the exponent
+       beq     t9, zero, norm_noshift_s
+       li      v1, 32
+       blt     t9, zero, 1f                    # if shift < 0, shift right
+       subu    v1, v1, t9
+       sll     t2, t2, t9                      # shift t2,t8 left
+       srl     v0, t8, v1                      # save bits shifted out
+       or      t2, t2, v0
+       sll     t8, t8, t9
+       b       norm_noshift_s
+1:
+       negu    t9                              # shift t2,t8 right by t9
+       subu    v1, v1, t9
+       sll     v0, t8, v1                      # save bits shifted out
+       sltu    v0, zero, v0                    # be sure to save any one bits
+       srl     t8, t8, t9
+       or      t8, t8, v0
+       sll     v0, t2, v1                      # save bits shifted out
+       or      t8, t8, v0
+       srl     t2, t2, t9
+norm_noshift_s:
+       move    t5, t1                          # save unrounded exponent
+       move    t6, t2                          # save unrounded fraction
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       beq     v0, MACH_FPC_ROUND_RN, 3f       # round to nearest
+       beq     v0, MACH_FPC_ROUND_RZ, 5f       # round to zero (truncate)
+       beq     v0, MACH_FPC_ROUND_RP, 1f       # round to +infinity
+       beq     t0, zero, 5f                    # if sign is positive, truncate
+       b       2f
+1:
+       bne     t0, zero, 5f                    # if sign is negative, truncate
+2:
+       beq     t8, zero, 5f                    # if exact, continue
+       addu    t2, t2, 1                       # add rounding bit
+       bne     t2, SIMPL_ONE<<1, 5f            # need to adjust exponent?
+       addu    t1, t1, 1                       # adjust exponent
+       srl     t2, t2, 1                       # renormalize fraction
+       b       5f
+3:
+       li      v0, GUARDBIT                    # load guard bit for rounding
+       addu    v0, v0, t8                      # add remainder
+       sltu    v1, v0, t8                      # compute carry out
+       beq     v1, zero, 4f                    # if no carry, continue
+       addu    t2, t2, 1                       # add carry to result
+       bne     t2, SIMPL_ONE<<1, 4f            # need to adjust exponent?
+       addu    t1, t1, 1                       # adjust exponent
+       srl     t2, t2, 1                       # renormalize fraction
+4:
+       bne     v0, zero, 5f                    # if rounded remainder is zero
+       and     t2, t2, ~1                      #  clear LSB (round to nearest)
+5:
+       bgt     t1, SEXP_MAX, overflow_s        # overflow?
+       blt     t1, SEXP_MIN, underflow_s       # underflow?
+       bne     t8, zero, inexact_s             # is result inexact?
+       addu    t1, t1, SEXP_BIAS               # bias exponent
+       and     t2, t2, ~SIMPL_ONE              # clear implied one bit
+       b       result_fs_s
+
+/*
+ * Handle inexact exception.
+ */
+inexact_s:
+       addu    t1, t1, SEXP_BIAS               # bias exponent
+       and     t2, t2, ~SIMPL_ONE              # clear implied one bit
+inexact_nobias_s:
+       jal     set_fd_sgl                      # save result
+       or      a1, a1, MACH_FPC_EXCEPTION_INEXACT | MACH_FPC_STICKY_INEXACT
+       and     v0, a1, MACH_FPC_ENABLE_INEXACT
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       b       done
+
+/*
+ * Overflow will trap (if enabled),
+ * or generate an inexact trap (if enabled),
+ * or generate an infinity.
+ */
+overflow_s:
+       or      a1, a1, MACH_FPC_EXCEPTION_OVERFLOW | MACH_FPC_STICKY_OVERFLOW
+       and     v0, a1, MACH_FPC_ENABLE_OVERFLOW
+       beq     v0, zero, 1f
+       subu    t1, t1, 192                     # bias exponent
+       and     t2, t2, ~SIMPL_ONE              # clear implied one bit
+       jal     set_fd_sgl                      # save result
+       b       fpe_trap
+1:
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       beq     v0, MACH_FPC_ROUND_RN, 5f       # round to nearest
+       beq     v0, MACH_FPC_ROUND_RZ, 1f       # round to zero (truncate)
+       beq     v0, MACH_FPC_ROUND_RP, 3f       # round to +infinity
+       bne     t0, zero, 2f
+1:
+       li      t1, SEXP_MAX                    # result is max finite
+       li      t2, 0x007fffff
+       b       inexact_s
+2:
+       li      t1, SEXP_MIN - 1                # result is -infinity
+       move    t2, zero
+       b       inexact_s
+3:
+       bne     t0, zero, 1b
+4:
+       li      t1, SEXP_MAX + 1                # result is +infinity
+       move    t2, zero
+       b       inexact_s
+5:
+       bne     t0, zero, 2b
+       b       4b
+
+/*
+ * In this implementation, "tininess" is detected "after rounding" and
+ * "loss of accuracy" is detected as "an inexact result".
+ */
+underflow_s:
+       and     v0, a1, MACH_FPC_ENABLE_UNDERFLOW
+       beq     v0, zero, 1f
+/*
+ * Underflow is enabled so compute the result and trap.
+ */
+       addu    t1, t1, 192                     # bias exponent
+       and     t2, t2, ~SIMPL_ONE              # clear implied one bit
+       jal     set_fd_sgl                      # save result
+       or      a1, a1, MACH_FPC_EXCEPTION_UNDERFLOW | MACH_FPC_STICKY_UNDERFLOW
+       b       fpe_trap
+/*
+ * Underflow is not enabled so compute the result,
+ * signal inexact result (if it is) and trap (if enabled).
+ */
+1:
+       move    t1, t5                          # get unrounded exponent
+       move    t2, t6                          # get unrounded fraction
+       li      t9, SEXP_MIN                    # compute shift amount
+       subu    t9, t9, t1                      # shift t2,t8 right by t9
+       blt     t9, SFRAC_BITS+2, 1f            # shift all the bits out?
+       move    t1, zero                        # result is inexact zero
+       move    t2, zero
+       or      a1, a1, MACH_FPC_EXCEPTION_UNDERFLOW | MACH_FPC_STICKY_UNDERFLOW
+       b       inexact_nobias_s
+1:
+       li      v1, 32
+       subu    v1, v1, t9
+       sll     t8, t2, v1                      # save bits shifted out
+       srl     t2, t2, t9
+/*
+ * Now round the denormalized result.
+ */
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       beq     v0, MACH_FPC_ROUND_RN, 3f       # round to nearest
+       beq     v0, MACH_FPC_ROUND_RZ, 5f       # round to zero (truncate)
+       beq     v0, MACH_FPC_ROUND_RP, 1f       # round to +infinity
+       beq     t0, zero, 5f                    # if sign is positive, truncate
+       b       2f
+1:
+       bne     t0, zero, 5f                    # if sign is negative, truncate
+2:
+       beq     t8, zero, 5f                    # if exact, continue
+       addu    t2, t2, 1                       # add rounding bit
+       b       5f
+3:
+       li      v0, GUARDBIT                    # load guard bit for rounding
+       addu    v0, v0, t8                      # add remainder
+       sltu    v1, v0, t8                      # compute carry out
+       beq     v1, zero, 4f                    # if no carry, continue
+       addu    t2, t2, 1                       # add carry to result
+4:
+       bne     v0, zero, 5f                    # if rounded remainder is zero
+       and     t2, t2, ~1                      #  clear LSB (round to nearest)
+5:
+       move    t1, zero                        # denorm or zero exponent
+       jal     set_fd_sgl                      # save result
+       beq     t8, zero, done                  # check for exact result
+       or      a1, a1, MACH_FPC_EXCEPTION_UNDERFLOW | MACH_FPC_STICKY_UNDERFLOW
+       or      a1, a1, MACH_FPC_EXCEPTION_INEXACT | MACH_FPC_STICKY_INEXACT
+       and     v0, a1, MACH_FPC_ENABLE_INEXACT
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       b       done
+
+/*
+ * Determine the amount to shift the fraction in order to restore the
+ * normalized position. After that, round and handle exceptions.
+ */
+norm_d:
+       move    v0, t2
+       move    t9, zero                        # t9 = num of leading zeros
+       bne     t2, zero, 1f
+       move    v0, t3
+       addu    t9, 32
+       bne     t3, zero, 1f
+       move    v0, t8
+       addu    t9, 32
+1:
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t2,t3,t8 the correct number of bits.
+ */
+1:
+       subu    t9, t9, DLEAD_ZEROS             # don't count leading zeros
+       subu    t1, t1, t9                      # adjust the exponent
+       beq     t9, zero, norm_noshift_d
+       li      v1, 32
+       blt     t9, zero, 2f                    # if shift < 0, shift right
+       blt     t9, v1, 1f                      # shift by < 32?
+       subu    t9, t9, v1                      # shift by >= 32
+       subu    v1, v1, t9
+       sll     t2, t3, t9                      # shift left by t9
+       srl     v0, t8, v1                      # save bits shifted out
+       or      t2, t2, v0
+       sll     t3, t8, t9
+       move    t8, zero
+       b       norm_noshift_d
+1:
+       subu    v1, v1, t9
+       sll     t2, t2, t9                      # shift left by t9
+       srl     v0, t3, v1                      # save bits shifted out
+       or      t2, t2, v0
+       sll     t3, t3, t9
+       srl     v0, t8, v1                      # save bits shifted out
+       or      t3, t3, v0
+       sll     t8, t8, t9
+       b       norm_noshift_d
+2:
+       negu    t9                              # shift right by t9
+       subu    v1, v1, t9                      #  (known to be < 32 bits)
+       sll     v0, t8, v1                      # save bits shifted out
+       sltu    v0, zero, v0                    # be sure to save any one bits
+       srl     t8, t8, t9
+       or      t8, t8, v0
+       sll     v0, t3, v1                      # save bits shifted out
+       or      t8, t8, v0
+       srl     t3, t3, t9
+       sll     v0, t2, v1                      # save bits shifted out
+       or      t3, t3, v0
+       srl     t2, t2, t9
+norm_noshift_d:
+       move    t5, t1                          # save unrounded exponent
+       move    t6, t2                          # save unrounded fraction (MS)
+       move    t7, t3                          # save unrounded fraction (LS)
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       beq     v0, MACH_FPC_ROUND_RN, 3f       # round to nearest
+       beq     v0, MACH_FPC_ROUND_RZ, 5f       # round to zero (truncate)
+       beq     v0, MACH_FPC_ROUND_RP, 1f       # round to +infinity
+       beq     t0, zero, 5f                    # if sign is positive, truncate
+       b       2f
+1:
+       bne     t0, zero, 5f                    # if sign is negative, truncate
+2:
+       beq     t8, zero, 5f                    # if exact, continue
+       addu    t3, t3, 1                       # add rounding bit
+       bne     t3, zero, 5f                    # branch if no carry
+       addu    t2, t2, 1                       # add carry
+       bne     t2, DIMPL_ONE<<1, 5f            # need to adjust exponent?
+       addu    t1, t1, 1                       # adjust exponent
+       srl     t2, t2, 1                       # renormalize fraction
+       b       5f
+3:
+       li      v0, GUARDBIT                    # load guard bit for rounding
+       addu    v0, v0, t8                      # add remainder
+       sltu    v1, v0, t8                      # compute carry out
+       beq     v1, zero, 4f                    # branch if no carry
+       addu    t3, t3, 1                       # add carry
+       bne     t3, zero, 4f                    # branch if no carry
+       addu    t2, t2, 1                       # add carry to result
+       bne     t2, DIMPL_ONE<<1, 4f            # need to adjust exponent?
+       addu    t1, t1, 1                       # adjust exponent
+       srl     t2, t2, 1                       # renormalize fraction
+4:
+       bne     v0, zero, 5f                    # if rounded remainder is zero
+       and     t3, t3, ~1                      #  clear LSB (round to nearest)
+5:
+       bgt     t1, DEXP_MAX, overflow_d        # overflow?
+       blt     t1, DEXP_MIN, underflow_d       # underflow?
+       bne     t8, zero, inexact_d             # is result inexact?
+       addu    t1, t1, DEXP_BIAS               # bias exponent
+       and     t2, t2, ~DIMPL_ONE              # clear implied one bit
+       b       result_fs_d
+
+/*
+ * Handle inexact exception.
+ */
+inexact_d:
+       addu    t1, t1, DEXP_BIAS               # bias exponent
+       and     t2, t2, ~DIMPL_ONE              # clear implied one bit
+inexact_nobias_d:
+       jal     set_fd_dbl                      # save result
+       or      a1, a1, MACH_FPC_EXCEPTION_INEXACT | MACH_FPC_STICKY_INEXACT
+       and     v0, a1, MACH_FPC_ENABLE_INEXACT
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       b       done
+
+/*
+ * Overflow will trap (if enabled),
+ * or generate an inexact trap (if enabled),
+ * or generate an infinity.
+ */
+overflow_d:
+       or      a1, a1, MACH_FPC_EXCEPTION_OVERFLOW | MACH_FPC_STICKY_OVERFLOW
+       and     v0, a1, MACH_FPC_ENABLE_OVERFLOW
+       beq     v0, zero, 1f
+       subu    t1, t1, 1536                    # bias exponent
+       and     t2, t2, ~DIMPL_ONE              # clear implied one bit
+       jal     set_fd_dbl                      # save result
+       b       fpe_trap
+1:
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       beq     v0, MACH_FPC_ROUND_RN, 5f       # round to nearest
+       beq     v0, MACH_FPC_ROUND_RZ, 1f       # round to zero (truncate)
+       beq     v0, MACH_FPC_ROUND_RP, 3f       # round to +infinity
+       bne     t0, zero, 2f
+1:
+       li      t1, DEXP_MAX                    # result is max finite
+       li      t2, 0x000fffff
+       li      t3, 0xffffffff
+       b       inexact_d
+2:
+       li      t1, DEXP_MIN - 1                # result is -infinity
+       move    t2, zero
+       move    t3, zero
+       b       inexact_d
+3:
+       bne     t0, zero, 1b
+4:
+       li      t1, DEXP_MAX + 1                # result is +infinity
+       move    t2, zero
+       move    t3, zero
+       b       inexact_d
+5:
+       bne     t0, zero, 2b
+       b       4b
+
+/*
+ * In this implementation, "tininess" is detected "after rounding" and
+ * "loss of accuracy" is detected as "an inexact result".
+ */
+underflow_d:
+       and     v0, a1, MACH_FPC_ENABLE_UNDERFLOW
+       beq     v0, zero, 1f
+/*
+ * Underflow is enabled so compute the result and trap.
+ */
+       addu    t1, t1, 1536                    # bias exponent
+       and     t2, t2, ~DIMPL_ONE              # clear implied one bit
+       jal     set_fd_dbl                      # save result
+       or      a1, a1, MACH_FPC_EXCEPTION_UNDERFLOW | MACH_FPC_STICKY_UNDERFLOW
+       b       fpe_trap
+/*
+ * Underflow is not enabled so compute the result,
+ * signal inexact result (if it is) and trap (if enabled).
+ */
+1:
+       move    t1, t5                          # get unrounded exponent
+       move    t2, t6                          # get unrounded fraction (MS)
+       move    t3, t7                          # get unrounded fraction (LS)
+       li      t9, DEXP_MIN                    # compute shift amount
+       subu    t9, t9, t1                      # shift t2,t8 right by t9
+       blt     t9, DFRAC_BITS+2, 1f            # shift all the bits out?
+       move    t1, zero                        # result is inexact zero
+       move    t2, zero
+       move    t3, zero
+       or      a1, a1, MACH_FPC_EXCEPTION_UNDERFLOW | MACH_FPC_STICKY_UNDERFLOW
+       b       inexact_nobias_d
+1:
+       li      v1, 32
+       blt     t9, v1, 1f                      # shift by < 32?
+       subu    t9, t9, v1                      # shift right by >= 32
+       subu    v1, v1, t9
+       sll     t8, t2, v1                      # save bits shifted out
+       srl     t3, t2, t9
+       move    t2, zero
+       b       2f
+1:
+       subu    v1, v1, t9                      # shift right by t9
+       sll     t8, t3, v1                      # save bits shifted out
+       srl     t3, t3, t9
+       sll     v0, t2, v1                      # save bits shifted out
+       or      t3, t3, v0
+       srl     t2, t2, t9
+/*
+ * Now round the denormalized result.
+ */
+2:
+       and     v0, a1, MACH_FPC_ROUNDING_BITS  # get rounding mode
+       beq     v0, MACH_FPC_ROUND_RN, 3f       # round to nearest
+       beq     v0, MACH_FPC_ROUND_RZ, 5f       # round to zero (truncate)
+       beq     v0, MACH_FPC_ROUND_RP, 1f       # round to +infinity
+       beq     t0, zero, 5f                    # if sign is positive, truncate
+       b       2f
+1:
+       bne     t0, zero, 5f                    # if sign is negative, truncate
+2:
+       beq     t8, zero, 5f                    # if exact, continue
+       addu    t3, t3, 1                       # add rounding bit
+       bne     t3, zero, 5f                    # if no carry, continue
+       addu    t2, t2, 1                       # add carry
+       b       5f
+3:
+       li      v0, GUARDBIT                    # load guard bit for rounding
+       addu    v0, v0, t8                      # add remainder
+       sltu    v1, v0, t8                      # compute carry out
+       beq     v1, zero, 4f                    # if no carry, continue
+       addu    t3, t3, 1                       # add rounding bit
+       bne     t3, zero, 4f                    # if no carry, continue
+       addu    t2, t2, 1                       # add carry
+4:
+       bne     v0, zero, 5f                    # if rounded remainder is zero
+       and     t3, t3, ~1                      #  clear LSB (round to nearest)
+5:
+       move    t1, zero                        # denorm or zero exponent
+       jal     set_fd_dbl                      # save result
+       beq     t8, zero, done                  # check for exact result
+       or      a1, a1, MACH_FPC_EXCEPTION_UNDERFLOW | MACH_FPC_STICKY_UNDERFLOW
+       or      a1, a1, MACH_FPC_EXCEPTION_INEXACT | MACH_FPC_STICKY_INEXACT
+       and     v0, a1, MACH_FPC_ENABLE_INEXACT
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       b       done
+
+/*
+ * Signal an invalid operation if the trap is enabled; otherwise,
+ * the result is a quiet NAN.
+ */
+invalid_s:                                     # trap invalid operation
+       or      a1, a1, MACH_FPC_EXCEPTION_INVALID | MACH_FPC_STICKY_INVALID
+       and     v0, a1, MACH_FPC_ENABLE_INVALID
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       move    t0, zero                        # result is a quiet NAN
+       li      t1, SEXP_INF
+       li      t2, SQUIET_NAN
+       jal     set_fd_sgl                      # save result (in t0,t1,t2)
+       b       done
+
+/*
+ * Signal an invalid operation if the trap is enabled; otherwise,
+ * the result is a quiet NAN.
+ */
+invalid_d:                                     # trap invalid operation
+       or      a1, a1, MACH_FPC_EXCEPTION_INVALID | MACH_FPC_STICKY_INVALID
+       and     v0, a1, MACH_FPC_ENABLE_INVALID
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       move    t0, zero                        # result is a quiet NAN
+       li      t1, DEXP_INF
+       li      t2, DQUIET_NAN0
+       li      t3, DQUIET_NAN1
+       jal     set_fd_dbl                      # save result (in t0,t1,t2,t3)
+       b       done
+
+/*
+ * Signal an invalid operation if the trap is enabled; otherwise,
+ * the result is INT_MAX or INT_MIN.
+ */
+invalid_w:                                     # trap invalid operation
+       or      a1, a1, MACH_FPC_EXCEPTION_INVALID | MACH_FPC_STICKY_INVALID
+       and     v0, a1, MACH_FPC_ENABLE_INVALID
+       bne     v0, zero, fpe_trap
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       bne     t0, zero, 1f
+       li      t2, INT_MAX                     # result is INT_MAX
+       b       result_fs_w
+1:
+       li      t2, INT_MIN                     # result is INT_MIN
+       b       result_fs_w
+
+/*
+ * Trap if the hardware should have handled this case.
+ */
+fpe_trap:
+       move    a2, a1                          # code = FP CSR
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       lw      a0, curproc                     # get current process
+       li      a1, SIGFPE
+       jal     trapsignal
+       b       done
+
+/*
+ * Send an illegal instruction signal to the current process.
+ */
+ill:
+       ctc1    a1, MACH_FPC_CSR                # save exceptions
+       move    a2, a0                          # code = FP instruction
+       lw      a0, curproc                     # get current process
+       li      a1, SIGILL
+       jal     trapsignal
+       b       done
+
+result_ft_s:
+       move    t0, t4                          # result is FT
+       move    t1, t5
+       move    t2, t6
+result_fs_s:                                   # result is FS
+       jal     set_fd_sgl                      # save result (in t0,t1,t2)
+       b       done
+
+result_fs_w:
+       jal     set_fd_word                     # save result (in t2)
+       b       done
+
+result_ft_d:
+       move    t0, t4                          # result is FT
+       move    t1, t5
+       move    t2, t6
+       move    t3, t7
+result_fs_d:                                   # result is FS
+       jal     set_fd_dbl                      # save result (in t0,t1,t2,t3)
+
+done:
+       lw      ra, STAND_RA_OFFSET(sp)
+       addu    sp, sp, STAND_FRAME_SIZE
+       j       ra
+END(MachEmulateFP)
+
+/*----------------------------------------------------------------------------
+ * get_fs_sgl --
+ *
+ *     Read (single precision) the FS register (bits 15-11) and
+ *     break up into fields.
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Results:
+ *     t0      contains the sign
+ *     t1      contains the (biased) exponent
+ *     t2      contains the fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(get_fs_sgl)
+       srl     a3, a0, 12 - 2                  # get FS field (even regs only)
+       and     a3, a3, 0xF << 2                # mask FS field
+       lw      a3, get_fs_sgl_tbl(a3)          # switch on register number
+       j       a3
+
+       .rdata
+get_fs_sgl_tbl:
+       .word   get_fs_sgl_f0
+       .word   get_fs_sgl_f2
+       .word   get_fs_sgl_f4
+       .word   get_fs_sgl_f6
+       .word   get_fs_sgl_f8
+       .word   get_fs_sgl_f10
+       .word   get_fs_sgl_f12
+       .word   get_fs_sgl_f14
+       .word   get_fs_sgl_f16
+       .word   get_fs_sgl_f18
+       .word   get_fs_sgl_f20
+       .word   get_fs_sgl_f22
+       .word   get_fs_sgl_f24
+       .word   get_fs_sgl_f26
+       .word   get_fs_sgl_f28
+       .word   get_fs_sgl_f30
+       .text
+
+get_fs_sgl_f0:
+       mfc1    t0, $f0
+       b       get_fs_sgl_done
+get_fs_sgl_f2:
+       mfc1    t0, $f2
+       b       get_fs_sgl_done
+get_fs_sgl_f4:
+       mfc1    t0, $f4
+       b       get_fs_sgl_done
+get_fs_sgl_f6:
+       mfc1    t0, $f6
+       b       get_fs_sgl_done
+get_fs_sgl_f8:
+       mfc1    t0, $f8
+       b       get_fs_sgl_done
+get_fs_sgl_f10:
+       mfc1    t0, $f10
+       b       get_fs_sgl_done
+get_fs_sgl_f12:
+       mfc1    t0, $f12
+       b       get_fs_sgl_done
+get_fs_sgl_f14:
+       mfc1    t0, $f14
+       b       get_fs_sgl_done
+get_fs_sgl_f16:
+       mfc1    t0, $f16
+       b       get_fs_sgl_done
+get_fs_sgl_f18:
+       mfc1    t0, $f18
+       b       get_fs_sgl_done
+get_fs_sgl_f20:
+       mfc1    t0, $f20
+       b       get_fs_sgl_done
+get_fs_sgl_f22:
+       mfc1    t0, $f22
+       b       get_fs_sgl_done
+get_fs_sgl_f24:
+       mfc1    t0, $f24
+       b       get_fs_sgl_done
+get_fs_sgl_f26:
+       mfc1    t0, $f26
+       b       get_fs_sgl_done
+get_fs_sgl_f28:
+       mfc1    t0, $f28
+       b       get_fs_sgl_done
+get_fs_sgl_f30:
+       mfc1    t0, $f30
+get_fs_sgl_done:
+       srl     t1, t0, 23                      # get exponent
+       and     t1, t1, 0xFF
+       and     t2, t0, 0x7FFFFF                # get fraction
+       srl     t0, t0, 31                      # get sign
+       bne     t1, SEXP_INF, 1f                # is it a signalling NAN?
+       and     v0, t2, SSIGNAL_NAN
+       bne     v0, zero, invalid_s
+1:
+       j       ra
+END(get_fs_sgl)
+
+/*----------------------------------------------------------------------------
+ * get_fs_dbl --
+ *
+ *     Read (double precision) the FS register (bits 15-11) and
+ *     break up into fields.
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Results:
+ *     t0      contains the sign
+ *     t1      contains the (biased) exponent
+ *     t2      contains the fraction
+ *     t3      contains the remaining fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(get_fs_dbl)
+       srl     a3, a0, 12 - 2                  # get FS field (even regs only)
+       and     a3, a3, 0xF << 2                # mask FS field
+       lw      a3, get_fs_dbl_tbl(a3)          # switch on register number
+       j       a3
+
+       .rdata
+get_fs_dbl_tbl:
+       .word   get_fs_dbl_f0
+       .word   get_fs_dbl_f2
+       .word   get_fs_dbl_f4
+       .word   get_fs_dbl_f6
+       .word   get_fs_dbl_f8
+       .word   get_fs_dbl_f10
+       .word   get_fs_dbl_f12
+       .word   get_fs_dbl_f14
+       .word   get_fs_dbl_f16
+       .word   get_fs_dbl_f18
+       .word   get_fs_dbl_f20
+       .word   get_fs_dbl_f22
+       .word   get_fs_dbl_f24
+       .word   get_fs_dbl_f26
+       .word   get_fs_dbl_f28
+       .word   get_fs_dbl_f30
+       .text
+
+get_fs_dbl_f0:
+       mfc1    t3, $f0
+       mfc1    t0, $f1
+       b       get_fs_dbl_done
+get_fs_dbl_f2:
+       mfc1    t3, $f2
+       mfc1    t0, $f3
+       b       get_fs_dbl_done
+get_fs_dbl_f4:
+       mfc1    t3, $f4
+       mfc1    t0, $f5
+       b       get_fs_dbl_done
+get_fs_dbl_f6:
+       mfc1    t3, $f6
+       mfc1    t0, $f7
+       b       get_fs_dbl_done
+get_fs_dbl_f8:
+       mfc1    t3, $f8
+       mfc1    t0, $f9
+       b       get_fs_dbl_done
+get_fs_dbl_f10:
+       mfc1    t3, $f10
+       mfc1    t0, $f11
+       b       get_fs_dbl_done
+get_fs_dbl_f12:
+       mfc1    t3, $f12
+       mfc1    t0, $f13
+       b       get_fs_dbl_done
+get_fs_dbl_f14:
+       mfc1    t3, $f14
+       mfc1    t0, $f15
+       b       get_fs_dbl_done
+get_fs_dbl_f16:
+       mfc1    t3, $f16
+       mfc1    t0, $f17
+       b       get_fs_dbl_done
+get_fs_dbl_f18:
+       mfc1    t3, $f18
+       mfc1    t0, $f19
+       b       get_fs_dbl_done
+get_fs_dbl_f20:
+       mfc1    t3, $f20
+       mfc1    t0, $f21
+       b       get_fs_dbl_done
+get_fs_dbl_f22:
+       mfc1    t3, $f22
+       mfc1    t0, $f23
+       b       get_fs_dbl_done
+get_fs_dbl_f24:
+       mfc1    t3, $f24
+       mfc1    t0, $f25
+       b       get_fs_dbl_done
+get_fs_dbl_f26:
+       mfc1    t3, $f26
+       mfc1    t0, $f27
+       b       get_fs_dbl_done
+get_fs_dbl_f28:
+       mfc1    t3, $f28
+       mfc1    t0, $f29
+       b       get_fs_dbl_done
+get_fs_dbl_f30:
+       mfc1    t3, $f30
+       mfc1    t0, $f31
+get_fs_dbl_done:
+       srl     t1, t0, 20                      # get exponent
+       and     t1, t1, 0x7FF
+       and     t2, t0, 0xFFFFF                 # get fraction
+       srl     t0, t0, 31                      # get sign
+       bne     t1, DEXP_INF, 1f                # is it a signalling NAN?
+       and     v0, t2, DSIGNAL_NAN
+       bne     v0, zero, invalid_d
+1:
+       j       ra
+END(get_fs_dbl)
+
+/*----------------------------------------------------------------------------
+ * get_fs_int --
+ *
+ *     Read (integer) the FS register (bits 15-11).
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Results:
+ *     t0      contains the sign
+ *     t2      contains the fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(get_fs_int)
+       srl     a3, a0, 12 - 2                  # get FS field (even regs only)
+       and     a3, a3, 0xF << 2                # mask FS field
+       lw      a3, get_fs_int_tbl(a3)          # switch on register number
+       j       a3
+
+       .rdata
+get_fs_int_tbl:
+       .word   get_fs_int_f0
+       .word   get_fs_int_f2
+       .word   get_fs_int_f4
+       .word   get_fs_int_f6
+       .word   get_fs_int_f8
+       .word   get_fs_int_f10
+       .word   get_fs_int_f12
+       .word   get_fs_int_f14
+       .word   get_fs_int_f16
+       .word   get_fs_int_f18
+       .word   get_fs_int_f20
+       .word   get_fs_int_f22
+       .word   get_fs_int_f24
+       .word   get_fs_int_f26
+       .word   get_fs_int_f28
+       .word   get_fs_int_f30
+       .text
+
+get_fs_int_f0:
+       mfc1    t2, $f0
+       b       get_fs_int_done
+get_fs_int_f2:
+       mfc1    t2, $f2
+       b       get_fs_int_done
+get_fs_int_f4:
+       mfc1    t2, $f4
+       b       get_fs_int_done
+get_fs_int_f6:
+       mfc1    t2, $f6
+       b       get_fs_int_done
+get_fs_int_f8:
+       mfc1    t2, $f8
+       b       get_fs_int_done
+get_fs_int_f10:
+       mfc1    t2, $f10
+       b       get_fs_int_done
+get_fs_int_f12:
+       mfc1    t2, $f12
+       b       get_fs_int_done
+get_fs_int_f14:
+       mfc1    t2, $f14
+       b       get_fs_int_done
+get_fs_int_f16:
+       mfc1    t2, $f16
+       b       get_fs_int_done
+get_fs_int_f18:
+       mfc1    t2, $f18
+       b       get_fs_int_done
+get_fs_int_f20:
+       mfc1    t2, $f20
+       b       get_fs_int_done
+get_fs_int_f22:
+       mfc1    t2, $f22
+       b       get_fs_int_done
+get_fs_int_f24:
+       mfc1    t2, $f24
+       b       get_fs_int_done
+get_fs_int_f26:
+       mfc1    t2, $f26
+       b       get_fs_int_done
+get_fs_int_f28:
+       mfc1    t2, $f28
+       b       get_fs_int_done
+get_fs_int_f30:
+       mfc1    t2, $f30
+get_fs_int_done:
+       srl     t0, t2, 31              # init the sign bit
+       bge     t2, zero, 1f
+       negu    t2
+1:
+       j       ra
+END(get_fs_int)
+
+/*----------------------------------------------------------------------------
+ * get_ft_sgl --
+ *
+ *     Read (single precision) the FT register (bits 20-16) and
+ *     break up into fields.
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Results:
+ *     t4      contains the sign
+ *     t5      contains the (biased) exponent
+ *     t6      contains the fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(get_ft_sgl)
+       srl     a3, a0, 17 - 2                  # get FT field (even regs only)
+       and     a3, a3, 0xF << 2                # mask FT field
+       lw      a3, get_ft_sgl_tbl(a3)          # switch on register number
+       j       a3
+
+       .rdata
+get_ft_sgl_tbl:
+       .word   get_ft_sgl_f0
+       .word   get_ft_sgl_f2
+       .word   get_ft_sgl_f4
+       .word   get_ft_sgl_f6
+       .word   get_ft_sgl_f8
+       .word   get_ft_sgl_f10
+       .word   get_ft_sgl_f12
+       .word   get_ft_sgl_f14
+       .word   get_ft_sgl_f16
+       .word   get_ft_sgl_f18
+       .word   get_ft_sgl_f20
+       .word   get_ft_sgl_f22
+       .word   get_ft_sgl_f24
+       .word   get_ft_sgl_f26
+       .word   get_ft_sgl_f28
+       .word   get_ft_sgl_f30
+       .text
+
+get_ft_sgl_f0:
+       mfc1    t4, $f0
+       b       get_ft_sgl_done
+get_ft_sgl_f2:
+       mfc1    t4, $f2
+       b       get_ft_sgl_done
+get_ft_sgl_f4:
+       mfc1    t4, $f4
+       b       get_ft_sgl_done
+get_ft_sgl_f6:
+       mfc1    t4, $f6
+       b       get_ft_sgl_done
+get_ft_sgl_f8:
+       mfc1    t4, $f8
+       b       get_ft_sgl_done
+get_ft_sgl_f10:
+       mfc1    t4, $f10
+       b       get_ft_sgl_done
+get_ft_sgl_f12:
+       mfc1    t4, $f12
+       b       get_ft_sgl_done
+get_ft_sgl_f14:
+       mfc1    t4, $f14
+       b       get_ft_sgl_done
+get_ft_sgl_f16:
+       mfc1    t4, $f16
+       b       get_ft_sgl_done
+get_ft_sgl_f18:
+       mfc1    t4, $f18
+       b       get_ft_sgl_done
+get_ft_sgl_f20:
+       mfc1    t4, $f20
+       b       get_ft_sgl_done
+get_ft_sgl_f22:
+       mfc1    t4, $f22
+       b       get_ft_sgl_done
+get_ft_sgl_f24:
+       mfc1    t4, $f24
+       b       get_ft_sgl_done
+get_ft_sgl_f26:
+       mfc1    t4, $f26
+       b       get_ft_sgl_done
+get_ft_sgl_f28:
+       mfc1    t4, $f28
+       b       get_ft_sgl_done
+get_ft_sgl_f30:
+       mfc1    t4, $f30
+get_ft_sgl_done:
+       srl     t5, t4, 23                      # get exponent
+       and     t5, t5, 0xFF
+       and     t6, t4, 0x7FFFFF                # get fraction
+       srl     t4, t4, 31                      # get sign
+       bne     t5, SEXP_INF, 1f                # is it a signalling NAN?
+       and     v0, t6, SSIGNAL_NAN
+       bne     v0, zero, invalid_s
+1:
+       j       ra
+END(get_ft_sgl)
+
+/*----------------------------------------------------------------------------
+ * get_ft_dbl --
+ *
+ *     Read (double precision) the FT register (bits 20-16) and
+ *     break up into fields.
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Results:
+ *     t4      contains the sign
+ *     t5      contains the (biased) exponent
+ *     t6      contains the fraction
+ *     t7      contains the remaining fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(get_ft_dbl)
+       srl     a3, a0, 17 - 2                  # get FT field (even regs only)
+       and     a3, a3, 0xF << 2                # mask FT field
+       lw      a3, get_ft_dbl_tbl(a3)          # switch on register number
+       j       a3
+
+       .rdata
+get_ft_dbl_tbl:
+       .word   get_ft_dbl_f0
+       .word   get_ft_dbl_f2
+       .word   get_ft_dbl_f4
+       .word   get_ft_dbl_f6
+       .word   get_ft_dbl_f8
+       .word   get_ft_dbl_f10
+       .word   get_ft_dbl_f12
+       .word   get_ft_dbl_f14
+       .word   get_ft_dbl_f16
+       .word   get_ft_dbl_f18
+       .word   get_ft_dbl_f20
+       .word   get_ft_dbl_f22
+       .word   get_ft_dbl_f24
+       .word   get_ft_dbl_f26
+       .word   get_ft_dbl_f28
+       .word   get_ft_dbl_f30
+       .text
+
+get_ft_dbl_f0:
+       mfc1    t7, $f0
+       mfc1    t4, $f1
+       b       get_ft_dbl_done
+get_ft_dbl_f2:
+       mfc1    t7, $f2
+       mfc1    t4, $f3
+       b       get_ft_dbl_done
+get_ft_dbl_f4:
+       mfc1    t7, $f4
+       mfc1    t4, $f5
+       b       get_ft_dbl_done
+get_ft_dbl_f6:
+       mfc1    t7, $f6
+       mfc1    t4, $f7
+       b       get_ft_dbl_done
+get_ft_dbl_f8:
+       mfc1    t7, $f8
+       mfc1    t4, $f9
+       b       get_ft_dbl_done
+get_ft_dbl_f10:
+       mfc1    t7, $f10
+       mfc1    t4, $f11
+       b       get_ft_dbl_done
+get_ft_dbl_f12:
+       mfc1    t7, $f12
+       mfc1    t4, $f13
+       b       get_ft_dbl_done
+get_ft_dbl_f14:
+       mfc1    t7, $f14
+       mfc1    t4, $f15
+       b       get_ft_dbl_done
+get_ft_dbl_f16:
+       mfc1    t7, $f16
+       mfc1    t4, $f17
+       b       get_ft_dbl_done
+get_ft_dbl_f18:
+       mfc1    t7, $f18
+       mfc1    t4, $f19
+       b       get_ft_dbl_done
+get_ft_dbl_f20:
+       mfc1    t7, $f20
+       mfc1    t4, $f21
+       b       get_ft_dbl_done
+get_ft_dbl_f22:
+       mfc1    t7, $f22
+       mfc1    t4, $f23
+       b       get_ft_dbl_done
+get_ft_dbl_f24:
+       mfc1    t7, $f24
+       mfc1    t4, $f25
+       b       get_ft_dbl_done
+get_ft_dbl_f26:
+       mfc1    t7, $f26
+       mfc1    t4, $f27
+       b       get_ft_dbl_done
+get_ft_dbl_f28:
+       mfc1    t7, $f28
+       mfc1    t4, $f29
+       b       get_ft_dbl_done
+get_ft_dbl_f30:
+       mfc1    t7, $f30
+       mfc1    t4, $f31
+get_ft_dbl_done:
+       srl     t5, t4, 20                      # get exponent
+       and     t5, t5, 0x7FF
+       and     t6, t4, 0xFFFFF                 # get fraction
+       srl     t4, t4, 31                      # get sign
+       bne     t5, DEXP_INF, 1f                # is it a signalling NAN?
+       and     v0, t6, DSIGNAL_NAN
+       bne     v0, zero, invalid_d
+1:
+       j       ra
+END(get_ft_dbl)
+
+/*----------------------------------------------------------------------------
+ * set_fd_sgl --
+ *
+ *     Write (single precision) the FD register (bits 10-6).
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Arguments:
+ *     a0      contains the FP instruction
+ *     t0      contains the sign
+ *     t1      contains the (biased) exponent
+ *     t2      contains the fraction
+ *
+ * set_fd_word --
+ *
+ *     Write (integer) the FD register (bits 10-6).
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Arguments:
+ *     a0      contains the FP instruction
+ *     t2      contains the integer
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(set_fd_sgl)
+       sll     t0, t0, 31                      # position sign
+       sll     t1, t1, 23                      # position exponent
+       or      t2, t2, t0
+       or      t2, t2, t1
+ALEAF(set_fd_word)
+       srl     a3, a0, 7 - 2                   # get FD field (even regs only)
+       and     a3, a3, 0xF << 2                # mask FT field
+       lw      a3, set_fd_sgl_tbl(a3)          # switch on register number
+       j       a3
+
+       .rdata
+set_fd_sgl_tbl:
+       .word   set_fd_sgl_f0
+       .word   set_fd_sgl_f2
+       .word   set_fd_sgl_f4
+       .word   set_fd_sgl_f6
+       .word   set_fd_sgl_f8
+       .word   set_fd_sgl_f10
+       .word   set_fd_sgl_f12
+       .word   set_fd_sgl_f14
+       .word   set_fd_sgl_f16
+       .word   set_fd_sgl_f18
+       .word   set_fd_sgl_f20
+       .word   set_fd_sgl_f22
+       .word   set_fd_sgl_f24
+       .word   set_fd_sgl_f26
+       .word   set_fd_sgl_f28
+       .word   set_fd_sgl_f30
+       .text
+
+set_fd_sgl_f0:
+       mtc1    t2, $f0
+       j       ra
+set_fd_sgl_f2:
+       mtc1    t2, $f2
+       j       ra
+set_fd_sgl_f4:
+       mtc1    t2, $f4
+       j       ra
+set_fd_sgl_f6:
+       mtc1    t2, $f6
+       j       ra
+set_fd_sgl_f8:
+       mtc1    t2, $f8
+       j       ra
+set_fd_sgl_f10:
+       mtc1    t2, $f10
+       j       ra
+set_fd_sgl_f12:
+       mtc1    t2, $f12
+       j       ra
+set_fd_sgl_f14:
+       mtc1    t2, $f14
+       j       ra
+set_fd_sgl_f16:
+       mtc1    t2, $f16
+       j       ra
+set_fd_sgl_f18:
+       mtc1    t2, $f18
+       j       ra
+set_fd_sgl_f20:
+       mtc1    t2, $f20
+       j       ra
+set_fd_sgl_f22:
+       mtc1    t2, $f22
+       j       ra
+set_fd_sgl_f24:
+       mtc1    t2, $f24
+       j       ra
+set_fd_sgl_f26:
+       mtc1    t2, $f26
+       j       ra
+set_fd_sgl_f28:
+       mtc1    t2, $f28
+       j       ra
+set_fd_sgl_f30:
+       mtc1    t2, $f30
+       j       ra
+END(set_fd_sgl)
+
+/*----------------------------------------------------------------------------
+ * set_fd_dbl --
+ *
+ *     Write (double precision) the FT register (bits 10-6).
+ *     This is an internal routine used by MachEmulateFP only.
+ *
+ * Arguments:
+ *     a0      contains the FP instruction
+ *     t0      contains the sign
+ *     t1      contains the (biased) exponent
+ *     t2      contains the fraction
+ *     t3      contains the remaining fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(set_fd_dbl)
+       sll     t0, t0, 31                      # set sign
+       sll     t1, t1, 20                      # set exponent
+       or      t0, t0, t1
+       or      t0, t0, t2                      # set fraction
+       srl     a3, a0, 7 - 2                   # get FD field (even regs only)
+       and     a3, a3, 0xF << 2                # mask FD field
+       lw      a3, set_fd_dbl_tbl(a3)          # switch on register number
+       j       a3
+
+       .rdata
+set_fd_dbl_tbl:
+       .word   set_fd_dbl_f0
+       .word   set_fd_dbl_f2
+       .word   set_fd_dbl_f4
+       .word   set_fd_dbl_f6
+       .word   set_fd_dbl_f8
+       .word   set_fd_dbl_f10
+       .word   set_fd_dbl_f12
+       .word   set_fd_dbl_f14
+       .word   set_fd_dbl_f16
+       .word   set_fd_dbl_f18
+       .word   set_fd_dbl_f20
+       .word   set_fd_dbl_f22
+       .word   set_fd_dbl_f24
+       .word   set_fd_dbl_f26
+       .word   set_fd_dbl_f28
+       .word   set_fd_dbl_f30
+       .text
+
+set_fd_dbl_f0:
+       mtc1    t3, $f0
+       mfc1    t0, $f1
+       j       ra
+set_fd_dbl_f2:
+       mtc1    t3, $f2
+       mfc1    t0, $f3
+       j       ra
+set_fd_dbl_f4:
+       mtc1    t3, $f4
+       mfc1    t0, $f5
+       j       ra
+set_fd_dbl_f6:
+       mtc1    t3, $f6
+       mfc1    t0, $f7
+       j       ra
+set_fd_dbl_f8:
+       mtc1    t3, $f8
+       mfc1    t0, $f9
+       j       ra
+set_fd_dbl_f10:
+       mtc1    t3, $f10
+       mfc1    t0, $f11
+       j       ra
+set_fd_dbl_f12:
+       mtc1    t3, $f12
+       mfc1    t0, $f13
+       j       ra
+set_fd_dbl_f14:
+       mtc1    t3, $f14
+       mfc1    t0, $f15
+       j       ra
+set_fd_dbl_f16:
+       mtc1    t3, $f16
+       mfc1    t0, $f17
+       j       ra
+set_fd_dbl_f18:
+       mtc1    t3, $f18
+       mfc1    t0, $f19
+       j       ra
+set_fd_dbl_f20:
+       mtc1    t3, $f20
+       mfc1    t0, $f21
+       j       ra
+set_fd_dbl_f22:
+       mtc1    t3, $f22
+       mfc1    t0, $f23
+       j       ra
+set_fd_dbl_f24:
+       mtc1    t3, $f24
+       mfc1    t0, $f25
+       j       ra
+set_fd_dbl_f26:
+       mtc1    t3, $f26
+       mfc1    t0, $f27
+       j       ra
+set_fd_dbl_f28:
+       mtc1    t3, $f28
+       mfc1    t0, $f29
+       j       ra
+set_fd_dbl_f30:
+       mtc1    t3, $f30
+       mfc1    t0, $f31
+       j       ra
+END(set_fd_dbl)
+
+/*----------------------------------------------------------------------------
+ * renorm_fs_s --
+ *
+ * Results:
+ *     t1      unbiased exponent
+ *     t2      normalized fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(renorm_fs_s)
+/*
+ * Find out how many leading zero bits are in t2 and put in t9.
+ */
+       move    v0, t2
+       move    t9, zero
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t2 the correct number of bits.
+ */
+1:
+       subu    t9, t9, SLEAD_ZEROS     # don't count normal leading zeros
+       li      t1, SEXP_MIN
+       subu    t1, t1, t9              # adjust exponent
+       sll     t2, t2, t9
+       j       ra
+END(renorm_fs_s)
+
+/*----------------------------------------------------------------------------
+ * renorm_fs_d --
+ *
+ * Results:
+ *     t1      unbiased exponent
+ *     t2,t3   normalized fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(renorm_fs_d)
+/*
+ * Find out how many leading zero bits are in t2,t3 and put in t9.
+ */
+       move    v0, t2
+       move    t9, zero
+       bne     t2, zero, 1f
+       move    v0, t3
+       addu    t9, 32
+1:
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t2,t3 the correct number of bits.
+ */
+1:
+       subu    t9, t9, DLEAD_ZEROS     # don't count normal leading zeros
+       li      t1, DEXP_MIN
+       subu    t1, t1, t9              # adjust exponent
+       li      v0, 32
+       blt     t9, v0, 1f
+       subu    t9, t9, v0              # shift fraction left >= 32 bits
+       sll     t2, t3, t9
+       move    t3, zero
+       j       ra
+1:
+       subu    v0, v0, t9              # shift fraction left < 32 bits
+       sll     t2, t2, t9
+       srl     v1, t3, v0
+       or      t2, t2, v1
+       sll     t3, t3, t9
+       j       ra
+END(renorm_fs_d)
+
+/*----------------------------------------------------------------------------
+ * renorm_ft_s --
+ *
+ * Results:
+ *     t5      unbiased exponent
+ *     t6      normalized fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(renorm_ft_s)
+/*
+ * Find out how many leading zero bits are in t6 and put in t9.
+ */
+       move    v0, t6
+       move    t9, zero
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t6 the correct number of bits.
+ */
+1:
+       subu    t9, t9, SLEAD_ZEROS     # don't count normal leading zeros
+       li      t5, SEXP_MIN
+       subu    t5, t5, t9              # adjust exponent
+       sll     t6, t6, t9
+       j       ra
+END(renorm_ft_s)
+
+/*----------------------------------------------------------------------------
+ * renorm_ft_d --
+ *
+ * Results:
+ *     t5      unbiased exponent
+ *     t6,t7   normalized fraction
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(renorm_ft_d)
+/*
+ * Find out how many leading zero bits are in t6,t7 and put in t9.
+ */
+       move    v0, t6
+       move    t9, zero
+       bne     t6, zero, 1f
+       move    v0, t7
+       addu    t9, 32
+1:
+       srl     v1, v0, 16
+       bne     v1, zero, 1f
+       addu    t9, 16
+       sll     v0, 16
+1:
+       srl     v1, v0, 24
+       bne     v1, zero, 1f
+       addu    t9, 8
+       sll     v0, 8
+1:
+       srl     v1, v0, 28
+       bne     v1, zero, 1f
+       addu    t9, 4
+       sll     v0, 4
+1:
+       srl     v1, v0, 30
+       bne     v1, zero, 1f
+       addu    t9, 2
+       sll     v0, 2
+1:
+       srl     v1, v0, 31
+       bne     v1, zero, 1f
+       addu    t9, 1
+/*
+ * Now shift t6,t7 the correct number of bits.
+ */
+1:
+       subu    t9, t9, DLEAD_ZEROS     # don't count normal leading zeros
+       li      t5, DEXP_MIN
+       subu    t5, t5, t9              # adjust exponent
+       li      v0, 32
+       blt     t9, v0, 1f
+       subu    t9, t9, v0              # shift fraction left >= 32 bits
+       sll     t6, t7, t9
+       move    t7, zero
+       j       ra
+1:
+       subu    v0, v0, t9              # shift fraction left < 32 bits
+       sll     t6, t6, t9
+       srl     v1, t7, v0
+       or      t6, t6, v1
+       sll     t7, t7, t9
+       j       ra
+END(renorm_ft_d)
diff --git a/usr/src/sys/pmax/pmax/genassym.c b/usr/src/sys/pmax/pmax/genassym.c
new file mode 100644 (file)
index 0000000..0088402
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)genassym.c  7.1 (Berkeley) %G%
+ */
+
+#define KERNEL
+
+#include "param.h"
+#include "buf.h"
+#include "map.h"
+#include "proc.h"
+#include "mbuf.h"
+#include "user.h"
+#include "machine/reg.h"
+#include "machine/pmap.h"
+
+main()
+{
+       register struct proc *p = (struct proc *)0;
+       register struct user *up = (struct user *)0;
+       register pmap_hash_t hp = (pmap_hash_t)PMAP_HASH_UADDR;
+       register struct vmmeter *vm = (struct vmmeter *)0;
+       register int size, s, n;
+
+       printf("#define\tP_LINK %d\n", &p->p_link);
+       printf("#define\tP_RLINK %d\n", &p->p_rlink);
+       printf("#define\tP_PRI %d\n", &p->p_pri);
+       printf("#define\tP_ADDR %d\n", &p->p_addr);
+       printf("#define\tP_UPTE %d\n", p->p_md.md_upte);
+       printf("#define\tU_PCB_REGS %d\n", up->u_pcb.pcb_regs);
+       printf("#define\tU_PCB_FPREGS %d\n", &up->u_pcb.pcb_regs[F0]);
+       printf("#define\tU_PCB_CONTEXT %d\n", &up->u_pcb.pcb_context);
+       printf("#define\tU_PCB_ONFAULT %d\n", &up->u_pcb.pcb_onfault);
+       printf("#define\tPMAP_HASH_LOW_OFFSET 0x%x\n", &hp->low);
+       printf("#define\tPMAP_HASH_HIGH_OFFSET 0x%x\n", &hp->high);
+       printf("#define\tPMAP_HASH_KPAGES %d\n", PMAP_HASH_KPAGES);
+       printf("#define\tPMAP_HASH_KADDR 0x%x\n", PMAP_HASH_KADDR);
+       printf("#define\tPMAP_HASH_SIZE_SHIFT %d\n", PMAP_HASH_SIZE_SHIFT);
+       printf("#define\tPMAP_HASH_SHIFT1 %d\n", PMAP_HASH_SHIFT1);
+       printf("#define\tPMAP_HASH_SHIFT2 %d\n", PMAP_HASH_SHIFT2);
+       printf("#define\tPMAP_HASH_MASK1 0x%x\n", PMAP_HASH_MASK1);
+       printf("#define\tPMAP_HASH_MASK2 0x%x\n", PMAP_HASH_MASK2);
+       printf("#define\tV_SWTCH %d\n", &vm->v_swtch);
+       printf("#define\tSIGILL %d\n", SIGILL);
+       printf("#define\tSIGFPE %d\n", SIGFPE);
+       exit(0);
+}
diff --git a/usr/src/sys/pmax/pmax/locore.s b/usr/src/sys/pmax/pmax/locore.s
new file mode 100644 (file)
index 0000000..e757775
--- /dev/null
@@ -0,0 +1,2822 @@
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Digital Equipment Corporation and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * Copyright (C) 1989 Digital Equipment Corporation.
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies.
+ * Digital Equipment Corporation makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
+ *     v 1.1 89/07/11 17:55:04 nelson Exp $ SPRITE (DECWRL)
+ * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
+ *     v 9.2 90/01/29 18:00:39 shirriff Exp $ SPRITE (DECWRL)
+ * from: $Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
+ *     v 1.1 89/07/10 14:27:41 nelson Exp $ SPRITE (DECWRL)
+ *
+ *     @(#)locore.s    7.1 (Berkeley) %G%
+ */
+
+/*
+ *     Contains code that is the first executed at boot time plus
+ *     assembly language support routines.
+ */
+
+#include "errno.h"
+
+#include "machine/regdef.h"
+#include "machine/param.h"
+#include "machine/vmparam.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+#include "machine/machAsmDefs.h"
+#include "pte.h"
+#include "assym.h"
+
+/*
+ * Amount to take off of the stack for the benefit of the debugger.
+ */
+#define START_FRAME    ((4 * 4) + 4 + 4)
+
+       .globl  start
+start:
+       .set    noreorder
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+       li      t1, MACH_RESERVED_ADDR          # invalid address
+       mtc0    t1, MACH_COP_0_TLB_HI           # Mark entry high as invalid
+       mtc0    zero, MACH_COP_0_TLB_LOW        # Zero out low entry.
+/*
+ * Clear the TLB (just to be safe).
+ * Align the starting value (t1), the increment (t2) and the upper bound (t3).
+ */
+       move    t1, zero
+       li      t2, 1 << VMMACH_TLB_INDEX_SHIFT
+       li      t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
+1:
+       mtc0    t1, MACH_COP_0_TLB_INDEX        # Set the index register.
+       addu    t1, t1, t2                      # Increment index.
+       bne     t1, t3, 1b                      # NB: always executes next
+       tlbwi                                   # Write the TLB entry.
+
+       li      sp, MACH_CODE_START - START_FRAME
+       la      gp, _gp
+       sw      zero, START_FRAME - 4(sp)       # Zero out old ra for debugger
+       jal     mach_init                       # mach_init(argc, argv, envp)
+       sw      zero, START_FRAME - 8(sp)       # Zero out old fp for debugger
+
+       li      t0, MACH_SR_COP_1_BIT           # Disable interrupts and
+       mtc0    t0, MACH_COP_0_STATUS_REG       #   enable the coprocessor
+       li      sp, KERNELSTACK - START_FRAME   # switch to standard stack
+       mfc0    t0, MACH_COP_0_PRID             # read processor ID register
+       cfc1    t1, MACH_FPC_ID                 # read FPU ID register
+       sw      t0, cpu                         # save PRID register
+       sw      t1, fpu                         # save FPU ID register
+       jal     main                            # main()
+       nop
+
+/* proc[1] == /etc/init now running here; run icode */
+       li      v0, PSL_USERSET
+       mtc0    v0, MACH_COP_0_STATUS_REG       # switch to user mode
+       j       zero                            # icode is at address zero
+       rfe
+       .set    reorder
+
+/*
+ * This code is copied to user data space as the first program to run.
+ * Basically, it just calls execve();
+ */
+       .globl  icode
+icode:
+       .set    noreorder
+       li      a1, (9 * 4)             # address of 'icode_argv'
+       addu    a0, a1, (3 * 4)         # address of 'icode_fname'
+       move    a2, zero                # no environment
+       li      v0, 59                  # code for execve system call
+       syscall
+       li      v0, 1                   # code for exit system call
+       syscall                         # execve failed: call exit()
+1:     b       1b                      # loop if exit returns
+       nop
+       .set    reorder
+icode_argv:
+       .word   (12 * 4)                # address of 'icode_fname'
+       .word   (15 * 4)                # address of 'icodeEnd'
+       .word   0
+icode_fname:
+       .asciiz "/sbin/init"            # occupies 3 words
+       .align  2
+       .globl  icodeEnd
+icodeEnd:
+
+       .sdata
+       .align  2
+       .globl  szicode
+szicode:
+       .word   (9 + 3 + 3) * 4         # compute icodeEnd - icode
+       .text
+
+/*
+ * Primitives
+ */
+
+/*
+ * This table is indexed by u.u_pcb.pcb_onfault in trap().
+ * The reason for using this table rather than storing an address in
+ * u.u_pcb.pcb_onfault is simply to make the code faster.
+ */
+       .globl  onfault_table
+       .data   
+       .align  2
+onfault_table:
+       .word   0               # invalid index number
+#define BADERR         1
+       .word   baderr
+#define ADDUPCERR      2
+       .word   addupcerr
+#define COPYERR                3
+       .word   copyerr
+#define FSWBERR                4
+       .word   fswberr
+       .text
+
+/*
+ * See if access to addr with a len type instruction causes a machine check.
+ * len is length of access (1=byte, 2=short, 4=long)
+ *
+ * badaddr(addr, len)
+ *     char *addr;
+ *     int len;
+ */
+LEAF(badaddr)
+       li      v0, BADERR
+       sw      v0, UADDR+U_PCB_ONFAULT
+       bne     a1, 1, 2f
+       lbu     v0, (a0)
+       b       5f
+2:
+       bne     a1, 2, 4f
+       lhu     v0, (a0)
+       b       5f
+4:
+       lw      v0, (a0)
+5:
+       sw      zero, UADDR+U_PCB_ONFAULT
+       move    v0, zero                # made it w/o errors
+       j       ra
+baderr:
+       li      v0, 1                   # trap sends us here
+       j       ra
+END(badaddr)
+
+/*
+ * update profiling information for the user
+ * addupc(pc, pr, ticks)
+ *     unsigned pc;
+ *     struct uprof *pr;
+ *     int ticks;
+ */
+LEAF(addupc)
+       lw      v1, 8(a1)               # get pr->pr_off
+       subu    a0, a0, v1              # pc -= pr->pr_off
+       blt     a0, zero, 1f            # ignore if less than zero
+       lw      v0, 12(a1)              # get pr->pr_scale
+       multu   v0, a0                  # compute index into count table
+       mflo    v0
+       srl     v0, v0, 16              # shift v1,v0 >> 16
+       mfhi    v1
+       sll     v1, v1, 16
+       or      v0, v0, v1
+       addu    v0, v0, 1               # round up and
+       and     v0, v0, ~1              #   align to short boundary
+       lw      v1, 4(a1)               # get pr->pr_size
+       bgeu    v0, v1, 1f              # ignore if index >= size
+       lw      v1, 0(a1)               # get pr->pr_base
+       addu    v0, v0, v1              # add index and base
+       li      v1, ADDUPCERR           # turn off profiling if fault
+       bltz    v0, addupcerr           # can this happen?
+       sw      v1, UADDR+U_PCB_ONFAULT
+       lh      v1, 0(v0)               # get old count
+       addu    v1, v1, a2              # add ticks
+       sh      v1, 0(v0)               # save new count
+       sw      zero, UADDR+U_PCB_ONFAULT
+1:
+       j       ra
+addupcerr:
+       sw      zero, 12(a1)            # pr->pr_scale = 0
+       j       ra
+END(addupc)
+
+/*
+ * netorder = htonl(hostorder)
+ * hostorder = ntohl(netorder)
+ */
+LEAF(htonl)                            # a0 = 0x11223344, return 0x44332211
+ALEAF(ntohl)
+       srl     v1, a0, 24              # v1 = 0x00000011
+       sll     v0, a0, 24              # v0 = 0x44000000
+       or      v0, v0, v1
+       and     v1, a0, 0xff00
+       sll     v1, v1, 8               # v1 = 0x00330000
+       or      v0, v0, v1
+       srl     v1, a0, 8
+       and     v1, v1, 0xff00          # v1 = 0x00002200
+       or      v0, v0, v1
+       j       ra
+END(htonl)
+
+/*
+ * netorder = htons(hostorder)
+ * hostorder = ntohs(netorder)
+ */
+LEAF(htons)
+ALEAF(ntohs)
+       srl     v0, a0, 8
+       and     v0, v0, 0xff
+       sll     v1, a0, 8
+       and     v1, v1, 0xff00
+       or      v0, v0, v1
+       j       ra
+END(htons)
+
+/*
+ * bit = ffs(value)
+ */
+LEAF(ffs)
+       move    v0, zero
+       beq     a0, zero, 2f
+1:
+       and     v1, a0, 1               # bit set?
+       addu    v0, v0, 1
+       srl     a0, a0, 1
+       beq     v1, zero, 1b            # no, continue
+2:
+       j       ra
+END(ffs)
+
+/*
+ * strlen(str)
+ */
+LEAF(strlen)
+       addu    v1, a0, 1
+1:
+       lb      v0, 0(a0)               # get byte from string
+       addu    a0, a0, 1               # increment pointer
+       bne     v0, zero, 1b            # continue if not end
+       subu    v0, a0, v1              # compute length - 1 for '\0' char
+       j       ra
+END(strlen)
+
+/*
+ * bzero(s1, n)
+ */
+LEAF(bzero)
+ALEAF(blkclr)
+       .set    noreorder
+       blt     a1, 12, smallclr        # small amount to clear?
+       subu    a3, zero, a0            # compute # bytes to word align address
+       and     a3, a3, 3
+       beq     a3, zero, 1f            # skip if word aligned
+       subu    a1, a1, a3              # subtract from remaining count
+       swr     zero, 0(a0)             # clear 1, 2, or 3 bytes to align
+       addu    a0, a0, a3
+1:
+       and     v0, a1, 3               # compute number of words left
+       subu    a3, a1, v0
+       move    a1, v0
+       addu    a3, a3, a0              # compute ending address
+2:
+       addu    a0, a0, 4               # clear words
+       bne     a0, a3, 2b              #   unrolling loop doesn't help
+       sw      zero, -4(a0)            #   since we're limited by memory speed
+smallclr:
+       ble     a1, zero, 2f
+       addu    a3, a1, a0              # compute ending address
+1:
+       addu    a0, a0, 1               # clear bytes
+       bne     a0, a3, 1b
+       sb      zero, -1(a0)
+2:
+       j       ra
+       nop
+       .set    reorder
+END(bzero)
+
+/*
+ * bcmp(s1, s2, n)
+ */
+LEAF(bcmp)
+       .set    noreorder
+       blt     a2, 16, smallcmp        # is it worth any trouble?
+       xor     v0, a0, a1              # compare low two bits of addresses
+       and     v0, v0, 3
+       subu    a3, zero, a1            # compute # bytes to word align address
+       bne     v0, zero, unalignedcmp  # not possible to align addresses
+       and     a3, a3, 3
+
+       beq     a3, zero, 1f
+       subu    a2, a2, a3              # subtract from remaining count
+       move    v0, v1                  # init v0,v1 so unmodified bytes match
+       lwr     v0, 0(a0)               # read 1, 2, or 3 bytes
+       lwr     v1, 0(a1)
+       addu    a1, a1, a3
+       bne     v0, v1, nomatch
+       addu    a0, a0, a3
+1:
+       and     a3, a2, ~3              # compute number of whole words left
+       subu    a2, a2, a3              #   which has to be >= (16-3) & ~3
+       addu    a3, a3, a0              # compute ending address
+2:
+       lw      v0, 0(a0)               # compare words
+       lw      v1, 0(a1)
+       addu    a0, a0, 4
+       bne     v0, v1, nomatch
+       addu    a1, a1, 4
+       bne     a0, a3, 2b
+       nop
+       b       smallcmp                # finish remainder
+       nop
+unalignedcmp:
+       beq     a3, zero, 2f
+       subu    a2, a2, a3              # subtract from remaining count
+       addu    a3, a3, a0              # compute ending address
+1:
+       lbu     v0, 0(a0)               # compare bytes until a1 word aligned
+       lbu     v1, 0(a1)
+       addu    a0, a0, 1
+       bne     v0, v1, nomatch
+       addu    a1, a1, 1
+       bne     a0, a3, 1b
+       nop
+2:
+       and     a3, a2, ~3              # compute number of whole words left
+       subu    a2, a2, a3              #   which has to be >= (16-3) & ~3
+       addu    a3, a3, a0              # compute ending address
+3:
+       lwr     v0, 0(a0)               # compare words a0 unaligned, a1 aligned
+       lwl     v0, 3(a0)
+       lw      v1, 0(a1)
+       addu    a0, a0, 4
+       bne     v0, v1, nomatch
+       addu    a1, a1, 4
+       bne     a0, a3, 3b
+       nop
+smallcmp:
+       ble     a2, zero, match
+       addu    a3, a2, a0              # compute ending address
+1:
+       lbu     v0, 0(a0)
+       lbu     v1, 0(a1)
+       addu    a0, a0, 1
+       bne     v0, v1, nomatch
+       addu    a1, a1, 1
+       bne     a0, a3, 1b
+       nop
+match:
+       j       ra
+       move    v0, zero
+nomatch:
+       j       ra
+       li      v0, 1
+       .set    reorder
+END(bcmp)
+
+/*
+ * {ov}bcopy(from, to, len)
+ */
+LEAF(bcopy)
+ALEAF(ovbcopy)
+       .set    noreorder
+       addu    t0, a0, a2              # t0 = end of s1 region
+       sltu    t1, a1, t0
+       sltu    t2, a0, a1
+       and     t1, t1, t2              # t1 = true if from < to < (from+len)
+       beq     t1, zero, forward       # non overlapping, do forward copy
+       slt     t2, a2, 12              # check for small copy
+
+       ble     a2, zero, 2f
+       addu    t1, a1, a2              # t1 = end of to region
+1:
+       lb      v0, -1(t0)              # copy bytes backwards,
+       subu    t0, t0, 1               #   doesn't happen often so do slow way
+       subu    t1, t1, 1
+       bne     t0, a0, 1b
+       sb      v0, 0(t1)
+2:
+       j       ra
+       nop
+forward:
+       bne     t2, zero, smallcpy      # do a small bcopy
+       xor     v0, a0, a1              # compare low two bits of addresses
+       and     v0, v0, 3
+       subu    a3, zero, a1            # compute # bytes to word align address
+       beq     v0, zero, aligned       # addresses can be word aligned
+       and     a3, a3, 3
+
+       beq     a3, zero, 1f
+       subu    a2, a2, a3              # subtract from remaining count
+       lwr     v0, 0(a0)               # get next 4 bytes (unaligned)
+       lwl     v0, 3(a0)
+       addu    a0, a0, a3
+       swr     v0, 0(a1)               # store 1, 2, or 3 bytes to align a1
+       addu    a1, a1, a3
+1:
+       and     v0, a2, 3               # compute number of words left
+       subu    a3, a2, v0
+       move    a2, v0
+       addu    a3, a3, a0              # compute ending address
+2:
+       lwr     v0, 0(a0)               # copy words a0 unaligned, a1 aligned
+       lwl     v0, 3(a0)
+       addu    a0, a0, 4
+       addu    a1, a1, 4
+       bne     a0, a3, 2b
+       sw      v0, -4(a1)
+       b       smallcpy
+       nop
+aligned:
+       beq     a3, zero, 1f
+       subu    a2, a2, a3              # subtract from remaining count
+       lwr     v0, 0(a0)               # copy 1, 2, or 3 bytes to align
+       addu    a0, a0, a3
+       swr     v0, 0(a1)
+       addu    a1, a1, a3
+1:
+       and     v0, a2, 3               # compute number of whole words left
+       subu    a3, a2, v0
+       move    a2, v0
+       addu    a3, a3, a0              # compute ending address
+2:
+       lw      v0, 0(a0)               # copy words
+       addu    a0, a0, 4
+       addu    a1, a1, 4
+       bne     a0, a3, 2b
+       sw      v0, -4(a1)
+smallcpy:
+       ble     a2, zero, 2f
+       addu    a3, a2, a0              # compute ending address
+1:
+       lbu     v0, 0(a0)               # copy bytes
+       addu    a0, a0, 1
+       addu    a1, a1, 1
+       bne     a0, a3, 1b
+       sb      v0, -1(a1)
+2:
+       sw      zero, UADDR+U_PCB_ONFAULT       # for copyin, copyout
+       j       ra
+       move    v0, zero
+       .set    reorder
+END(bcopy)
+
+/*
+ * Copy a null terminated string within the kernel address space.
+ * Maxlength may be null if count not wanted.
+ *     copystr(fromaddr, toaddr, maxlength, &lencopied)
+ *             caddr_t fromaddr;
+ *             caddr_t toaddr;
+ *             u_int maxlength;
+ *             u_int *lencopied;
+ */
+LEAF(copystr)
+       move    t2, a2                  # Save the number of bytes
+1:
+       lb      t0, 0(a0)
+       sb      t0, 0(a1)
+       sub     a2, a2, 1
+       beq     t0, zero, 2f
+       add     a0, a0, 1
+       add     a1, a1, 1
+       bne     a2, zero, 1b
+2:
+       beq     a3, zero, 3f
+       sub     a2, t2, a2              # compute length copied
+       sw      a2, 0(a3)
+3:
+       sw      zero, UADDR+U_PCB_ONFAULT       # for copyinstr, copyoutstr
+       move    v0, zero
+       j       ra
+END(copystr)
+
+/*
+ * Copy a null terminated string from the user address space into
+ * the kernel address space.
+ *
+ *     copyinstr(fromaddr, toaddr, maxlength, &lencopied)
+ *             caddr_t fromaddr;
+ *             caddr_t toaddr;
+ *             u_int maxlength;
+ *             u_int *lencopied;
+ */
+LEAF(copyinstr)
+       li      v0, COPYERR
+       blt     a0, zero, copyerr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       b       copystr
+END(copyinstr)
+
+/*
+ * Copy a null terminated string from the kernel address space into
+ * the user address space.
+ *
+ *     copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
+ *             caddr_t fromaddr;
+ *             caddr_t toaddr;
+ *             u_int maxlength;
+ *             u_int *lencopied;
+ */
+LEAF(copyoutstr)
+       li      v0, COPYERR
+       blt     a1, zero, copyerr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       b       copystr
+END(copyoutstr)
+
+/*
+ * Copy specified amount of data from user space into the kernel
+ *     copyin(from, to, len)
+ *             caddr_t *from;  (user source address)
+ *             caddr_t *to;    (kernel destination address)
+ *             unsigned len;
+ */
+LEAF(copyin)
+       li      v0, COPYERR
+       blt     a0, zero, copyerr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       b       bcopy
+END(copyin)
+
+/*
+ * Copy specified amount of data from kernel to the user space
+ *     copyout(from, to, len)
+ *             caddr_t *from;  (kernel source address)
+ *             caddr_t *to;    (user destination address)
+ *             unsigned len;
+ */
+LEAF(copyout)
+       li      v0, COPYERR
+       blt     a1, zero, copyerr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       b       bcopy
+END(copyout)
+
+LEAF(copyerr)
+       li      v0, EFAULT              # return error
+       j       ra
+END(copyerr)
+
+/*
+ * Copy data to the DMA buffer.
+ * The DMA bufffer can only be written one short at a time
+ * (and takes ~14 cycles).
+ *
+ *     CopyToBuffer(src, dst, length)
+ *             u_short *src;   NOTE: must be short aligned
+ *             u_short *dst;
+ *             int length;
+ */
+LEAF(CopyToBuffer)
+       blez    a2, 2f
+1:
+       lhu     t0, 0(a0)               # read 2 bytes of data
+       subu    a2, a2, 2
+       addu    a0, a0, 2
+       addu    a1, a1, 4
+       sh      t0, -4(a1)              # write 2 bytes of data to buffer
+       bgtz    a2, 1b
+2:
+       j       ra
+END(CopyToBuffer)
+
+/*
+ * Copy data from the DMA buffer.
+ * The DMA bufffer can only be read one short at a time
+ * (and takes ~12 cycles).
+ *
+ *     CopyFromBuffer(src, dst, length)
+ *             u_short *src;
+ *             char *dst;
+ *             int length;
+ */
+LEAF(CopyFromBuffer)
+       and     t0, a1, 1               # test for aligned dst
+       beq     t0, zero, 3f
+       blt     a2, 2, 7f               # at least 2 bytes to copy?
+1:
+       lhu     t0, 0(a0)               # read 2 bytes of data from buffer
+       addu    a0, a0, 4               # keep buffer pointer word aligned
+       addu    a1, a1, 2
+       subu    a2, a2, 2
+       sb      t0, -2(a1)
+       srl     t0, t0, 8
+       sb      t0, -1(a1)
+       bge     a2, 2, 1b
+3:
+       blt     a2, 2, 7f               # at least 2 bytes to copy?
+6:
+       lhu     t0, 0(a0)               # read 2 bytes of data from buffer
+       addu    a0, a0, 4               # keep buffer pointer word aligned
+       addu    a1, a1, 2
+       subu    a2, a2, 2
+       sh      t0, -2(a1)
+       bge     a2, 2, 6b
+7:
+       ble     a2, zero, 9f            # done?
+       lhu     t0, 0(a0)               # copy one more byte
+       sb      t0, 0(a1)
+9:
+       j       ra
+END(CopyFromBuffer)
+
+/*
+ * Copy the kernel stack to the new process and save the current context so
+ * the new process will return nonzero when it is resumed by swtch().
+ *
+ *     copykstack(up)
+ *             struct user *up;
+ */
+LEAF(copykstack)
+       subu    v0, sp, UADDR           # compute offset into stack
+       addu    v0, v0, a0              # v0 = new stack address
+       move    v1, sp                  # v1 = old stack address
+       li      t1, KERNELSTACK
+1:
+       lw      t0, 0(v1)               # copy stack data
+       addu    v1, v1, 4
+       sw      t0, 0(v0)
+       addu    v0, v0, 4
+       bne     v1, t1, 1b
+       /* FALLTHROUGH */
+/*
+ * Save registers and state so we can do a longjmp later.
+ * Note: this only works if p != curproc since
+ * swtch() will copy over pcb_context.
+ *
+ *     savectx(up)
+ *             struct user *up;
+ */
+ALEAF(savectx)
+       .set    noreorder
+       sw      s0, U_PCB_CONTEXT+0(a0)
+       sw      s1, U_PCB_CONTEXT+4(a0)
+       sw      s2, U_PCB_CONTEXT+8(a0)
+       sw      s3, U_PCB_CONTEXT+12(a0)
+       mfc0    v0, MACH_COP_0_STATUS_REG
+       sw      s4, U_PCB_CONTEXT+16(a0)
+       sw      s5, U_PCB_CONTEXT+20(a0)
+       sw      s6, U_PCB_CONTEXT+24(a0)
+       sw      s7, U_PCB_CONTEXT+28(a0)
+       sw      sp, U_PCB_CONTEXT+32(a0)
+       sw      s8, U_PCB_CONTEXT+36(a0)
+       sw      ra, U_PCB_CONTEXT+40(a0)
+       sw      v0, U_PCB_CONTEXT+44(a0)
+       j       ra
+       move    v0, zero
+       .set    reorder
+END(copykstack)
+
+/*
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them.  Setrq puts processes into queues, Remrq
+ * removes them from queues.  The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+
+/*
+ * setrq(p)
+ *     proc *p;
+ *
+ * Call should be made at splclock(), and p->p_stat should be SRUN.
+ */
+NON_LEAF(setrq, STAND_FRAME_SIZE, ra)
+       subu    sp, sp, STAND_FRAME_SIZE
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+       lw      t0, P_RLINK(a0)         ## firewall: p->p_rlink must be 0
+       beq     t0, zero, 1f            ##
+       sw      ra, STAND_RA_OFFSET(sp) ##
+       PANIC("setrq")                  ##
+1:
+       lbu     t0, P_PRI(a0)           # put on queue which is p->p_pri / 4
+       srl     t0, t0, 2               # compute index into 'whichqs'
+       li      t1, 1                   # compute corresponding bit
+       sll     t1, t1, t0
+       lw      t2, whichqs             # set corresponding bit
+       or      t2, t2, t1
+       sw      t2, whichqs
+       sll     t0, t0, 3               # compute index into 'qs'
+       la      t1, qs
+       addu    t0, t0, t1              # t0 = qp = &qs[pri >> 2]
+       lw      t1, P_RLINK(t0)         # t1 = qp->ph_rlink
+       sw      t0, P_LINK(a0)          # p->p_link = qp
+       sw      t1, P_RLINK(a0)         # p->p_rlink = qp->ph_rlink
+       sw      a0, P_LINK(t1)          # p->p_rlink->p_link = p;
+       sw      a0, P_RLINK(t0)         # qp->ph_rlink = p
+       addu    sp, sp, STAND_FRAME_SIZE
+       j       ra
+END(setrq)
+
+/*
+ * Remrq(p)
+ *
+ * Call should be made at splclock().
+ */
+NON_LEAF(remrq, STAND_FRAME_SIZE, ra)
+       subu    sp, sp, STAND_FRAME_SIZE
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+       lbu     t0, P_PRI(a0)           # get from queue which is p->p_pri / 4
+       srl     t0, t0, 2               # compute index into 'whichqs'
+       li      t1, 1                   # compute corresponding bit
+       sll     t1, t1, t0
+       lw      t2, whichqs             # check corresponding bit
+       and     v0, t2, t1
+       bne     v0, zero, 1f            ##
+       sw      ra, STAND_RA_OFFSET(sp) ##
+       PANIC("remrq")                  ## it wasn't recorded to be on its q
+1:
+       lw      v0, P_RLINK(a0)         # v0 = p->p_rlink
+       lw      v1, P_LINK(a0)          # v1 = p->p_link
+       sw      v1, P_LINK(v0)          # p->p_rlink->p_link = p->p_link;
+       sw      v0, P_RLINK(v1)         # p->p_link->p_rlink = p->r_rlink
+       sll     t0, t0, 3               # compute index into 'qs'
+       la      v0, qs
+       addu    t0, t0, v0              # t0 = qp = &qs[pri >> 2]
+       lw      v0, P_LINK(t0)          # check if queue empty
+       bne     v0, t0, 2f              # No. qp->ph_link != qp
+       xor     t2, t2, t1              # clear corresponding bit in 'whichqs'
+       sw      t2, whichqs
+2:
+       sw      zero, P_RLINK(a0)       ## for firewall checking
+       addu    sp, sp, STAND_FRAME_SIZE
+       j       ra
+END(remrq)
+
+/*
+ * swtch_exit()
+ *
+ * At exit of a process, do a swtch for the last time.
+ * The mapping of the pcb at p->p_addr has already been deleted,
+ * and the memory for the pcb+stack has been freed.
+ * All interrupts should be blocked at this point.
+ */
+LEAF(swtch_exit)
+       .set    noreorder
+       la      v0, nullproc                    # save state into garbage proc
+       lw      t0, P_UPTE+0(v0)                # t0 = first u. pte
+       lw      t1, P_UPTE+4(v0)                # t1 = 2nd u. pte
+       li      v0, UADDR                       # v0 = first HI entry
+       mtc0    zero, MACH_COP_0_TLB_INDEX      # set the index register
+       mtc0    v0, MACH_COP_0_TLB_HI           # init high entry
+       mtc0    t0, MACH_COP_0_TLB_LOW          # init low entry
+       li      t0, 1 << VMMACH_TLB_INDEX_SHIFT
+       tlbwi                                   # Write the TLB entry.
+       addu    v0, v0, NBPG                    # 2nd HI entry
+       mtc0    t0, MACH_COP_0_TLB_INDEX        # set the index register
+       mtc0    v0, MACH_COP_0_TLB_HI           # init high entry
+       mtc0    t1, MACH_COP_0_TLB_LOW          # init low entry
+       nop
+       tlbwi                                   # Write the TLB entry.
+       .set    reorder
+       li      sp, KERNELSTACK - START_FRAME   # switch to standard stack
+       b       swtch
+END(swtch_exit)
+
+/*
+ * When no processes are on the runq, swtch branches to idle
+ * to wait for something to come ready.
+ * Note: this is really a part of swtch() but defined here for kernel profiling.
+ */
+LEAF(idle)
+       .set    noreorder
+       li      t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       mtc0    t0, MACH_COP_0_STATUS_REG       # enable all interrupts
+       nop
+       .set    reorder
+1:
+       lw      t0, whichqs                     # look for non-empty queue
+       beq     t0, zero, 1b
+       b       sw1
+END(idle)
+
+/*
+ * swtch()
+ * Find the highest priority process and resume it.
+ */
+NON_LEAF(swtch, STAND_FRAME_SIZE, ra)
+       .set    noreorder
+       sw      sp, UADDR+U_PCB_CONTEXT+32      # save old sp
+       subu    sp, sp, STAND_FRAME_SIZE
+       sw      ra, STAND_RA_OFFSET(sp)
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+       lw      t2, cnt+V_SWTCH                 # for statistics
+       lw      t1, whichqs                     # look for non-empty queue
+       mfc0    t0, MACH_COP_0_STATUS_REG       # t0 = saved status register
+       sw      ra, UADDR+U_PCB_CONTEXT+40      # save return address
+       sw      t0, UADDR+U_PCB_CONTEXT+44      # save status register
+       addu    t2, t2, 1
+       beq     t1, zero, idle                  # if none, idle
+       sw      t2, cnt+V_SWTCH
+sw1:
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable all interrupts
+       nop
+       lw      t0, whichqs                     # look for non-empty queue
+       li      t2, -1                          # t2 = lowest bit set
+       beq     t0, zero, idle                  # if none, idle
+       move    t3, t0                          # t3 = saved whichqs
+1:
+       add     t2, t2, 1
+       and     t1, t0, 1                       # bit set?
+       beq     t1, zero, 1b
+       srl     t0, t0, 1                       # try next bit
+/*
+ * Remove process from queue.
+ */
+       sll     t0, t2, 3
+       la      t1, qs
+       addu    t0, t0, t1                      # t0 = qp = &qs[highbit]
+       lw      a0, P_LINK(t0)                  # a0 = p = highest pri process
+       nop
+       lw      v0, P_LINK(a0)                  # v0 = p->p_link
+       bne     t0, a0, 2f                      # make sure something in queue
+       sw      v0, P_LINK(t0)                  # qp->ph_link = p->p_link;
+       PANIC("swtch")                          # nothing in queue
+2:
+       sw      t0, P_RLINK(v0)                 # p->p_link->p_rlink = qp
+       bne     v0, t0, 3f                      # queue still not empty
+       sw      zero, P_RLINK(a0)               ## for firewall checking
+       li      v1, 1                           # compute bit in 'whichqs'
+       sll     v1, v1, t2
+       xor     t3, t3, v1                      # clear bit in 'whichqs'
+       sw      t3, whichqs
+3:
+/*
+ * Save old context and switch to new one.
+ */
+       sw      a0, curproc                     # set curproc
+       sw      zero, want_resched
+       jal     pmap_alloc_tlbpid               # v0 = TLB PID
+       sw      a0, STAND_FRAME_SIZE(sp)        # save p
+       lw      a0, STAND_FRAME_SIZE(sp)        # restore p
+       sll     v0, v0, VMMACH_TLB_PID_SHIFT    # v0 = aligned PID
+       or      v0, v0, UADDR                   # v0 = first HI entry
+       lw      t0, P_UPTE+0(a0)                # t0 = first u. pte
+       lw      t1, P_UPTE+4(a0)                # t1 = 2nd u. pte
+       sw      s0, UADDR+U_PCB_CONTEXT+0       # do a 'savectx()'
+       sw      s1, UADDR+U_PCB_CONTEXT+4       #  We save s0 to s8 here because
+       sw      s2, UADDR+U_PCB_CONTEXT+8       #  the TLB trap code uses
+       sw      s3, UADDR+U_PCB_CONTEXT+12      #  CONTEXT and there should be
+       sw      s4, UADDR+U_PCB_CONTEXT+16      #  no faults at this point.
+       sw      s5, UADDR+U_PCB_CONTEXT+20
+       sw      s6, UADDR+U_PCB_CONTEXT+24
+       sw      s7, UADDR+U_PCB_CONTEXT+28
+       sw      s8, UADDR+U_PCB_CONTEXT+36
+/*
+ * Resume process indicated by the pte's for its u struct
+ * NOTE: This is hard coded to UPAGES == 2.
+ * Also, there should be no TLB faults at this point.
+ */
+       mtc0    zero, MACH_COP_0_TLB_INDEX      # set the index register
+       mtc0    v0, MACH_COP_0_TLB_HI           # init high entry
+       mtc0    t0, MACH_COP_0_TLB_LOW          # init low entry
+       li      t0, 1 << VMMACH_TLB_INDEX_SHIFT
+       tlbwi                                   # Write the TLB entry.
+       addu    v0, v0, NBPG                    # 2nd HI entry
+       mtc0    t0, MACH_COP_0_TLB_INDEX        # set the index register
+       mtc0    v0, MACH_COP_0_TLB_HI           # init high entry
+       mtc0    t1, MACH_COP_0_TLB_LOW          # init low entry
+       nop
+       tlbwi                                   # Write the TLB entry.
+/*
+ * Now running on new u struct.
+ * Restore registers and return.
+ */
+       lw      v0, UADDR+U_PCB_CONTEXT+44      # restore kernel context
+       lw      ra, UADDR+U_PCB_CONTEXT+40
+       lw      s0, UADDR+U_PCB_CONTEXT+0
+       lw      s1, UADDR+U_PCB_CONTEXT+4
+       lw      s2, UADDR+U_PCB_CONTEXT+8
+       lw      s3, UADDR+U_PCB_CONTEXT+12
+       lw      s4, UADDR+U_PCB_CONTEXT+16
+       lw      s5, UADDR+U_PCB_CONTEXT+20
+       lw      s6, UADDR+U_PCB_CONTEXT+24
+       lw      s7, UADDR+U_PCB_CONTEXT+28
+       lw      sp, UADDR+U_PCB_CONTEXT+32
+       lw      s8, UADDR+U_PCB_CONTEXT+36
+       mtc0    v0, MACH_COP_0_STATUS_REG
+       j       ra
+       li      v0, 1                           # possible return to 'savectx()'
+       .set    reorder
+END(swtch)
+
+/*
+ * {fu,su},{ibyte,iword}, fetch or store a byte or word to user text space.
+ * {fu,su},{byte,word}, fetch or store a byte or word to user data space.
+ */
+LEAF(fuword)
+ALEAF(fuiword)
+       li      v0, FSWBERR
+       blt     a0, zero, fswberr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       lw      v0, 0(a0)               # fetch word
+       sw      zero, UADDR+U_PCB_ONFAULT
+       j       ra
+END(fuword)
+
+LEAF(fubyte)
+ALEAF(fuibyte)
+       li      v0, FSWBERR
+       blt     a0, zero, fswberr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       lbu     v0, 0(a0)               # fetch byte
+       sw      zero, UADDR+U_PCB_ONFAULT
+       j       ra
+END(fubyte)
+
+LEAF(suword)
+ALEAF(suiword)
+       li      v0, FSWBERR
+       blt     a0, zero, fswberr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       sw      a1, 0(a0)               # store word
+       sw      zero, UADDR+U_PCB_ONFAULT
+       move    v0, zero
+       j       ra
+END(suword)
+
+LEAF(subyte)
+ALEAF(suibyte)
+       li      v0, FSWBERR
+       blt     a0, zero, fswberr       # make sure address is in user space
+       sw      v0, UADDR+U_PCB_ONFAULT
+       sb      a1, 0(a0)               # store byte
+       sw      zero, UADDR+U_PCB_ONFAULT
+       move    v0, zero
+       j       ra
+END(subyte)
+
+LEAF(fswberr)
+       li      v0, -1
+       j       ra
+END(fswberr)
+
+/*
+ * Insert 'p' after 'q'.
+ *     _insque(p, q)
+ *             caddr_t p, q;
+ */
+LEAF(_insque)
+       lw      v0, 0(a1)               # v0 = q->next
+       sw      a1, 4(a0)               # p->prev = q
+       sw      v0, 0(a0)               # p->next = q->next
+       sw      a0, 4(v0)               # q->next->prev = p
+       sw      a0, 0(a1)               # q->next = p
+       j       ra
+END(_insque)
+
+/*
+ * Remove item 'p' from queue.
+ *     _remque(p)
+ *             caddr_t p;
+ */
+LEAF(_remque)
+       lw      v0, 0(a0)               # v0 = p->next
+       lw      v1, 4(a0)               # v1 = p->prev
+       sw      v0, 0(v1)               # p->prev->next = p->next
+       sw      v1, 4(v0)               # p->next->prev = p->prev
+       j       ra
+END(_remque)
+
+/*
+ * This code is copied to the UTLB exception vector address to
+ * handle user level TLB translation misses.
+ * NOTE: This code must be relocatable!!!
+ */
+       .globl  MachUTLBMiss
+MachUTLBMiss:
+       .set    noat
+       .set    noreorder
+       mfc0    k0, MACH_COP_0_BAD_VADDR        # get the virtual address
+       nop
+       srl     k0, k0, PMAP_HASH_SHIFT1        # get page in low bits
+       srl     k1, k0, PMAP_HASH_SHIFT2 - PMAP_HASH_SHIFT1
+       and     k0, k0, PMAP_HASH_MASK1
+       and     k1, k1, PMAP_HASH_MASK2
+       or      k1, k1, k0
+       sll     k1, k1, PMAP_HASH_SIZE_SHIFT    # compute index
+       lw      k0, PMAP_HASH_LOW_OFFSET(k1)    # get cached low PTE entry
+       lw      k1, PMAP_HASH_HIGH_OFFSET(k1)   # get cached high PTE entry
+       mtc0    k0, MACH_COP_0_TLB_LOW
+       mfc0    k0, MACH_COP_0_TLB_HI           # get actual high PTE entry
+       nop
+       bne     k0, k1, 1f                      # non-matching PTE
+       mfc0    k0, MACH_COP_0_EXC_PC           # get return address
+       tlbwr                                   # update TLB
+       j       k0
+       rfe
+1:
+       j       SlowFault                       # handle cache miss
+       nop
+       .set    reorder
+       .set    at
+       .globl  MachUTLBMissEnd
+MachUTLBMissEnd:
+
+/*
+ * This code is copied to the general exception vector address to
+ * handle all execptions except RESET and UTLBMiss.
+ * NOTE: This code must be relocatable!!!
+ */
+       .globl  MachException
+MachException:
+/*
+ * Find out what mode we came from and jump to the proper handler.
+ */
+       .set    noat
+       .set    noreorder
+       mfc0    k0, MACH_COP_0_STATUS_REG       # Get the status register
+       mfc0    k1, MACH_COP_0_CAUSE_REG        # Get the cause register value.
+       and     k0, k0, MACH_SR_KU_PREV         # test for user mode
+       beq     k0, zero, 1f                    # handle kernel exception
+       and     k1, k1, MACH_CR_EXC_CODE        # Mask out the cause bits.
+       addu    k1, k1, 0x40                    # change index to user table
+1:
+       la      k0, machExceptionTable          # get base of the jump table
+       add     k0, k0, k1                      # Get the address of the
+                                               #  function entry.  Note that
+                                               #  the cause is already
+                                               #  shifted left by 2 bits so
+                                               #  we don't have to shift.
+       lw      k0, 0(k0)                       # Get the function address
+       nop
+       j       k0                              # Jump to the function.
+       nop
+       .set    reorder
+       .set    at
+       .globl  MachExceptionEnd
+MachExceptionEnd:
+
+/*
+ * We couldn't find a TLB entry.
+ * Find out what mode we came from and call the appropriate handler.
+ */
+SlowFault:
+       .set    noat
+       .set    noreorder
+       mfc0    k0, MACH_COP_0_STATUS_REG
+       nop
+       and     k0, k0, MACH_SR_KU_PREV
+       bne     k0, zero, MachUserGenException
+       nop
+       .set    reorder
+       .set    at
+/*
+ * Fall though ...
+ */
+
+/*----------------------------------------------------------------------------
+ *
+ * MachKernGenException --
+ *
+ *     Handle an exception from kernel mode.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+/*
+ * The kernel exception stack contains 18 saved general registers,
+ * the status register and the multiply lo and high registers.
+ * In addition, we set this up for linkage conventions.
+ */
+#define KERN_REG_SIZE          (18 * 4)
+#define KERN_REG_OFFSET                (STAND_FRAME_SIZE)
+#define KERN_SR_OFFSET         (STAND_FRAME_SIZE + KERN_REG_SIZE)
+#define KERN_MULT_LO_OFFSET    (STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
+#define KERN_MULT_HI_OFFSET    (STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
+#define        KERN_EXC_FRAME_SIZE     (STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
+
+NON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra)
+       .set    noreorder
+       .set    noat
+       subu    sp, sp, KERN_EXC_FRAME_SIZE
+       .mask   0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE)
+/*
+ * Save the relevant kernel registers onto the stack.
+ * We don't need to save s0 - s8, sp and gp because
+ * the compiler does it for us.
+ */
+       sw      AT, KERN_REG_OFFSET + 0(sp)
+       sw      v0, KERN_REG_OFFSET + 4(sp)
+       sw      v1, KERN_REG_OFFSET + 8(sp)
+       sw      a0, KERN_REG_OFFSET + 12(sp)
+       mflo    v0
+       mfhi    v1
+       sw      a1, KERN_REG_OFFSET + 16(sp)
+       sw      a2, KERN_REG_OFFSET + 20(sp)
+       sw      a3, KERN_REG_OFFSET + 24(sp)
+       sw      t0, KERN_REG_OFFSET + 28(sp)
+       mfc0    a0, MACH_COP_0_STATUS_REG       # First arg is the status reg.
+       sw      t1, KERN_REG_OFFSET + 32(sp)
+       sw      t2, KERN_REG_OFFSET + 36(sp)
+       sw      t3, KERN_REG_OFFSET + 40(sp)
+       sw      t4, KERN_REG_OFFSET + 44(sp)
+       mfc0    a1, MACH_COP_0_CAUSE_REG        # Second arg is the cause reg.
+       sw      t5, KERN_REG_OFFSET + 48(sp)
+       sw      t6, KERN_REG_OFFSET + 52(sp)
+       sw      t7, KERN_REG_OFFSET + 56(sp)
+       sw      t8, KERN_REG_OFFSET + 60(sp)
+       mfc0    a2, MACH_COP_0_BAD_VADDR        # Third arg is the fault addr.
+       sw      t9, KERN_REG_OFFSET + 64(sp)
+       sw      ra, KERN_REG_OFFSET + 68(sp)
+       sw      v0, KERN_MULT_LO_OFFSET(sp)
+       sw      v1, KERN_MULT_HI_OFFSET(sp)
+       mfc0    a3, MACH_COP_0_EXC_PC           # Fourth arg is the pc.
+       sw      a0, KERN_SR_OFFSET(sp)
+/*
+ * Call the exception handler.
+ */
+       jal     trap
+       sw      a3, STAND_RA_OFFSET(sp)         # for debugging
+/*
+ * Restore registers and return from the exception.
+ * v0 contains the return address.
+ */
+       lw      a0, KERN_SR_OFFSET(sp)
+       lw      t0, KERN_MULT_LO_OFFSET(sp)
+       lw      t1, KERN_MULT_HI_OFFSET(sp)
+       mtc0    a0, MACH_COP_0_STATUS_REG       # Restore the SR, disable intrs
+       mtlo    t0
+       mthi    t1
+       move    k0, v0
+       lw      AT, KERN_REG_OFFSET + 0(sp)
+       lw      v0, KERN_REG_OFFSET + 4(sp)
+       lw      v1, KERN_REG_OFFSET + 8(sp)
+       lw      a0, KERN_REG_OFFSET + 12(sp)
+       lw      a1, KERN_REG_OFFSET + 16(sp)
+       lw      a2, KERN_REG_OFFSET + 20(sp)
+       lw      a3, KERN_REG_OFFSET + 24(sp)
+       lw      t0, KERN_REG_OFFSET + 28(sp)
+       lw      t1, KERN_REG_OFFSET + 32(sp)
+       lw      t2, KERN_REG_OFFSET + 36(sp)
+       lw      t3, KERN_REG_OFFSET + 40(sp)
+       lw      t4, KERN_REG_OFFSET + 44(sp)
+       lw      t5, KERN_REG_OFFSET + 48(sp)
+       lw      t6, KERN_REG_OFFSET + 52(sp)
+       lw      t7, KERN_REG_OFFSET + 56(sp)
+       lw      t8, KERN_REG_OFFSET + 60(sp)
+       lw      t9, KERN_REG_OFFSET + 64(sp)
+       lw      ra, KERN_REG_OFFSET + 68(sp)
+       addu    sp, sp, KERN_EXC_FRAME_SIZE
+       j       k0                              # Now return from the
+       rfe                                     #  exception.
+       .set    at
+       .set    reorder
+END(MachKernGenException)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachUserGenException --
+ *
+ *     Handle an exception from user mode.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+NON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra)
+       .set    noreorder
+       .set    noat
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+/*
+ * Save all of the registers except for the kernel temporaries in u.u_pcb.
+ */
+       sw      AT, UADDR+U_PCB_REGS+(AST * 4)
+       sw      v0, UADDR+U_PCB_REGS+(V0 * 4)
+       sw      v1, UADDR+U_PCB_REGS+(V1 * 4)
+       sw      a0, UADDR+U_PCB_REGS+(A0 * 4)
+       mflo    v0
+       sw      a1, UADDR+U_PCB_REGS+(A1 * 4)
+       sw      a2, UADDR+U_PCB_REGS+(A2 * 4)
+       sw      a3, UADDR+U_PCB_REGS+(A3 * 4)
+       sw      t0, UADDR+U_PCB_REGS+(T0 * 4)
+       mfhi    v1
+       sw      t1, UADDR+U_PCB_REGS+(T1 * 4)
+       sw      t2, UADDR+U_PCB_REGS+(T2 * 4)
+       sw      t3, UADDR+U_PCB_REGS+(T3 * 4)
+       sw      t4, UADDR+U_PCB_REGS+(T4 * 4)
+       mfc0    a0, MACH_COP_0_STATUS_REG       # First arg is the status reg.
+       sw      t5, UADDR+U_PCB_REGS+(T5 * 4)
+       sw      t6, UADDR+U_PCB_REGS+(T6 * 4)
+       sw      t7, UADDR+U_PCB_REGS+(T7 * 4)
+       sw      s0, UADDR+U_PCB_REGS+(S0 * 4)
+       mfc0    a1, MACH_COP_0_CAUSE_REG        # Second arg is the cause reg.
+       sw      s1, UADDR+U_PCB_REGS+(S1 * 4)
+       sw      s2, UADDR+U_PCB_REGS+(S2 * 4)
+       sw      s3, UADDR+U_PCB_REGS+(S3 * 4)
+       sw      s4, UADDR+U_PCB_REGS+(S4 * 4)
+       mfc0    a2, MACH_COP_0_BAD_VADDR        # Third arg is the fault addr
+       sw      s5, UADDR+U_PCB_REGS+(S5 * 4)
+       sw      s6, UADDR+U_PCB_REGS+(S6 * 4)
+       sw      s7, UADDR+U_PCB_REGS+(S7 * 4)
+       sw      t8, UADDR+U_PCB_REGS+(T8 * 4)
+       mfc0    a3, MACH_COP_0_EXC_PC           # Fourth arg is the pc.
+       sw      t9, UADDR+U_PCB_REGS+(T9 * 4)
+       sw      gp, UADDR+U_PCB_REGS+(GP * 4)
+       sw      sp, UADDR+U_PCB_REGS+(SP * 4)
+       sw      s8, UADDR+U_PCB_REGS+(S8 * 4)
+       li      sp, KERNELSTACK - STAND_FRAME_SIZE      # switch to kernel SP
+       sw      ra, UADDR+U_PCB_REGS+(RA * 4)
+       sw      v0, UADDR+U_PCB_REGS+(MULLO * 4)
+       sw      v1, UADDR+U_PCB_REGS+(MULHI * 4)
+       sw      a0, UADDR+U_PCB_REGS+(SR * 4)
+       la      gp, _gp                         # switch to kernel GP
+       sw      a3, UADDR+U_PCB_REGS+(PC * 4)
+       sw      a3, STAND_RA_OFFSET(sp)         # for debugging
+       and     t0, a0, ~MACH_SR_COP_1_BIT      # Turn off the FPU.
+/*
+ * Call the exception handler.
+ */
+       jal     trap
+       mtc0    t0, MACH_COP_0_STATUS_REG
+/*
+ * Restore user registers and return. NOTE: interrupts are enabled.
+ */
+       lw      a0, UADDR+U_PCB_REGS+(SR * 4)
+       lw      t0, UADDR+U_PCB_REGS+(MULLO * 4)
+       lw      t1, UADDR+U_PCB_REGS+(MULHI * 4)
+       mtc0    a0, MACH_COP_0_STATUS_REG       # this should disable interrupts
+       mtlo    t0
+       mthi    t1
+       lw      k0, UADDR+U_PCB_REGS+(PC * 4)
+       lw      AT, UADDR+U_PCB_REGS+(AST * 4)
+       lw      v0, UADDR+U_PCB_REGS+(V0 * 4)
+       lw      v1, UADDR+U_PCB_REGS+(V1 * 4)
+       lw      a0, UADDR+U_PCB_REGS+(A0 * 4)
+       lw      a1, UADDR+U_PCB_REGS+(A1 * 4)
+       lw      a2, UADDR+U_PCB_REGS+(A2 * 4)
+       lw      a3, UADDR+U_PCB_REGS+(A3 * 4)
+       lw      t0, UADDR+U_PCB_REGS+(T0 * 4)
+       lw      t1, UADDR+U_PCB_REGS+(T1 * 4)
+       lw      t2, UADDR+U_PCB_REGS+(T2 * 4)
+       lw      t3, UADDR+U_PCB_REGS+(T3 * 4)
+       lw      t4, UADDR+U_PCB_REGS+(T4 * 4)
+       lw      t5, UADDR+U_PCB_REGS+(T5 * 4)
+       lw      t6, UADDR+U_PCB_REGS+(T6 * 4)
+       lw      t7, UADDR+U_PCB_REGS+(T7 * 4)
+       lw      s0, UADDR+U_PCB_REGS+(S0 * 4)
+       lw      s1, UADDR+U_PCB_REGS+(S1 * 4)
+       lw      s2, UADDR+U_PCB_REGS+(S2 * 4)
+       lw      s3, UADDR+U_PCB_REGS+(S3 * 4)
+       lw      s4, UADDR+U_PCB_REGS+(S4 * 4)
+       lw      s5, UADDR+U_PCB_REGS+(S5 * 4)
+       lw      s6, UADDR+U_PCB_REGS+(S6 * 4)
+       lw      s7, UADDR+U_PCB_REGS+(S7 * 4)
+       lw      t8, UADDR+U_PCB_REGS+(T8 * 4)
+       lw      t9, UADDR+U_PCB_REGS+(T9 * 4)
+       lw      gp, UADDR+U_PCB_REGS+(GP * 4)
+       lw      sp, UADDR+U_PCB_REGS+(SP * 4)
+       lw      s8, UADDR+U_PCB_REGS+(S8 * 4)
+       lw      ra, UADDR+U_PCB_REGS+(RA * 4)
+       j       k0
+       rfe
+       .set    at
+       .set    reorder
+END(MachUserGenException)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachKernIntr --
+ *
+ *     Handle an interrupt from kernel mode.
+ *     Interrupts must use a separate stack since during exit()
+ *     there is a window of time when there is no kernel stack.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+#define KINTR_REG_OFFSET       (STAND_FRAME_SIZE)
+#define KINTR_SR_OFFSET                (STAND_FRAME_SIZE + KERN_REG_SIZE)
+#define KINTR_SP_OFFSET                (STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
+#define KINTR_MULT_LO_OFFSET   (STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
+#define KINTR_MULT_HI_OFFSET   (STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
+#define        KINTR_FRAME_SIZE        (STAND_FRAME_SIZE + KERN_REG_SIZE + 16)
+
+NON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra)
+       .set    noreorder
+       .set    noat
+       .mask   0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE)
+/*
+ * Check to see if we are already on the interrupt stack.
+ */
+       li      k0, MACH_CODE_START             # interrupt stack below code
+       sltu    k1, sp, k0
+       beq     k1, zero, 1f                    # no, init sp
+       nop
+       sw      sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(sp)      # save old sp
+       b       2f
+       subu    sp, sp, KINTR_FRAME_SIZE        # allocate stack frame
+1:
+       sw      sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(k0)      # save old sp
+       subu    sp, k0, KINTR_FRAME_SIZE        # switch to interrupt stack
+2:
+/*
+ * Save the relevant kernel registers onto the stack.
+ * We don't need to save s0 - s8, sp and gp because
+ * the compiler does it for us.
+ */
+       sw      AT, KINTR_REG_OFFSET + 0(sp)
+       sw      v0, KINTR_REG_OFFSET + 4(sp)
+       sw      v1, KINTR_REG_OFFSET + 8(sp)
+       sw      a0, KINTR_REG_OFFSET + 12(sp)
+       mflo    v0
+       mfhi    v1
+       sw      a1, KINTR_REG_OFFSET + 16(sp)
+       sw      a2, KINTR_REG_OFFSET + 20(sp)
+       sw      a3, KINTR_REG_OFFSET + 24(sp)
+       sw      t0, KINTR_REG_OFFSET + 28(sp)
+       mfc0    a0, MACH_COP_0_STATUS_REG       # First arg is the status reg.
+       sw      t1, KINTR_REG_OFFSET + 32(sp)
+       sw      t2, KINTR_REG_OFFSET + 36(sp)
+       sw      t3, KINTR_REG_OFFSET + 40(sp)
+       sw      t4, KINTR_REG_OFFSET + 44(sp)
+       mfc0    a1, MACH_COP_0_CAUSE_REG        # Second arg is the cause reg.
+       sw      t5, KINTR_REG_OFFSET + 48(sp)
+       sw      t6, KINTR_REG_OFFSET + 52(sp)
+       sw      t7, KINTR_REG_OFFSET + 56(sp)
+       sw      t8, KINTR_REG_OFFSET + 60(sp)
+       mfc0    a2, MACH_COP_0_EXC_PC           # Third arg is the pc.
+       sw      t9, KINTR_REG_OFFSET + 64(sp)
+       sw      ra, KINTR_REG_OFFSET + 68(sp)
+       sw      v0, KINTR_MULT_LO_OFFSET(sp)
+       sw      v1, KINTR_MULT_HI_OFFSET(sp)
+       sw      a0, KINTR_SR_OFFSET(sp)
+/*
+ * Call the interrupt handler.
+ */
+       jal     interrupt
+       sw      a2, STAND_RA_OFFSET(sp)         # for debugging
+/*
+ * Restore registers and return from the interrupt.
+ */
+       lw      a0, KINTR_SR_OFFSET(sp)
+       lw      t0, KINTR_MULT_LO_OFFSET(sp)
+       lw      t1, KINTR_MULT_HI_OFFSET(sp)
+       mtc0    a0, MACH_COP_0_STATUS_REG       # Restore the SR, disable intrs
+       mtlo    t0
+       mthi    t1
+       lw      k0, STAND_RA_OFFSET(sp)
+       lw      AT, KINTR_REG_OFFSET + 0(sp)
+       lw      v0, KINTR_REG_OFFSET + 4(sp)
+       lw      v1, KINTR_REG_OFFSET + 8(sp)
+       lw      a0, KINTR_REG_OFFSET + 12(sp)
+       lw      a1, KINTR_REG_OFFSET + 16(sp)
+       lw      a2, KINTR_REG_OFFSET + 20(sp)
+       lw      a3, KINTR_REG_OFFSET + 24(sp)
+       lw      t0, KINTR_REG_OFFSET + 28(sp)
+       lw      t1, KINTR_REG_OFFSET + 32(sp)
+       lw      t2, KINTR_REG_OFFSET + 36(sp)
+       lw      t3, KINTR_REG_OFFSET + 40(sp)
+       lw      t4, KINTR_REG_OFFSET + 44(sp)
+       lw      t5, KINTR_REG_OFFSET + 48(sp)
+       lw      t6, KINTR_REG_OFFSET + 52(sp)
+       lw      t7, KINTR_REG_OFFSET + 56(sp)
+       lw      t8, KINTR_REG_OFFSET + 60(sp)
+       lw      t9, KINTR_REG_OFFSET + 64(sp)
+       lw      ra, KINTR_REG_OFFSET + 68(sp)
+       lw      sp, KINTR_SP_OFFSET(sp)         # restore orig sp
+       j       k0                              # Now return from the
+       rfe                                     #  interrupt.
+       .set    at
+       .set    reorder
+END(MachKernIntr)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachUserIntr --
+ *
+ *     Handle an interrupt from user mode.
+ *     Note: we save minimal state in the u.u_pcb struct and use the standard
+ *     kernel stack since there has to be a u page if we came from user mode.
+ *     If there is a pending software interrupt, then save the remaining state
+ *     and call softintr(). This is all because if we call swtch() inside
+ *     interrupt(), not all the user registers have been saved in u.u_pcb.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+NON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra)
+       .set    noreorder
+       .set    noat
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+/*
+ * Save the relevant user registers into the u.u_pcb struct.
+ * We don't need to save s0 - s8 because
+ * the compiler does it for us.
+ */
+       sw      AT, UADDR+U_PCB_REGS+(AST * 4)
+       sw      v0, UADDR+U_PCB_REGS+(V0 * 4)
+       sw      v1, UADDR+U_PCB_REGS+(V1 * 4)
+       sw      a0, UADDR+U_PCB_REGS+(A0 * 4)
+       mflo    v0
+       mfhi    v1
+       sw      a1, UADDR+U_PCB_REGS+(A1 * 4)
+       sw      a2, UADDR+U_PCB_REGS+(A2 * 4)
+       sw      a3, UADDR+U_PCB_REGS+(A3 * 4)
+       sw      t0, UADDR+U_PCB_REGS+(T0 * 4)
+       mfc0    a0, MACH_COP_0_STATUS_REG       # First arg is the status reg.
+       sw      t1, UADDR+U_PCB_REGS+(T1 * 4)
+       sw      t2, UADDR+U_PCB_REGS+(T2 * 4)
+       sw      t3, UADDR+U_PCB_REGS+(T3 * 4)
+       sw      t4, UADDR+U_PCB_REGS+(T4 * 4)
+       mfc0    a1, MACH_COP_0_CAUSE_REG        # Second arg is the cause reg.
+       sw      t5, UADDR+U_PCB_REGS+(T5 * 4)
+       sw      t6, UADDR+U_PCB_REGS+(T6 * 4)
+       sw      t7, UADDR+U_PCB_REGS+(T7 * 4)
+       sw      t8, UADDR+U_PCB_REGS+(T8 * 4)
+       mfc0    a2, MACH_COP_0_EXC_PC           # Third arg is the pc.
+       sw      t9, UADDR+U_PCB_REGS+(T9 * 4)
+       sw      gp, UADDR+U_PCB_REGS+(GP * 4)
+       sw      sp, UADDR+U_PCB_REGS+(SP * 4)
+       sw      ra, UADDR+U_PCB_REGS+(RA * 4)
+       li      sp, KERNELSTACK - STAND_FRAME_SIZE      # switch to kernel SP
+       sw      v0, UADDR+U_PCB_REGS+(MULLO * 4)
+       sw      v1, UADDR+U_PCB_REGS+(MULHI * 4)
+       sw      a0, UADDR+U_PCB_REGS+(SR * 4)
+       sw      a2, UADDR+U_PCB_REGS+(PC * 4)
+       la      gp, _gp                         # switch to kernel GP
+       and     t0, a0, ~MACH_SR_COP_1_BIT      # Turn off the FPU.
+       mtc0    t0, MACH_COP_0_STATUS_REG
+/*
+ * Call the interrupt handler.
+ */
+       jal     interrupt
+       sw      a2, STAND_RA_OFFSET(sp)         # for debugging
+/*
+ * Restore registers and return from the interrupt.
+ */
+       lw      a0, UADDR+U_PCB_REGS+(SR * 4)
+       lw      v0, astpending                  # any pending interrupts?
+       mtc0    a0, MACH_COP_0_STATUS_REG       # Restore the SR, disable intrs
+       bne     v0, zero, 1f                    # don't restore, call softintr
+       lw      t0, UADDR+U_PCB_REGS+(MULLO * 4)
+       lw      t1, UADDR+U_PCB_REGS+(MULHI * 4)
+       lw      k0, UADDR+U_PCB_REGS+(PC * 4)
+       lw      AT, UADDR+U_PCB_REGS+(AST * 4)
+       lw      v0, UADDR+U_PCB_REGS+(V0 * 4)
+       lw      v1, UADDR+U_PCB_REGS+(V1 * 4)
+       lw      a0, UADDR+U_PCB_REGS+(A0 * 4)
+       lw      a1, UADDR+U_PCB_REGS+(A1 * 4)
+       lw      a2, UADDR+U_PCB_REGS+(A2 * 4)
+       lw      a3, UADDR+U_PCB_REGS+(A3 * 4)
+       mtlo    t0
+       mthi    t1
+       lw      t0, UADDR+U_PCB_REGS+(T0 * 4)
+       lw      t1, UADDR+U_PCB_REGS+(T1 * 4)
+       lw      t2, UADDR+U_PCB_REGS+(T2 * 4)
+       lw      t3, UADDR+U_PCB_REGS+(T3 * 4)
+       lw      t4, UADDR+U_PCB_REGS+(T4 * 4)
+       lw      t5, UADDR+U_PCB_REGS+(T5 * 4)
+       lw      t6, UADDR+U_PCB_REGS+(T6 * 4)
+       lw      t7, UADDR+U_PCB_REGS+(T7 * 4)
+       lw      t8, UADDR+U_PCB_REGS+(T8 * 4)
+       lw      t9, UADDR+U_PCB_REGS+(T9 * 4)
+       lw      gp, UADDR+U_PCB_REGS+(GP * 4)
+       lw      sp, UADDR+U_PCB_REGS+(SP * 4)
+       lw      ra, UADDR+U_PCB_REGS+(RA * 4)
+       j       k0                              # Now return from the
+       rfe                                     #  interrupt.
+
+1:
+/*
+ * We have pending software interrupts; save remaining user state in u.u_pcb.
+ */
+       sw      s0, UADDR+U_PCB_REGS+(S0 * 4)
+       sw      s1, UADDR+U_PCB_REGS+(S1 * 4)
+       sw      s2, UADDR+U_PCB_REGS+(S2 * 4)
+       sw      s3, UADDR+U_PCB_REGS+(S3 * 4)
+       sw      s4, UADDR+U_PCB_REGS+(S4 * 4)
+       sw      s5, UADDR+U_PCB_REGS+(S5 * 4)
+       sw      s6, UADDR+U_PCB_REGS+(S6 * 4)
+       sw      s7, UADDR+U_PCB_REGS+(S7 * 4)
+       sw      s8, UADDR+U_PCB_REGS+(S8 * 4)
+       li      t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR
+/*
+ * Call the software interrupt handler.
+ */
+       jal     softintr
+       mtc0    t0, MACH_COP_0_STATUS_REG       # enable interrupts (spl0)
+/*
+ * Restore user registers and return. NOTE: interrupts are enabled.
+ */
+       lw      a0, UADDR+U_PCB_REGS+(SR * 4)
+       lw      t0, UADDR+U_PCB_REGS+(MULLO * 4)
+       lw      t1, UADDR+U_PCB_REGS+(MULHI * 4)
+       mtc0    a0, MACH_COP_0_STATUS_REG       # this should disable interrupts
+       mtlo    t0
+       mthi    t1
+       lw      k0, UADDR+U_PCB_REGS+(PC * 4)
+       lw      AT, UADDR+U_PCB_REGS+(AST * 4)
+       lw      v0, UADDR+U_PCB_REGS+(V0 * 4)
+       lw      v1, UADDR+U_PCB_REGS+(V1 * 4)
+       lw      a0, UADDR+U_PCB_REGS+(A0 * 4)
+       lw      a1, UADDR+U_PCB_REGS+(A1 * 4)
+       lw      a2, UADDR+U_PCB_REGS+(A2 * 4)
+       lw      a3, UADDR+U_PCB_REGS+(A3 * 4)
+       lw      t0, UADDR+U_PCB_REGS+(T0 * 4)
+       lw      t1, UADDR+U_PCB_REGS+(T1 * 4)
+       lw      t2, UADDR+U_PCB_REGS+(T2 * 4)
+       lw      t3, UADDR+U_PCB_REGS+(T3 * 4)
+       lw      t4, UADDR+U_PCB_REGS+(T4 * 4)
+       lw      t5, UADDR+U_PCB_REGS+(T5 * 4)
+       lw      t6, UADDR+U_PCB_REGS+(T6 * 4)
+       lw      t7, UADDR+U_PCB_REGS+(T7 * 4)
+       lw      s0, UADDR+U_PCB_REGS+(S0 * 4)
+       lw      s1, UADDR+U_PCB_REGS+(S1 * 4)
+       lw      s2, UADDR+U_PCB_REGS+(S2 * 4)
+       lw      s3, UADDR+U_PCB_REGS+(S3 * 4)
+       lw      s4, UADDR+U_PCB_REGS+(S4 * 4)
+       lw      s5, UADDR+U_PCB_REGS+(S5 * 4)
+       lw      s6, UADDR+U_PCB_REGS+(S6 * 4)
+       lw      s7, UADDR+U_PCB_REGS+(S7 * 4)
+       lw      t8, UADDR+U_PCB_REGS+(T8 * 4)
+       lw      t9, UADDR+U_PCB_REGS+(T9 * 4)
+       lw      gp, UADDR+U_PCB_REGS+(GP * 4)
+       lw      sp, UADDR+U_PCB_REGS+(SP * 4)
+       lw      s8, UADDR+U_PCB_REGS+(S8 * 4)
+       lw      ra, UADDR+U_PCB_REGS+(RA * 4)
+       j       k0
+       rfe
+       .set    at
+       .set    reorder
+END(MachUserIntr)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachTLBModException --
+ *
+ *     Handle a TLB modified exception.
+ *     The BaddVAddr, Context, and EntryHi registers contain the failed
+ *     virtual address.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(MachTLBModException)
+#if 0
+       .set    noreorder
+       .set    noat
+       tlbp                                    # find the TLB entry
+       mfc0    k0, MACH_COP_0_TLB_LOW          # get the physical address
+       mfc0    k1, MACH_COP_0_TLB_INDEX        # check to be sure its valid
+       or      k0, k0, VMMACH_TLB_MOD_BIT      # update TLB
+       blt     k1, zero, 4f                    # not found!!!
+       mtc0    k0, MACH_COP_0_TLB_LOW
+       li      k1, MACH_CACHED_MEMORY_ADDR
+       subu    k0, k0, k1
+       srl     k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT
+       la      k1, pmap_attributes
+       add     k0, k0, k1
+       lbu     k1, 0(k0)                       # fetch old value
+       nop
+       or      k1, k1, 1                       # set modified bit
+       sb      k1, 0(k0)                       # save new value
+       mfc0    k0, MACH_COP_0_EXC_PC           # get return address
+       nop
+       j       k0
+       rfe
+4:
+       break   0                               # panic
+       .set    reorder
+       .set    at
+#endif
+END(MachTLBModException)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachTLBMissException --
+ *
+ *     Handle a TLB miss exception from kernel mode.
+ *     The BaddVAddr, Context, and EntryHi registers contain the failed
+ *     virtual address.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(MachTLBMissException)
+       .set    noreorder
+       .set    noat
+       mfc0    k0, MACH_COP_0_BAD_VADDR        # get the fault address
+       li      k1, MACH_KSEG2_ADDR             # compute index
+       subu    k0, k0, k1
+       srl     k0, k0, PGSHIFT
+       li      k1, PMAP_HASH_KPAGES * NPTEPG   # index within range?
+       sltu    k1, k0, k1
+       beq     k1, zero, SlowFault             # No. do it the long way
+       sll     k0, k0, 2                       # compute offset from index
+       lw      k0, PMAP_HASH_KADDR(k0)         # get PTE entry
+       mfc0    k1, MACH_COP_0_EXC_PC           # get return address
+       mtc0    k0, MACH_COP_0_TLB_LOW          # save PTE entry
+       and     k0, k0, PG_V                    # make sure it's valid
+       beq     k0, zero, SlowFault             # No. do it the long way
+       nop
+       tlbwr                                   # update TLB
+       j       k1
+       rfe
+       .set    reorder
+       .set    at
+END(MachTLBMissException)
+
+/*
+ * Set/clear software interrupt routines.
+ */
+
+LEAF(setsoftclock)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_CAUSE_REG        # read cause register
+       nop
+       or      v0, v0, MACH_SOFT_INT_MASK_0    # set soft clock interrupt
+       mtc0    v0, MACH_COP_0_CAUSE_REG        # save it
+       j       ra
+       nop
+       .set    reorder
+END(setsoftclock)
+
+LEAF(clearsoftclock)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_CAUSE_REG        # read cause register
+       nop
+       and     v0, v0, ~MACH_SOFT_INT_MASK_0   # clear soft clock interrupt
+       mtc0    v0, MACH_COP_0_CAUSE_REG        # save it
+       j       ra
+       nop
+       .set    reorder
+END(clearsoftclock)
+
+LEAF(setsoftnet)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_CAUSE_REG        # read cause register
+       nop
+       or      v0, v0, MACH_SOFT_INT_MASK_1    # set soft net interrupt
+       mtc0    v0, MACH_COP_0_CAUSE_REG        # save it
+       j       ra
+       nop
+       .set    reorder
+END(setsoftnet)
+
+LEAF(clearsoftnet)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_CAUSE_REG        # read cause register
+       nop
+       and     v0, v0, ~MACH_SOFT_INT_MASK_1   # clear soft net interrupt
+       mtc0    v0, MACH_COP_0_CAUSE_REG        # save it
+       j       ra
+       nop
+       .set    reorder
+END(clearsoftnet)
+
+/*
+ * Set/change interrupt priority routines.
+ */
+
+LEAF(MachEnableIntr)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       nop
+       or      v0, v0, MACH_SR_INT_ENA_CUR
+       mtc0    v0, MACH_COP_0_STATUS_REG       # enable all interrupts
+       j       ra
+       nop
+       .set    reorder
+END(MachEnableIntr)
+
+LEAF(spl0)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       nop
+       or      t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       mtc0    t0, MACH_COP_0_STATUS_REG       # enable all interrupts
+       j       ra
+       and     v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       .set    reorder
+END(spl0)
+
+LEAF(splsoftclock)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       li      t0, ~MACH_SOFT_INT_MASK_1       # disable soft clock
+       and     t0, t0, v0
+       mtc0    t0, MACH_COP_0_STATUS_REG       # save it
+       j       ra
+       and     v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       .set    reorder
+END(splsoftclock)
+
+LEAF(splbio)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       li      t0, ~MACH_INT_MASK_0            # disable SCSI interrupts
+       and     t0, t0, v0
+       mtc0    t0, MACH_COP_0_STATUS_REG       # save it
+       j       ra
+       and     v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       .set    reorder
+END(splbio)
+
+/*
+ * Block interrupts for any device that could allocate memory at interrupt
+ * time.
+ */
+LEAF(splnet)
+ALEAF(splimp)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       li      t0, ~MACH_INT_MASK_1            # disable network interrupts
+       and     t0, t0, v0
+       mtc0    t0, MACH_COP_0_STATUS_REG       # save it
+       j       ra
+       and     v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       .set    reorder
+END(splnet)
+
+LEAF(spltty)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       li      t0, ~MACH_INT_MASK_2            # disable tty interrupts
+       and     t0, t0, v0
+       mtc0    t0, MACH_COP_0_STATUS_REG       # save it
+       j       ra
+       and     v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       .set    reorder
+END(spltty)
+
+LEAF(splclock)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       li      t0, ~MACH_INT_MASK_3            # disable clock interrupts
+       and     t0, t0, v0
+       mtc0    t0, MACH_COP_0_STATUS_REG       # save it
+       j       ra
+       and     v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       .set    reorder
+END(splclock)
+
+LEAF(splhigh)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG       # read status register
+       li      t0, ~MACH_SR_INT_ENA_CUR        # disable all interrupts
+       and     t0, t0, v0
+       mtc0    t0, MACH_COP_0_STATUS_REG       # save it
+       j       ra
+       and     v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       .set    reorder
+END(splhigh)
+
+/*
+ * Restore saved interrupt mask.
+ */
+LEAF(splx)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_STATUS_REG
+       li      t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
+       and     t0, t0, v0
+       or      t0, t0, a0
+       mtc0    t0, MACH_COP_0_STATUS_REG
+       j       ra
+       nop
+       .set    reorder
+END(splx)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachEmptyWriteBuffer --
+ *
+ *     Return when the write buffer is empty.
+ *
+ *     MachEmptyWriteBuffer()
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(MachEmptyWriteBuffer)
+       .set    noreorder
+       nop
+       nop
+       nop
+       nop
+1:     bc0f    1b
+       nop
+       j       ra
+       nop
+       .set    reorder
+END(MachEmptyWriteBuffer)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachTLBWriteIndexed --
+ *
+ *     Write the given entry into the TLB at the given index.
+ *
+ *     MachTLBWriteIndexed(index, highEntry, lowEntry)
+ *             int index;
+ *             int highEntry;
+ *             int lowEntry;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     TLB entry set.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachTLBWriteIndexed)
+       .set    noreorder
+       mfc0    t1, MACH_COP_0_STATUS_REG       # Save the status register.
+       mfc0    t0, MACH_COP_0_TLB_HI           # Save the current PID.
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+
+       sll     a0, a0, VMMACH_TLB_INDEX_SHIFT
+       mtc0    a0, MACH_COP_0_TLB_INDEX        # Set the index.
+       mtc0    a1, MACH_COP_0_TLB_HI           # Set up entry high.
+       mtc0    a2, MACH_COP_0_TLB_LOW          # Set up entry low.
+       nop
+       tlbwi                                   # Write the TLB
+
+       mtc0    t0, MACH_COP_0_TLB_HI           # Restore the PID.
+       j       ra
+       mtc0    t1, MACH_COP_0_STATUS_REG       # Restore the status register
+       .set    reorder
+END(MachTLBWriteIndexed)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachTLBWriteRandom --
+ *
+ *     Write the given entry into the TLB at a random location.
+ *
+ *     MachTLBWriteRandom(highEntry, lowEntry)
+ *             unsigned highEntry;
+ *             unsigned lowEntry;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     TLB entry set.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachTLBWriteRandom)
+       .set    noreorder
+       mfc0    v1, MACH_COP_0_STATUS_REG       # Save the status register.
+       mfc0    v0, MACH_COP_0_TLB_HI           # Save the current PID.
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+
+       mtc0    a0, MACH_COP_0_TLB_HI           # Set up entry high.
+       mtc0    a1, MACH_COP_0_TLB_LOW          # Set up entry low.
+       nop
+       tlbwr                                   # Write the TLB
+
+       mtc0    v0, MACH_COP_0_TLB_HI           # Restore the PID.
+       j       ra
+       mtc0    v1, MACH_COP_0_STATUS_REG       # Restore the status register
+       .set    reorder
+END(MachTLBWriteRandom)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachSetPID --
+ *
+ *     Write the given pid into the TLB pid reg.
+ *
+ *     MachSetPID(pid)
+ *             int pid;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     PID set in the entry hi register.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachSetPID)
+       .set    noreorder
+       sll     a0, a0, VMMACH_TLB_PID_SHIFT    # put PID in right spot
+       mtc0    a0, MACH_COP_0_TLB_HI           # Write the hi reg value
+       j       ra
+       nop
+       .set    reorder
+END(MachSetPID)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachTLBFlush --
+ *
+ *     Flush the "random" entries from the TLB.
+ *
+ *     MachTLBFlush()
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     The TLB is flushed.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachTLBFlush)
+       .set    noreorder
+       mfc0    v1, MACH_COP_0_STATUS_REG       # Save the status register.
+       mfc0    t0, MACH_COP_0_TLB_HI           # Save the PID
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+       li      t1, MACH_RESERVED_ADDR          # invalid address
+       mtc0    t1, MACH_COP_0_TLB_HI           # Mark entry high as invalid
+       mtc0    zero, MACH_COP_0_TLB_LOW        # Zero out low entry.
+/*
+ * Align the starting value (t1), the increment (t2) and the upper bound (t3).
+ */
+       li      t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
+       li      t2, 1 << VMMACH_TLB_INDEX_SHIFT
+       li      t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
+1:
+       mtc0    t1, MACH_COP_0_TLB_INDEX        # Set the index register.
+       addu    t1, t1, t2                      # Increment index.
+       bne     t1, t3, 1b                      # NB: always executes next
+       tlbwi                                   # Write the TLB entry.
+
+       mtc0    t0, MACH_COP_0_TLB_HI           # Restore the PID
+       j       ra
+       mtc0    v1, MACH_COP_0_STATUS_REG       # Restore the status register
+       .set    reorder
+END(MachTLBFlush)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachTLBFlushPID --
+ *
+ *     Flush all entries with the given PID from the TLB.
+ *
+ *     MachTLBFlushPID(pid)
+ *             int pid;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     All entries corresponding to this PID are flushed.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachTLBFlushPID)
+       .set    noreorder
+       mfc0    v1, MACH_COP_0_STATUS_REG       # Save the status register.
+       mfc0    t0, MACH_COP_0_TLB_HI           # Save the current PID
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+       sll     a0, a0, VMMACH_TLB_PID_SHIFT    # Align the pid to flush.
+/*
+ * Align the starting value (t1), the increment (t2) and the upper bound (t3).
+ */
+       li      t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
+       li      t2, 1 << VMMACH_TLB_INDEX_SHIFT
+       li      t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
+       mtc0    t1, MACH_COP_0_TLB_INDEX        # Set the index register
+1:
+       addu    t1, t1, t2                      # Increment index.
+       tlbr                                    # Read from the TLB
+       mfc0    t4, MACH_COP_0_TLB_HI           # Fetch the hi register.
+       nop
+       and     t4, t4, VMMACH_TLB_PID          # compare PID's
+       bne     t4, a0, 2f
+       li      v0, MACH_RESERVED_ADDR          # invalid address
+       mtc0    v0, MACH_COP_0_TLB_HI           # Mark entry high as invalid
+       mtc0    zero, MACH_COP_0_TLB_LOW        # Zero out low entry.
+       nop
+       tlbwi                                   # Write the entry.
+2:
+       bne     t1, t3, 1b
+       mtc0    t1, MACH_COP_0_TLB_INDEX        # Set the index register
+
+       mtc0    t0, MACH_COP_0_TLB_HI           # restore PID
+       j       ra
+       mtc0    v1, MACH_COP_0_STATUS_REG       # Restore the status register
+       .set    reorder
+END(MachTLBFlushPID)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachTLBFlushAddr --
+ *
+ *     Flush any TLB entries for the given address.
+ *
+ *     MachTLBFlushAddr(virtaddr)
+ *             unsigned virtaddr;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     The process's page is flushed from the TLB.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachTLBFlushAddr)
+       .set    noreorder
+       mfc0    v1, MACH_COP_0_STATUS_REG       # Save the status register.
+       mfc0    t0, MACH_COP_0_TLB_HI           # Get current PID
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+       mtc0    a0, MACH_COP_0_TLB_HI           # look for addr & PID
+       mtc0    zero, MACH_COP_0_TLB_LOW        # look for matching PID
+       nop
+       tlbp                                    # Probe for the entry.
+       mfc0    v0, MACH_COP_0_TLB_INDEX        # See what we got
+       li      t1, MACH_RESERVED_ADDR          # Load invalid entry.
+       bltz    v0, 1f                          # index < 0 => !found
+       mtc0    t1, MACH_COP_0_TLB_HI           # Prepare index hi.
+       nop
+       tlbwi
+1:
+       mtc0    t0, MACH_COP_0_TLB_HI           # restore PID
+       j       ra
+       mtc0    v1, MACH_COP_0_STATUS_REG       # Restore the status register
+       .set    reorder
+END(MachTLBFlushAddr)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachTLBUpdate --
+ *
+ *     Update the TLB if highreg is found.
+ *
+ *     MachTLBUpdate(highreg, lowreg)
+ *             unsigned highreg, lowreg;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachTLBUpdate)
+       .set    noreorder
+       mfc0    v1, MACH_COP_0_STATUS_REG       # Save the status register.
+       mfc0    t0, MACH_COP_0_TLB_HI           # Save current PID
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+       mtc0    a0, MACH_COP_0_TLB_HI           # init high reg.
+       mtc0    a1, MACH_COP_0_TLB_LOW          # init low reg.
+       nop
+       tlbp                                    # Probe for the entry.
+       mfc0    v0, MACH_COP_0_TLB_INDEX        # See what we got
+       nop
+       bltz    v0, 1f                          # index < 0 => !found
+       nop
+       tlbwi
+1:
+       mtc0    t0, MACH_COP_0_TLB_HI           # restore PID
+       j       ra
+       mtc0    v1, MACH_COP_0_STATUS_REG       # Restore the status register
+       .set    reorder
+END(MachTLBUpdate)
+
+#ifdef DEBUG
+/*--------------------------------------------------------------------------
+ *
+ * MachTLBDump --
+ *
+ *     Print all entries in the TLB if 'all' is true; otherwise, just
+ *     print valid entries.
+ *
+ *     MachTLBDump(all)
+ *             int all;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *--------------------------------------------------------------------------
+ */
+
+#define DUMP_FRAME_SIZE        (STAND_FRAME_SIZE + 4*4)
+
+NON_LEAF(MachTLBDump, DUMP_FRAME_SIZE, ra)
+       .set    noreorder
+       subu    sp, sp, DUMP_FRAME_SIZE
+       sw      s0, STAND_RA_OFFSET(sp)
+       sw      s1, STAND_RA_OFFSET+4(sp)
+       sw      s2, STAND_RA_OFFSET+8(sp)
+       sw      s3, STAND_RA_OFFSET+12(sp)
+       sw      ra, STAND_RA_OFFSET+16(sp)
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+
+       mfc0    s0, MACH_COP_0_TLB_HI           # Save the current PID
+       sw      a0, DUMP_FRAME_SIZE(sp)         # Save 'all'
+/*
+ * Align the starting value (s1), the increment (s2) and the upper bound (s3).
+ */
+       move    s1, zero
+       li      s2, 1 << VMMACH_TLB_INDEX_SHIFT
+       li      s3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
+       mtc0    s1, MACH_COP_0_TLB_INDEX        # Set the index register
+1:
+       addu    s1, s1, s2                      # Increment index.
+       tlbr                                    # Read from the TLB
+       bne     a0, zero, 2f                    # skip valid check if 'all'
+       mfc0    a3, MACH_COP_0_TLB_LOW          # Fetch the low register.
+       nop
+       and     t0, a3, PG_V                    # is it valid?
+       beq     t0, zero, 3f
+       nop
+2:
+       mfc0    a2, MACH_COP_0_TLB_HI           # Fetch the hi register.
+       PRINTF("%d: hi %x low %x\n")            # print entry
+       srl     a1, s1, VMMACH_TLB_INDEX_SHIFT  # this is in the delay slot
+       lw      a0, DUMP_FRAME_SIZE(sp)         # get 'all'
+3:
+       bne     s1, s3, 1b
+       mtc0    s1, MACH_COP_0_TLB_INDEX        # Set the index register
+
+       mtc0    s0, MACH_COP_0_TLB_HI           # restore PID
+       nop
+       lw      ra, STAND_RA_OFFSET+16(sp)
+       lw      s0, STAND_RA_OFFSET(sp)
+       lw      s1, STAND_RA_OFFSET+4(sp)
+       lw      s2, STAND_RA_OFFSET+8(sp)
+       lw      s3, STAND_RA_OFFSET+12(sp)
+       j       ra
+       addu    sp, sp, DUMP_FRAME_SIZE
+       .set    reorder
+END(MachTLBDump)
+
+       .comm   tlbhi, 4
+       .comm   tlblo, 4
+LEAF(MachTLBFind)
+       .set    noreorder
+       mfc0    v1, MACH_COP_0_STATUS_REG       # Save the status register.
+       mfc0    t0, MACH_COP_0_TLB_HI           # Get current PID
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts
+       mtc0    a0, MACH_COP_0_TLB_HI           # Set up entry high.
+       mtc0    a1, MACH_COP_0_TLB_LOW          # Set up entry low.
+       nop
+       tlbp                                    # Probe for the entry.
+       mfc0    v0, MACH_COP_0_TLB_INDEX        # See what we got
+       mfc0    t1, MACH_COP_0_TLB_HI           # See what we got
+       mfc0    t2, MACH_COP_0_TLB_LOW          # See what we got
+       sw      t1, tlbhi
+       sw      t2, tlblo
+       mtc0    t0, MACH_COP_0_TLB_HI           # Get current PID
+       j       ra
+       mtc0    v1, MACH_COP_0_STATUS_REG       # Restore the status register
+       .set    reorder
+END(MachTLBFind)
+
+/*--------------------------------------------------------------------------
+ *
+ * MachGetPID --
+ *
+ *     MachGetPID()
+ *
+ * Results:
+ *     Returns the current TLB pid reg.
+ *
+ * Side effects:
+ *     None.
+ *
+ *--------------------------------------------------------------------------
+ */
+LEAF(MachGetPID)
+       .set    noreorder
+       mfc0    v0, MACH_COP_0_TLB_HI           # get PID
+       nop
+       and     v0, v0, VMMACH_TLB_PID          # mask off PID
+       j       ra
+       srl     v0, v0, VMMACH_TLB_PID_SHIFT    # put PID in right spot
+       .set    reorder
+END(MachGetPID)
+#endif /* DEBUG */
+
+/*----------------------------------------------------------------------------
+ *
+ * MachSwitchFPState --
+ *
+ *     Save the current state into 'from' and restore it from 'to'.
+ *
+ *     MachSwitchFPState(from, to)
+ *             struct proc *from;
+ *             struct user *to;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(MachSwitchFPState)
+       .set    noreorder
+       mfc0    t1, MACH_COP_0_STATUS_REG       # Save old SR
+       li      t0, MACH_SR_COP_1_BIT           # Disable interrupts and
+       mtc0    t0, MACH_COP_0_STATUS_REG       #  enable the coprocessor
+
+       beq     a0, zero, 1f                    # skip save if NULL pointer
+       nop
+/*
+ * First read out the status register to make sure that all FP operations
+ * have completed.
+ */
+       lw      a0, P_ADDR(a0)                  # get pointer to pcb for proc
+       cfc1    t0, MACH_FPC_CSR                # stall til FP done, get status
+       li      t3, ~MACH_SR_COP_1_BIT
+       lw      t2, U_PCB_REGS+(PS * 4)(a0)     # get CPU status register
+       sw      t0, U_PCB_FPREGS+(32 * 4)(a0)   # save FP status
+       and     t2, t2, t3                      # clear COP_1 enable bit
+       sw      t2, U_PCB_REGS+(PS * 4)(a0)     # save new status register
+/*
+ * Save the floating point registers.
+ */
+       swc1    $f0, U_PCB_FPREGS+(0 * 4)(a0)
+       swc1    $f1, U_PCB_FPREGS+(1 * 4)(a0)
+       swc1    $f2, U_PCB_FPREGS+(2 * 4)(a0)
+       swc1    $f3, U_PCB_FPREGS+(3 * 4)(a0)
+       swc1    $f4, U_PCB_FPREGS+(4 * 4)(a0)
+       swc1    $f5, U_PCB_FPREGS+(5 * 4)(a0)
+       swc1    $f6, U_PCB_FPREGS+(6 * 4)(a0)
+       swc1    $f7, U_PCB_FPREGS+(7 * 4)(a0)
+       swc1    $f8, U_PCB_FPREGS+(8 * 4)(a0)
+       swc1    $f9, U_PCB_FPREGS+(9 * 4)(a0)
+       swc1    $f10, U_PCB_FPREGS+(10 * 4)(a0)
+       swc1    $f11, U_PCB_FPREGS+(11 * 4)(a0)
+       swc1    $f12, U_PCB_FPREGS+(12 * 4)(a0)
+       swc1    $f13, U_PCB_FPREGS+(13 * 4)(a0)
+       swc1    $f14, U_PCB_FPREGS+(14 * 4)(a0)
+       swc1    $f15, U_PCB_FPREGS+(15 * 4)(a0)
+       swc1    $f16, U_PCB_FPREGS+(16 * 4)(a0)
+       swc1    $f17, U_PCB_FPREGS+(17 * 4)(a0)
+       swc1    $f18, U_PCB_FPREGS+(18 * 4)(a0)
+       swc1    $f19, U_PCB_FPREGS+(19 * 4)(a0)
+       swc1    $f20, U_PCB_FPREGS+(20 * 4)(a0)
+       swc1    $f21, U_PCB_FPREGS+(21 * 4)(a0)
+       swc1    $f22, U_PCB_FPREGS+(22 * 4)(a0)
+       swc1    $f23, U_PCB_FPREGS+(23 * 4)(a0)
+       swc1    $f24, U_PCB_FPREGS+(24 * 4)(a0)
+       swc1    $f25, U_PCB_FPREGS+(25 * 4)(a0)
+       swc1    $f26, U_PCB_FPREGS+(26 * 4)(a0)
+       swc1    $f27, U_PCB_FPREGS+(27 * 4)(a0)
+       swc1    $f28, U_PCB_FPREGS+(28 * 4)(a0)
+       swc1    $f29, U_PCB_FPREGS+(29 * 4)(a0)
+       swc1    $f30, U_PCB_FPREGS+(30 * 4)(a0)
+       swc1    $f31, U_PCB_FPREGS+(31 * 4)(a0)
+
+1:
+/* 
+ *  Restore the floating point registers.
+ */
+       lw      t0, U_PCB_FPREGS+(32 * 4)(a1)   # get status register
+       lwc1    $f0, U_PCB_FPREGS+(0 * 4)(a1)
+       lwc1    $f1, U_PCB_FPREGS+(1 * 4)(a1)
+       lwc1    $f2, U_PCB_FPREGS+(2 * 4)(a1)
+       lwc1    $f3, U_PCB_FPREGS+(3 * 4)(a1)
+       lwc1    $f4, U_PCB_FPREGS+(4 * 4)(a1)
+       lwc1    $f5, U_PCB_FPREGS+(5 * 4)(a1)
+       lwc1    $f6, U_PCB_FPREGS+(6 * 4)(a1)
+       lwc1    $f7, U_PCB_FPREGS+(7 * 4)(a1)
+       lwc1    $f8, U_PCB_FPREGS+(8 * 4)(a1)
+       lwc1    $f9, U_PCB_FPREGS+(9 * 4)(a1)
+       lwc1    $f10, U_PCB_FPREGS+(10 * 4)(a1)
+       lwc1    $f11, U_PCB_FPREGS+(11 * 4)(a1)
+       lwc1    $f12, U_PCB_FPREGS+(12 * 4)(a1)
+       lwc1    $f13, U_PCB_FPREGS+(13 * 4)(a1)
+       lwc1    $f14, U_PCB_FPREGS+(14 * 4)(a1)
+       lwc1    $f15, U_PCB_FPREGS+(15 * 4)(a1)
+       lwc1    $f16, U_PCB_FPREGS+(16 * 4)(a1)
+       lwc1    $f17, U_PCB_FPREGS+(17 * 4)(a1)
+       lwc1    $f18, U_PCB_FPREGS+(18 * 4)(a1)
+       lwc1    $f19, U_PCB_FPREGS+(19 * 4)(a1)
+       lwc1    $f20, U_PCB_FPREGS+(20 * 4)(a1)
+       lwc1    $f21, U_PCB_FPREGS+(21 * 4)(a1)
+       lwc1    $f22, U_PCB_FPREGS+(22 * 4)(a1)
+       lwc1    $f23, U_PCB_FPREGS+(23 * 4)(a1)
+       lwc1    $f24, U_PCB_FPREGS+(24 * 4)(a1)
+       lwc1    $f25, U_PCB_FPREGS+(25 * 4)(a1)
+       lwc1    $f26, U_PCB_FPREGS+(26 * 4)(a1)
+       lwc1    $f27, U_PCB_FPREGS+(27 * 4)(a1)
+       lwc1    $f28, U_PCB_FPREGS+(28 * 4)(a1)
+       lwc1    $f29, U_PCB_FPREGS+(29 * 4)(a1)
+       lwc1    $f30, U_PCB_FPREGS+(30 * 4)(a1)
+       lwc1    $f31, U_PCB_FPREGS+(31 * 4)(a1)
+
+       and     t0, t0, ~MACH_FPC_EXCEPTION_BITS
+       ctc1    t0, MACH_FPC_CSR
+       nop
+
+       mtc0    t1, MACH_COP_0_STATUS_REG       # Restore the status register.
+       j       ra
+       nop
+       .set    reorder
+END(MachSwitchFPState)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachSaveCurFPState --
+ *
+ *     Save the current floating point coprocessor state.
+ *
+ *     MachSaveCurFPState(p)
+ *             struct proc *p;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(MachSaveCurFPState)
+       .set    noreorder
+       lw      a0, P_ADDR(a0)                  # get pointer to pcb for proc
+       mfc0    t1, MACH_COP_0_STATUS_REG       # Disable interrupts and
+       li      t0, MACH_SR_COP_1_BIT           #  enable the coprocessor
+       mtc0    t0, MACH_COP_0_STATUS_REG
+       nop
+/*
+ * First read out the status register to make sure that all FP operations
+ * have completed.
+ */
+       lw      t2, U_PCB_REGS+(PS * 4)(a0)     # get CPU status register
+       li      t3, ~MACH_SR_COP_1_BIT
+       and     t2, t2, t3                      # clear COP_1 enable bit
+       cfc1    t0, MACH_FPC_CSR                # stall til FP done, get status
+       sw      t2, U_PCB_REGS+(PS * 4)(a0)     # save new status register
+       sw      t0, U_PCB_FPREGS+(32 * 4)(a0)   # save FP status
+/*
+ * Save the floating point registers.
+ */
+       swc1    $f0, U_PCB_FPREGS+(0 * 4)(a0)
+       swc1    $f1, U_PCB_FPREGS+(1 * 4)(a0)
+       swc1    $f2, U_PCB_FPREGS+(2 * 4)(a0)
+       swc1    $f3, U_PCB_FPREGS+(3 * 4)(a0)
+       swc1    $f4, U_PCB_FPREGS+(4 * 4)(a0)
+       swc1    $f5, U_PCB_FPREGS+(5 * 4)(a0)
+       swc1    $f6, U_PCB_FPREGS+(6 * 4)(a0)
+       swc1    $f7, U_PCB_FPREGS+(7 * 4)(a0)
+       swc1    $f8, U_PCB_FPREGS+(8 * 4)(a0)
+       swc1    $f9, U_PCB_FPREGS+(9 * 4)(a0)
+       swc1    $f10, U_PCB_FPREGS+(10 * 4)(a0)
+       swc1    $f11, U_PCB_FPREGS+(11 * 4)(a0)
+       swc1    $f12, U_PCB_FPREGS+(12 * 4)(a0)
+       swc1    $f13, U_PCB_FPREGS+(13 * 4)(a0)
+       swc1    $f14, U_PCB_FPREGS+(14 * 4)(a0)
+       swc1    $f15, U_PCB_FPREGS+(15 * 4)(a0)
+       swc1    $f16, U_PCB_FPREGS+(16 * 4)(a0)
+       swc1    $f17, U_PCB_FPREGS+(17 * 4)(a0)
+       swc1    $f18, U_PCB_FPREGS+(18 * 4)(a0)
+       swc1    $f19, U_PCB_FPREGS+(19 * 4)(a0)
+       swc1    $f20, U_PCB_FPREGS+(20 * 4)(a0)
+       swc1    $f21, U_PCB_FPREGS+(21 * 4)(a0)
+       swc1    $f22, U_PCB_FPREGS+(22 * 4)(a0)
+       swc1    $f23, U_PCB_FPREGS+(23 * 4)(a0)
+       swc1    $f24, U_PCB_FPREGS+(24 * 4)(a0)
+       swc1    $f25, U_PCB_FPREGS+(25 * 4)(a0)
+       swc1    $f26, U_PCB_FPREGS+(26 * 4)(a0)
+       swc1    $f27, U_PCB_FPREGS+(27 * 4)(a0)
+       swc1    $f28, U_PCB_FPREGS+(28 * 4)(a0)
+       swc1    $f29, U_PCB_FPREGS+(29 * 4)(a0)
+       swc1    $f30, U_PCB_FPREGS+(30 * 4)(a0)
+       swc1    $f31, U_PCB_FPREGS+(31 * 4)(a0)
+
+       mtc0    t1, MACH_COP_0_STATUS_REG       # Restore the status register.
+       j       ra
+       nop
+       .set    reorder
+END(MachSaveCurFPState)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachFPInterrupt --
+ *
+ *     Handle a floating point interrupt.
+ *
+ *     MachFPInterrupt(statusReg, causeReg, pc)
+ *             unsigned statusReg;
+ *             unsigned causeReg;
+ *             unsigned pc;
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra)
+       .set    noreorder
+       subu    sp, sp, STAND_FRAME_SIZE
+       mfc0    t0, MACH_COP_0_STATUS_REG
+       sw      ra, STAND_RA_OFFSET(sp)
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+
+       or      t1, t0, MACH_SR_COP_1_BIT
+       mtc0    t1, MACH_COP_0_STATUS_REG
+       nop
+       nop
+       cfc1    t1, MACH_FPC_CSR        # stall til FP done, get status
+       nop
+       .set    reorder
+       sll     t2, t1, (31 - 17)       # unimplemented operation?
+       bgez    t2, 3f                  # no, normal trap
+/*
+ * We got an unimplemented operation trap so
+ * fetch the instruction, compute the next PC and emulate the instruction.
+ */
+       bgez    a1, 1f                  # Check the branch delay bit.
+/*
+ * The instruction is in the branch delay slot so the branch will have to
+ * be emulated to get the resulting PC.
+ */
+       sw      a2, STAND_FRAME_SIZE + 8(sp)
+       li      a0, UADDR+U_PCB_REGS    # first arg is ptr to CPU registers
+       move    a1, a2                  # second arg is instruction PC
+       move    a2, t1                  # third arg is floating point CSR
+       move    a3, zero                # fourth arg is FALSE
+       jal     MachEmulateBranch       # compute PC after branch
+/*
+ * Now load the floating-point instruction in the branch delay slot
+ * to be emulated.
+ */
+       lw      a2, STAND_FRAME_SIZE + 8(sp)    # restore EXC pc
+       lw      a0, 4(a2)                       # a0 = coproc instruction
+       b       2f
+/*
+ * This is not in the branch delay slot so calculate the resulting
+ * PC (epc + 4) into v0 and continue to MachEmulateFP().
+ */
+1:
+       lw      a0, 0(a2)                       # a0 = coproc instruction
+       addu    v0, a2, 4                       # v0 = next pc
+2:
+       sw      v0, UADDR+U_PCB_REGS+(PC * 4)   # save new pc
+/*
+ * Check to see if the instruction to be emulated is a floating-point
+ * instruction.
+ */
+       srl     a3, a0, MACH_OPCODE_SHIFT
+       beq     a3, MACH_OPCODE_C1, 4f          # this should never fail
+/*
+ * Send a floating point exception signal to the current process.
+ */
+3:
+       lw      a0, curproc                     # get current process
+       cfc1    a2, MACH_FPC_CSR                # code = FP execptions
+       li      a1, SIGFPE
+       ctc1    zero, MACH_FPC_CSR              # Clear exceptions
+       jal     trapsignal
+       b       FPReturn
+
+/*
+ * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate.
+ */
+4:
+       jal     MachEmulateFP
+
+/*
+ * Turn off the floating point coprocessor and return.
+ */
+FPReturn:
+       .set    noreorder
+       mfc0    t0, MACH_COP_0_STATUS_REG
+       lw      ra, STAND_RA_OFFSET(sp)
+       and     t0, t0, ~MACH_SR_COP_1_BIT
+       mtc0    t0, MACH_COP_0_STATUS_REG
+       j       ra
+       addu    sp, sp, STAND_FRAME_SIZE
+       .set    reorder
+END(MachFPInterrupt)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachConfigCache --
+ *
+ *     Size the caches.
+ *     NOTE: should only be called from mach_init().
+ *
+ * Results:
+ *             None.
+ *
+ * Side effects:
+ *     The size of the data cache is stored into machDataCacheSize and the
+ *     size of instruction cache is stored into machInstCacheSize.
+ *
+ *----------------------------------------------------------------------------
+ */
+NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra)
+       .set    noreorder
+       subu    sp, sp, STAND_FRAME_SIZE
+       sw      ra, STAND_RA_OFFSET(sp)         # Save return address.
+       .mask   0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts.
+       la      v0, 1f
+       or      v0, MACH_UNCACHED_MEMORY_ADDR   # Run uncached.
+       j       v0
+       nop
+1:
+/*
+ * This works because jal doesn't change pc[31..28] and the
+ * linker still thinks SizeCache is in the cached region so it computes
+ * the correct address without complaining.
+ */
+       jal     SizeCache                       # Get the size of the d-cache.
+       nop
+       sw      v0, machDataCacheSize
+       nop                                     # Make sure sw out of pipe
+       nop
+       nop
+       nop
+       li      v0, MACH_SR_SWAP_CACHES         # Swap caches
+       mtc0    v0, MACH_COP_0_STATUS_REG
+       nop                                     # Insure caches stable
+       nop
+       nop
+       nop
+       jal     SizeCache                       # Get the size of the i-cache.
+       nop
+       sw      v0, machInstCacheSize           
+       nop                                     # Make sure sw out of pipe
+       nop
+       nop
+       nop
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Swap back caches. 
+       nop
+       nop
+       nop
+       nop
+       la      t0, 1f
+       j       t0                              # Back to cached mode
+       nop
+1:
+       lw      ra, STAND_RA_OFFSET(sp)         # Restore return addr
+       addu    sp, sp, STAND_FRAME_SIZE        # Restore sp.
+       j       ra
+       nop
+       .set    reorder
+END(MachConfigCache)
+
+/*----------------------------------------------------------------------------
+ *
+ * SizeCache --
+ *
+ *     Get the size of the cache.
+ *
+ * Results:
+ *     The size of the cache.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(SizeCache)
+       .set    noreorder
+       mfc0    t0, MACH_COP_0_STATUS_REG       # Save the current status reg.
+       nop                             
+       or      v0, t0, MACH_SR_ISOL_CACHES     # Isolate the caches.
+       nop                                     # Make sure no stores in pipe
+       mtc0    v0, MACH_COP_0_STATUS_REG
+       nop                                     # Make sure isolated
+       nop
+       nop
+/*
+ * Clear cache size boundaries.
+ */
+       li      v0, MACH_MIN_CACHE_SIZE
+1:
+       sw      zero, MACH_CACHED_MEMORY_ADDR(v0)       # Clear cache memory
+       sll     v0, v0, 1
+       bleu    v0, +MACH_MAX_CACHE_SIZE, 1b
+       nop
+       li      v0, -1
+       sw      v0, MACH_CACHED_MEMORY_ADDR(zero)       # Store marker in cache
+       li      v0, MACH_MIN_CACHE_SIZE
+2:
+       lw      v1, MACH_CACHED_MEMORY_ADDR(v0)         # Look for marker
+       nop                     
+       bne     v1, zero, 3f                            # Found marker.
+       nop
+       sll     v0, v0, 1                               # cache size * 2
+       bleu    v0, +MACH_MAX_CACHE_SIZE, 2b            # keep looking
+       nop
+       move    v0, zero                                # must be no cache
+3:
+       mtc0    t0, MACH_COP_0_STATUS_REG
+       nop                                             # Make sure unisolated
+       nop
+       nop
+       nop
+       j       ra
+       nop
+       .set    reorder
+END(SizeCache)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachFlushCache --
+ *
+ *     Flush the caches.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     The contents of the caches is flushed.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(MachFlushCache)
+       .set    noreorder
+       lw      t1, machInstCacheSize           # Must load before isolating
+       lw      t2, machDataCacheSize           # Must load before isolating
+       mfc0    t3, MACH_COP_0_STATUS_REG       # Save the status register.
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts.
+       la      v0, 1f
+       or      v0, MACH_UNCACHED_MEMORY_ADDR   # Run uncached.
+       j       v0                      
+       nop
+/*
+ * Flush the instruction cache.
+ */
+1:
+       li      v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
+       mtc0    v0, MACH_COP_0_STATUS_REG       # Isolate and swap caches.
+       li      t0, MACH_UNCACHED_MEMORY_ADDR
+       subu    t0, t0, t1
+       li      t1, MACH_UNCACHED_MEMORY_ADDR
+       la      v0, 1f                          # Run cached
+       j       v0
+       nop
+1:
+       sb      zero, 0(t0)
+       sb      zero, 4(t0)
+       sb      zero, 8(t0)
+       sb      zero, 12(t0)
+       sb      zero, 16(t0)
+       sb      zero, 20(t0)
+       sb      zero, 24(t0)
+       addu    t0, t0, 32
+       bne     t0, t1, 1b
+       sb      zero, -4(t0)
+
+       la      v0, 1f
+       or      v0, MACH_UNCACHED_MEMORY_ADDR
+       j       v0                              # Run uncached
+       nop
+/*
+ * Flush the data cache.
+ */
+1:
+       li      v0, MACH_SR_ISOL_CACHES
+       mtc0    v0, MACH_COP_0_STATUS_REG       # Isolate and swap back caches
+       li      t0, MACH_UNCACHED_MEMORY_ADDR
+       subu    t0, t0, t2
+       la      v0, 1f
+       j       v0                              # Back to cached mode
+       nop
+1:
+       sb      zero, 0(t0)
+       sb      zero, 4(t0)
+       sb      zero, 8(t0)
+       sb      zero, 12(t0)
+       sb      zero, 16(t0)
+       sb      zero, 20(t0)
+       sb      zero, 24(t0)
+       addu    t0, t0, 32
+       bne     t0, t1, 1b
+       sb      zero, -4(t0)
+
+       nop                                     # Insure isolated stores 
+       nop                                     #   out of pipe.
+       nop
+       nop
+       mtc0    t3, MACH_COP_0_STATUS_REG       # Restore status reg.
+       nop                                     # Insure cache unisolated.
+       nop
+       nop
+       nop
+       j       ra
+       nop
+       .set    reorder
+END(MachFlushCache)
+
+/*----------------------------------------------------------------------------
+ *
+ * MachFlushICache --
+ *
+ *     MachFlushICache(addr, len)
+ *
+ *     Flush instruction cache for range of addr to addr + len - 1.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     The contents of the cache is flushed.
+ *
+ *----------------------------------------------------------------------------
+ */
+LEAF(MachFlushICache)
+       .set    noreorder
+       lw      t1, machInstCacheSize
+       mfc0    t3, MACH_COP_0_STATUS_REG       # Save SR
+       subu    t0, t1, 1                       # t0 = size - 1
+       and     a0, a0, t0                      # mask off address bits
+       addu    t0, t0, MACH_UNCACHED_MEMORY_ADDR
+       subu    t0, t0, t1
+       mtc0    zero, MACH_COP_0_STATUS_REG     # Disable interrupts.
+
+       la      v0, 1f
+       or      v0, MACH_UNCACHED_MEMORY_ADDR   # Run uncached.
+       j       v0
+       nop
+1:
+       li      v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
+       mtc0    v0, MACH_COP_0_STATUS_REG
+       bltu    t1, a1, 1f                      # cache is smaller than region
+       nop
+       move    t1, a1
+1:
+       addu    t1, t1, t0                      # compute ending address
+       la      v0, 1f                          # run cached
+       j       v0
+       nop
+1:
+       sb      zero, 0(t0)
+       sb      zero, 4(t0)
+       sb      zero, 8(t0)
+       sb      zero, 12(t0)
+       sb      zero, 16(t0)
+       sb      zero, 20(t0)
+       sb      zero, 24(t0)
+       addu    t0, t0, 32
+       bltu    t0, t1, 1b
+       sb      zero, -4(t0)
+
+       la      v0, 1f
+       or      v0, MACH_UNCACHED_MEMORY_ADDR
+       j       v0                              # Run uncached
+       nop
+1:
+       nop                             # insure isolated stores out of pipe
+       mtc0    zero, MACH_COP_0_STATUS_REG     # unisolate, unswap
+       nop                                     # keep pipeline clean
+       nop
+       nop
+       mtc0    t3, MACH_COP_0_STATUS_REG       # enable interrupts
+       j       ra                              # return and run cached
+       nop
+       .set    reorder
+END(MachFlushICache)
diff --git a/usr/src/sys/pmax/pmax/machdep.c b/usr/src/sys/pmax/pmax/machdep.c
new file mode 100644 (file)
index 0000000..097c28a
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: machdep.c 1.63 91/04/24$
+ *
+ *     @(#)machdep.c   7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "signalvar.h"
+#include "kernel.h"
+#include "map.h"
+#include "proc.h"
+#include "buf.h"
+#include "reboot.h"
+#include "conf.h"
+#include "file.h"
+#include "clist.h"
+#include "callout.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "msgbuf.h"
+#include "user.h"
+#ifdef SYSVSHM
+#include "shm.h"
+#endif
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+#include "../include/cpu.h"
+#include "../include/reg.h"
+#include "../include/psl.h"
+#include "../include/machMon.h"
+#include "clockreg.h"
+#include "pte.h"
+
+#define        MAXMEM  24*1024*CLSIZE  /* XXX - from cmap.h */
+
+vm_map_t buffer_map;
+
+/*
+ * Declare these as initialized data so we can patch them.
+ */
+int    nswbuf = 0;
+#ifdef NBUF
+int    nbuf = NBUF;
+#else
+int    nbuf = 0;
+#endif
+#ifdef BUFPAGES
+int    bufpages = BUFPAGES;
+#else
+int    bufpages = 0;
+#endif
+int    msgbufmapped;           /* set when safe to use msgbuf */
+int    maxmem;                 /* max memory per process */
+int    physmem = MAXMEM;       /* max supported memory, changes to actual */
+/*
+ * safepri is a safe priority for sleep to set for a spin-wait
+ * during autoconfiguration or after a panic.
+ */
+int    safepri = PSL_LOWIPL;
+
+struct user *proc0paddr;
+struct proc nullproc;          /* for use by swtch_exit() */
+
+/*
+ * Do all the stuff that locore normally does before calling main().
+ * Process arguments passed to us by the prom monitor.
+ * Return the first page address following the system.
+ */
+mach_init(argc, argv)
+       int argc;
+       char *argv[];
+{
+       register char *cp;
+       register int i;
+       register unsigned firstaddr;
+       register caddr_t v;
+       extern char edata[], end[];
+       extern char MachUTLBMiss[], MachUTLBMissEnd[];
+       extern char MachException[], MachExceptionEnd[];
+#ifdef ATTR
+       extern char *pmap_attributes;
+#endif
+
+       /* clear BSS segment, pages for u, and proc[0] page table */
+       v = (caddr_t)pmax_round_page(end) + 2 * UPAGES * NBPG;
+       bzero(edata, v - edata);
+
+       /* look at argv[0] and compute bootdev */
+       makebootdev(argv[0]);
+
+       /*
+        * Look at arguments passed to us and compute boothowto.
+        */
+#ifdef GENERIC
+       boothowto = RB_SINGLE | RB_ASKNAME;
+#else
+       boothowto = RB_SINGLE | RB_DFLTROOT;
+#endif
+       if (argc > 1) {
+               for (i = 1; i < argc; i++) {
+                       for (cp = argv[i]; *cp; cp++) {
+                               switch (*cp) {
+                               case '-':
+                                       continue;
+
+                               case '0': /* XXX */
+                               case '1': /* XXX */
+                               case '2': /* XXX */
+                               case '3': /* XXX */
+                               case '4': /* XXX */
+                               case '5': /* XXX */
+                               case '6': /* XXX */
+                                   {
+                                       extern int sii_debug;
+
+                                       sii_debug = *cp - '0';
+                                       break;
+                                   }
+
+                               case 'a': /* autoboot */
+                                       boothowto &= ~RB_SINGLE;
+                                       break;
+
+                               case 'n': /* ask for names */
+                                       boothowto |= RB_ASKNAME;
+                                       boothowto &= ~RB_DFLTROOT;
+                                       break;
+
+                               case 'N': /* don't ask for names */
+                                       boothowto &= ~RB_ASKNAME;
+                                       boothowto |= RB_DFLTROOT;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * Init mapping for u page(s) for proc[0], pm_tlbpid 1.
+        */
+       firstaddr = pmax_round_page(end);
+       curproc->p_addr = proc0paddr = (struct user *)firstaddr;
+       curproc->p_regs = proc0paddr->u_pcb.pcb_regs;
+       for (i = 0; i < UPAGES; i++) {
+               MachTLBWriteIndexed(i,
+                       (UADDR + (i << PGSHIFT)) | (1 << VMMACH_TLB_PID_SHIFT),
+                       curproc->p_md.md_upte[i] = firstaddr | PG_V | PG_M);
+               firstaddr += NBPG;
+       }
+       MachSetPID(1);
+
+       /*
+        * init nullproc for swtch_exit().
+        * init mapping for u page(s), pm_tlbpid 0
+        * This could be used for an idle process.
+        */
+       nullproc.p_regs = ((struct user *)firstaddr)->u_pcb.pcb_regs;
+       for (i = 0; i < UPAGES; i++) {
+               nullproc.p_md.md_upte[i] = firstaddr | PG_V | PG_M;
+               firstaddr += NBPG;
+       }
+
+       /*
+        * Copy down exception vector code.
+        */
+       if (MachUTLBMissEnd - MachUTLBMiss > 0x80)
+               panic("startup: UTLB code too large");
+       bcopy(MachUTLBMiss, (char *)MACH_UTLB_MISS_EXC_VEC,
+               MachUTLBMissEnd - MachUTLBMiss);
+       bcopy(MachException, (char *)MACH_GEN_EXC_VEC,
+               MachExceptionEnd - MachException);
+
+       /*
+        * Clear out the I and D caches.
+        */
+       MachConfigCache();
+       MachFlushCache();
+
+       /*
+        * Find out how much memory is available.
+        */
+       physmem = btoc(v - KERNBASE);
+       cp = (char *)(MACH_UNCACHED_MEMORY_ADDR + (physmem << PGSHIFT));
+       while (cp < (char *)MACH_UNCACHED_FRAME_BUFFER_ADDR) {
+               if (badaddr(cp, 4))
+                       break;
+               cp += NBPG;
+               physmem++;
+       }
+       maxmem = physmem + btoc(KERNBASE);
+
+       /*
+        * Initialize error message buffer (at end of core).
+        */
+       maxmem -= btoc(sizeof (struct msgbuf));
+       msgbufp = (struct msgbuf *)(maxmem << PGSHIFT);
+       msgbufmapped = 1;
+
+       /*
+        * Allocate space for system data structures.
+        * The first available real memory address is in "firstaddr".
+        * The first available kernel virtual address is in "v".
+        * As pages of kernel virtual memory are allocated, "v" is incremented.
+        * As pages of memory are allocated and cleared,
+        * "firstaddr" is incremented.
+        */
+       /*
+        * These data structures are allocated here instead of cpu_startup()
+        * because physical memory is directly addressable. We don't have
+        * to map these into virtual address space.
+        */
+       firstaddr = (unsigned)v;
+
+#define        valloc(name, type, num) \
+           (name) = (type *)v; v = (caddr_t)((name)+(num))
+#define        valloclim(name, type, num, lim) \
+           (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
+       valloc(cfree, struct cblock, nclist);
+       valloc(callout, struct callout, ncallout);
+       valloc(swapmap, struct map, nswapmap = maxproc * 2);
+#ifdef SYSVSHM
+       valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
+#endif
+#ifdef ATTR
+       /* this is allocated here just to save a few bytes */
+       valloc(pmap_attributes, char, physmem);
+#endif
+
+       /*
+        * Determine how many buffers to allocate.
+        * We allocate more buffer space than the BSD standard of
+        * using 10% of memory for the first 2 Meg, 5% of remaining.
+        * We just allocate a flat 10%.  Insure a minimum of 16 buffers.
+        * We allocate 1/2 as many swap buffer headers as file i/o buffers.
+        */
+       if (bufpages == 0)
+               bufpages = physmem / 10 / CLSIZE;
+       if (nbuf == 0) {
+               nbuf = bufpages;
+               if (nbuf < 16)
+                       nbuf = 16;
+       }
+       if (nswbuf == 0) {
+               nswbuf = (nbuf / 2) &~ 1;       /* force even */
+               if (nswbuf > 256)
+                       nswbuf = 256;           /* sanity */
+       }
+       valloc(swbuf, struct buf, nswbuf);
+       valloc(buf, struct buf, nbuf);
+
+       /*
+        * Clear allocated memory.
+        */
+       v = (caddr_t)pmax_round_page(v);
+       bzero((caddr_t)firstaddr, (unsigned)v - firstaddr);
+
+       /*
+        * Initialize the virtual memory system.
+        */
+       pmap_bootstrap((vm_offset_t)v);
+}
+
+/*
+ * Console initialization: called early on from main,
+ * before vm init or startup.  Do enough configuration
+ * to choose and initialize a console.
+ */
+consinit()
+{
+
+#include "pm.h"
+#if NPM > 0
+       /*
+        * Initialize the console before we print anything out.
+        */
+       pminit();
+#endif
+}
+
+/*
+ * cpu_startup: allocate memory for variable-sized tables,
+ * initialize cpu, and do autoconfiguration.
+ */
+cpu_startup()
+{
+       register unsigned i;
+       register caddr_t v, firstaddr;
+       int base, residual;
+       extern long Usrptsize;
+       extern struct map *useriomap;
+#ifdef DEBUG
+       extern int pmapdebug;
+       int opmapdebug = pmapdebug;
+#endif
+       vm_offset_t minaddr, maxaddr;
+       vm_size_t size;
+
+#ifdef DEBUG
+       pmapdebug = 0;
+#endif
+
+       /*
+        * Good {morning,afternoon,evening,night}.
+        */
+       printf(version);
+       printf("real mem = %d\n", ctob(physmem));
+
+       /*
+        * Allocate virtual address space for file I/O buffers.
+        * Note they are different than the array of headers, 'buf',
+        * and usually occupy more virtual memory than physical.
+        */
+       size = MAXBSIZE * nbuf;
+       buffer_map = kmem_suballoc(kernel_map, (vm_offset_t)&buffers,
+                                  &maxaddr, size, FALSE);
+       minaddr = (vm_offset_t)buffers;
+       if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0,
+                       &minaddr, size, FALSE) != KERN_SUCCESS)
+               panic("startup: cannot allocate buffers");
+       base = bufpages / nbuf;
+       residual = bufpages % nbuf;
+       for (i = 0; i < nbuf; i++) {
+               vm_size_t curbufsize;
+               vm_offset_t curbuf;
+
+               /*
+                * First <residual> buffers get (base+1) physical pages
+                * allocated for them.  The rest get (base) physical pages.
+                *
+                * The rest of each buffer occupies virtual space,
+                * but has no physical memory allocated for it.
+                */
+               curbuf = (vm_offset_t)buffers + i * MAXBSIZE;
+               curbufsize = CLBYTES * (i < residual ? base+1 : base);
+               vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE);
+               vm_map_simplify(buffer_map, curbuf);
+       }
+       /*
+        * Allocate a submap for exec arguments.  This map effectively
+        * limits the number of processes exec'ing at any time.
+        */
+       exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+                                16*NCARGS, TRUE);
+       /*
+        * Allocate a submap for physio
+        */
+       phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+                                VM_PHYS_SIZE, TRUE);
+
+       /*
+        * Finally, allocate mbuf pool.  Since mclrefcnt is an off-size
+        * we use the more space efficient malloc in place of kmem_alloc.
+        */
+       mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES,
+                                  M_MBUF, M_NOWAIT);
+       bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
+       mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr,
+                              VM_MBUF_SIZE, FALSE);
+       /*
+        * Initialize callouts
+        */
+       callfree = callout;
+       for (i = 1; i < ncallout; i++)
+               callout[i-1].c_next = &callout[i];
+
+#ifdef DEBUG
+       pmapdebug = opmapdebug;
+#endif
+       printf("avail mem = %d\n", ptoa(cnt.v_free_count));
+       printf("using %d buffers containing %d bytes of memory\n",
+               nbuf, bufpages * CLBYTES);
+       /*
+        * Set up CPU-specific registers, cache, etc.
+        */
+       initcpu();
+
+       /*
+        * Set up buffers, so they can be used to read disk labels.
+        */
+       bufinit();
+
+       /*
+        * Configure the system.
+        */
+       configure();
+}
+
+/*
+ * Set registers on exec.
+ * Clear all registers except sp, pc.
+ */
+setregs(p, entry, retval)
+       register struct proc *p;
+       u_long entry;
+       int retval[2];
+{
+       int sp = p->p_regs[SP];
+
+       bzero((caddr_t)p->p_regs, (FSR + 1) * sizeof(int));
+       p->p_regs[SP] = sp;
+       p->p_regs[PC] = entry;
+       p->p_regs[PS] = PSL_USERSET;
+       p->p_md.md_flags & ~MDP_FPUSED;
+}
+
+/*
+ * WARNING: code in locore.s assumes the layout shown for sf_signum
+ * thru sf_handler so... don't screw with them!
+ */
+struct sigframe {
+       int     sf_signum;              /* signo for handler */
+       int     sf_code;                /* additional info for handler */
+       struct  sigcontext *sf_scp;     /* context ptr for handler */
+       sig_t   sf_handler;             /* handler addr for u_sigc */
+};
+
+#ifdef DEBUG
+int sigdebug = 0;
+int sigpid = 0;
+#define SDB_FOLLOW     0x01
+#define SDB_KSTACK     0x02
+#define SDB_FPSTATE    0x04
+#endif
+
+/*
+ * Send an interrupt to process.
+ */
+void
+sendsig(catcher, sig, mask, code)
+       sig_t catcher;
+       int sig, mask;
+       unsigned code;
+{
+       register struct proc *p = curproc;
+       register struct sigframe *fp;
+       register struct sigacts *ps = p->p_sigacts;
+       register struct sigcontext *scp;
+       register int *regs;
+       int oonstack, fsize;
+       struct sigcontext ksc;
+
+       regs = p->p_regs;
+       oonstack = ps->ps_onstack;
+       /*
+        * Allocate and validate space for the signal handler
+        * context. Note that if the stack is in data space, the
+        * call to grow() is a nop, and the copyout()
+        * will fail if the process has not already allocated
+        * the space with a `brk'.
+        */
+       if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) {
+               scp = (struct sigcontext *)ps->ps_sigsp - 1;
+               ps->ps_onstack = 1;
+       } else
+               scp = (struct sigcontext *)regs[SP] - 1;
+       fp = (struct sigframe *)scp - 1;
+       if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) 
+               (void)grow(p, (unsigned)fp);
+       /*
+        * Build the signal context to be used by sigreturn.
+        */
+       ksc.sc_onstack = oonstack;
+       ksc.sc_mask = mask;
+       ksc.sc_pc = regs[PC];
+       ksc.sc_regs[ZERO] = 0xACEDBADE;         /* magic number */
+       bcopy((caddr_t)&regs[1], (caddr_t)&ksc.sc_regs[1],
+               sizeof(ksc.sc_regs) - sizeof(int));
+       ksc.sc_fpused = p->p_md.md_flags & MDP_FPUSED;
+       if (ksc.sc_fpused) {
+               extern struct proc *machFPCurProcPtr;
+
+               /* if FPU has current state, save it first */
+               if (p == machFPCurProcPtr) {
+                       MachSaveCurFPState(p);
+                       machFPCurProcPtr = (struct proc *)0;
+               }
+               bcopy((caddr_t)&p->p_regs[F0], (caddr_t)ksc.sc_fpregs,
+                       sizeof(ksc.sc_fpregs));
+       }
+       if (copyout((caddr_t)&ksc, (caddr_t)scp, sizeof(ksc))) {
+               /*
+                * Process has trashed its stack; give it an illegal
+                * instruction to halt it in its tracks.
+                */
+               SIGACTION(p, SIGILL) = SIG_DFL;
+               sig = sigmask(SIGILL);
+               p->p_sigignore &= ~sig;
+               p->p_sigcatch &= ~sig;
+               p->p_sigmask &= ~sig;
+               psignal(p, SIGILL);
+               return;
+       }
+       /* 
+        * Build the argument list for the signal handler.
+        */
+       regs[A0] = sig;
+       regs[A1] = code;
+       regs[A2] = (int)scp;
+       regs[A3] = (int)catcher;
+
+       regs[PC] = (int)catcher;
+       regs[SP] = (int)fp;
+       regs[RA] = KERNBASE;    /* this causes a trap which we interpret as
+                                * meaning "do a sigreturn". */
+#ifdef DEBUG
+       if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
+               printf("sendsig(%d): sig %d ssp %x usp %x scp %x\n",
+                      p->p_pid, sig, &oonstack, fp, fp->sf_scp);
+#endif
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken.  Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psl to gain improper priviledges or to cause
+ * a machine fault.
+ */
+/* ARGSUSED */
+sigreturn(p, uap, retval)
+       struct proc *p;
+       struct args {
+               struct sigcontext *sigcntxp;
+       } *uap;
+       int *retval;
+{
+       register struct sigcontext *scp;
+       register int *regs;
+       struct sigcontext ksc;
+       int error;
+
+       register struct frame *frame;
+       register int rf;
+       struct sigcontext tsigc;
+       int flags;
+
+       scp = uap->sigcntxp;
+#ifdef DEBUG
+       if (sigdebug & SDB_FOLLOW)
+               printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp);
+#endif
+       regs = p->p_regs;
+       /*
+        * Test and fetch the context structure.
+        * We grab it all at once for speed.
+        */
+       error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(ksc));
+       if (error != 0 || ksc.sc_regs[ZERO] != 0xACEDBADE ||
+           (unsigned)ksc.sc_regs[SP] < (unsigned)regs[SP]) {
+#ifdef DEBUG
+               if (!(sigdebug & SDB_FOLLOW))
+                       printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp);
+               printf("  old sp %x ra %x pc %x\n",
+                       regs[SP], regs[RA], regs[PC]);
+               printf("  new sp %x ra %x pc %x err %d z %x\n",
+                       ksc.sc_regs[SP], ksc.sc_regs[RA], ksc.sc_regs[PC],
+                       error, ksc.sc_regs[ZERO]);
+#endif
+               if (regs[PC] == KERNBASE) {
+                       int sig;
+
+                       /*
+                        * Process has trashed its stack; give it an illegal
+                        * instruction to halt it in its tracks.
+                        */
+                       SIGACTION(p, SIGILL) = SIG_DFL;
+                       sig = sigmask(SIGILL);
+                       p->p_sigignore &= ~sig;
+                       p->p_sigcatch &= ~sig;
+                       p->p_sigmask &= ~sig;
+                       psignal(p, SIGILL);
+               }
+               return (EINVAL);
+       }
+       /*
+        * Restore the user supplied information
+        */
+       p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
+       p->p_sigmask = scp->sc_mask &~ sigcantmask;
+       regs[PC] = ksc.sc_pc;
+       bcopy((caddr_t)&ksc.sc_regs[1], (caddr_t)&regs[1],
+               sizeof(ksc.sc_regs) - sizeof(int));
+       ksc.sc_fpused = p->p_md.md_flags & MDP_FPUSED;
+       if (ksc.sc_fpused)
+               bcopy((caddr_t)ksc.sc_fpregs, (caddr_t)&p->p_regs[F0],
+                       sizeof(ksc.sc_fpregs));
+       return (EJUSTRETURN);
+}
+
+int    waittime = -1;
+
+boot(howto)
+       register int howto;
+{
+
+       trapDump("boot"); /* XXX */
+       /* take a snap shot before clobbering any registers */
+       if (curproc)
+               savectx(curproc->p_addr, 0);
+
+       howto |= RB_HALT; /* XXX */
+       boothowto = howto;
+       if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
+               register struct buf *bp;
+               int iter, nbusy;
+
+               waittime = 0;
+               (void) spl0();
+               printf("syncing disks... ");
+               /*
+                * Release vnodes held by texts before sync.
+                */
+               if (panicstr == 0)
+                       vnode_pager_umount(NULL);
+#ifdef notdef
+#include "fd.h"
+#if NFD > 0
+               fdshutdown();
+#endif
+#endif
+               sync(&proc0, (void *)NULL, (int *)NULL);
+
+               for (iter = 0; iter < 20; iter++) {
+                       nbusy = 0;
+                       for (bp = &buf[nbuf]; --bp >= buf; )
+                               if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
+                                       nbusy++;
+                       if (nbusy == 0)
+                               break;
+                       printf("%d ", nbusy);
+                       DELAY(40000 * iter);
+               }
+               if (nbusy)
+                       printf("giving up\n");
+               else
+                       printf("done\n");
+               /*
+                * If we've been adjusting the clock, the todr
+                * will be out of synch; adjust it now.
+                */
+               resettodr();
+       }
+       (void) splhigh();               /* extreme priority */
+       if (howto & RB_HALT) {
+#ifdef DEBUG
+               void (*f)() = (void (*)())MACH_MON_RESTART;
+#else
+               void (*f)() = (void (*)())MACH_MON_REINIT;
+#endif
+
+               (*f)(); /* jump back to prom monitor */
+       } else {
+               void (*f)() = (void (*)())MACH_MON_AUTOBOOT;
+
+               if (howto & RB_DUMP)
+                       dumpsys();
+               (*f)(); /* jump back to prom monitor and do 'auto' cmd */
+               /*NOTREACHED*/
+       }
+       /*NOTREACHED*/
+}
+
+int    dumpmag = 0x8fca0101;   /* magic number for savecore */
+int    dumpsize = 0;           /* also for savecore */
+long   dumplo = 0;
+
+dumpconf()
+{
+       int nblks;
+
+       dumpsize = physmem;
+       if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) {
+               nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev);
+               if (dumpsize > btoc(dbtob(nblks - dumplo)))
+                       dumpsize = btoc(dbtob(nblks - dumplo));
+               else if (dumplo == 0)
+                       dumplo = nblks - btodb(ctob(physmem));
+       }
+       /*
+        * Don't dump on the first CLBYTES (why CLBYTES?)
+        * in case the dump device includes a disk label.
+        */
+       if (dumplo < btodb(CLBYTES))
+               dumplo = btodb(CLBYTES);
+}
+
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+dumpsys()
+{
+       int error;
+
+       msgbufmapped = 0;
+       if (dumpdev == NODEV)
+               return;
+       /*
+        * For dumps during autoconfiguration,
+        * if dump device has already configured...
+        */
+       if (dumpsize == 0)
+               dumpconf();
+       if (dumplo < 0)
+               return;
+       printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
+       printf("dump ");
+       switch (error = (*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
+
+       case ENXIO:
+               printf("device bad\n");
+               break;
+
+       case EFAULT:
+               printf("device not ready\n");
+               break;
+
+       case EINVAL:
+               printf("area improper\n");
+               break;
+
+       case EIO:
+               printf("i/o error\n");
+               break;
+
+       default:
+               printf("error %d\n", error);
+               break;
+
+       case 0:
+               printf("succeeded\n");
+       }
+}
+
+/*
+ * Return the best possible estimate of the time in the timeval
+ * to which tvp points.  Unfortunately, we can't read the hardware registers.
+ * We guarantee that the time will be greater than the value obtained by a
+ * previous call.
+ */
+microtime(tvp)
+       register struct timeval *tvp;
+{
+       int s = splclock();
+       static struct timeval lasttime;
+
+       *tvp = time;
+#ifdef notdef
+       tvp->tv_usec += clkread();
+       while (tvp->tv_usec > 1000000) {
+               tvp->tv_sec++;
+               tvp->tv_usec -= 1000000;
+       }
+#endif
+       if (tvp->tv_sec == lasttime.tv_sec &&
+           tvp->tv_usec <= lasttime.tv_usec &&
+           (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) {
+               tvp->tv_sec++;
+               tvp->tv_usec -= 1000000;
+       }
+       lasttime = *tvp;
+       splx(s);
+}
+
+initcpu()
+{
+       register volatile struct chiptime *c;
+       int i;
+
+       /* disable clock interrupts (until startrtclock()) */
+       c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
+       c->regb = REGB_DATA_MODE | REGB_HOURS_FORMAT;
+       i = c->regc;
+       spl0();         /* safe to turn interrupts on now */
+       return (i);
+}
diff --git a/usr/src/sys/pmax/pmax/mem.c b/usr/src/sys/pmax/pmax/mem.c
new file mode 100644 (file)
index 0000000..f8ef726
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: mem.c 1.14 90/10/12$
+ *
+ *     @(#)mem.c       7.1 (Berkeley) %G%
+ */
+
+/*
+ * Memory special file
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "buf.h"
+#include "systm.h"
+#include "malloc.h"
+
+#include "../include/cpu.h"
+
+#include "vm/vm_param.h"
+#include "vm/lock.h"
+#include "vm/pmap.h"
+#include "vm/vm_prot.h"
+
+/*ARGSUSED*/
+mmrw(dev, uio, flags)
+       dev_t dev;
+       struct uio *uio;
+       int flags;
+{
+       register int o;
+       register u_int c, v;
+       register struct iovec *iov;
+       int error = 0;
+       caddr_t zbuf = NULL;
+       extern u_int lowram;
+
+       while (uio->uio_resid > 0 && error == 0) {
+               iov = uio->uio_iov;
+               if (iov->iov_len == 0) {
+                       uio->uio_iov++;
+                       uio->uio_iovcnt--;
+                       if (uio->uio_iovcnt < 0)
+                               panic("mmrw");
+                       continue;
+               }
+               switch (minor(dev)) {
+
+/* minor device 0 is physical memory */
+               case 0:
+                       v = uio->uio_offset;
+                       c = iov->iov_len;
+                       if (v + c >= physmem)
+                               return (EFAULT);
+                       error = uiomove((caddr_t)(MACH_CACHED_MEMORY_ADDR + v),
+                               (int)c, uio);
+                       continue;
+
+/* minor device 1 is kernel memory */
+               case 1:
+                       c = iov->iov_len;
+                       if (!kernacc((caddr_t)uio->uio_offset, c,
+                           uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+                               return (EFAULT);
+                       error = uiomove((caddr_t)uio->uio_offset, (int)c, uio);
+                       continue;
+
+/* minor device 2 is EOF/RATHOLE */
+               case 2:
+                       if (uio->uio_rw == UIO_WRITE)
+                               uio->uio_resid = 0;
+                       return (0);
+
+/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
+               case 12:
+                       if (uio->uio_rw == UIO_WRITE) {
+                               c = iov->iov_len;
+                               break;
+                       }
+                       if (zbuf == NULL) {
+                               zbuf = (caddr_t)
+                                   malloc(CLBYTES, M_TEMP, M_WAITOK);
+                               bzero(zbuf, CLBYTES);
+                       }
+                       c = MIN(iov->iov_len, CLBYTES);
+                       error = uiomove(zbuf, (int)c, uio);
+                       continue;
+
+               default:
+                       return (ENXIO);
+               }
+               if (error)
+                       break;
+               iov->iov_base += c;
+               iov->iov_len -= c;
+               uio->uio_offset += c;
+               uio->uio_resid -= c;
+       }
+       if (zbuf)
+               free(zbuf, M_TEMP);
+       return (error);
+}
diff --git a/usr/src/sys/pmax/pmax/pmap.c b/usr/src/sys/pmax/pmax/pmap.c
new file mode 100644 (file)
index 0000000..10b235a
--- /dev/null
@@ -0,0 +1,1497 @@
+/* 
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)pmap.c      7.1 (Berkeley) %G%
+ */
+
+/*
+ *     Manages physical address maps.
+ *
+ *     In addition to hardware address maps, this
+ *     module is called upon to provide software-use-only
+ *     maps which may or may not be stored in the same
+ *     form as hardware maps.  These pseudo-maps are
+ *     used to store intermediate results from copy
+ *     operations to and from address spaces.
+ *
+ *     Since the information managed by this module is
+ *     also stored by the logical address mapping module,
+ *     this module may throw away valid virtual-to-physical
+ *     mappings at almost any time.  However, invalidations
+ *     of virtual-to-physical mappings must be done as
+ *     requested.
+ *
+ *     In order to cope with hardware architectures which
+ *     make virtual-to-physical map invalidates expensive,
+ *     this module may delay invalidate or reduced protection
+ *     operations until such time as they are actually
+ *     necessary.  This module is given full information as
+ *     to which processors are currently using which maps,
+ *     and to when physical maps must be made correct.
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "malloc.h"
+#include "user.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+#include "../include/machConst.h"
+#include "pte.h"
+
+/*
+ * For each vm_page_t, there is a list of all currently valid virtual
+ * mappings of that page.  An entry is a pv_entry_t, the list is pv_table.
+ * XXX really should do this as a part of the higher level code.
+ */
+typedef struct pv_entry {
+       struct pv_entry *pv_next;       /* next pv_entry */
+       struct pmap     *pv_pmap;       /* pmap where mapping lies */
+       vm_offset_t     pv_va;          /* virtual address for mapping */
+       int             pv_flags;       /* flags */
+} *pv_entry_t;
+
+pv_entry_t     pv_table;       /* array of entries, one per page */
+extern void    pmap_remove_pv();
+
+#define pa_index(pa)           atop((pa) - first_phys_addr)
+#define pa_to_pvh(pa)          (&pv_table[pa_index(pa)])
+
+#ifdef DEBUG
+struct {
+       int kernel;     /* entering kernel mapping */
+       int user;       /* entering user mapping */
+       int ptpneeded;  /* needed to allocate a PT page */
+       int pwchange;   /* no mapping change, just wiring or protection */
+       int wchange;    /* no mapping change, just wiring */
+       int mchange;    /* was mapped but mapping to different page */
+       int managed;    /* a managed page */
+       int firstpv;    /* first mapping for this PA */
+       int secondpv;   /* second mapping for this PA */
+       int ci;         /* cache inhibited */
+       int unmanaged;  /* not a managed page */
+       int flushes;    /* cache flushes */
+       int cachehit;   /* new entry forced valid entry out */
+} enter_stats;
+struct {
+       int calls;
+       int removes;
+       int flushes;
+       int pidflushes; /* HW pid stolen */
+       int pvfirst;
+       int pvsearch;
+} remove_stats;
+
+int pmapdebug;
+#define PDB_FOLLOW     0x0001
+#define PDB_INIT       0x0002
+#define PDB_ENTER      0x0004
+#define PDB_REMOVE     0x0008
+#define PDB_CREATE     0x0010
+#define PDB_PTPAGE     0x0020
+#define PDB_CACHE      0x0040
+#define PDB_BITS       0x0080
+#define PDB_COLLECT    0x0100
+#define PDB_PROTECT    0x0200
+#define PDB_TLBPID     0x0400
+#define PDB_PARANOIA   0x2000
+#define PDB_WIRING     0x4000
+#define PDB_PVDUMP     0x8000
+
+#endif /* DEBUG */
+
+u_int  whichpids[2] = {        /* bit mask of hardware PID's in use */
+       3, 0
+};
+
+struct pmap    kernel_pmap_store;
+pmap_t         kernel_pmap;
+pmap_t         cur_pmap;       /* current pmap mapped in hardware */
+
+vm_offset_t            avail_start;    /* PA of first available physical page */
+vm_offset_t    avail_end;      /* PA of last available physical page */
+vm_size_t      mem_size;       /* memory size in bytes */
+vm_offset_t    virtual_avail;  /* VA of first avail page (after kernel bss)*/
+vm_offset_t    virtual_end;    /* VA of last avail page (end of kernel AS) */
+int            pmaxpagesperpage;       /* PAGE_SIZE / NBPG */
+#ifdef ATTR
+char           *pmap_attributes;       /* reference and modify bits */
+#endif
+pmap_hash_t    zero_pmap_hash;         /* empty TLB hash table for init */
+
+/*
+ *     Bootstrap the system enough to run with virtual memory.
+ */
+void
+pmap_bootstrap(firstaddr)
+       vm_offset_t firstaddr;
+{
+       register int i;
+       vm_offset_t start = firstaddr;
+       extern int maxmem, physmem;
+
+       /*
+        * Allocate a TLB hash table for the kernel.
+        * This could be a KSEG0 address and thus save TLB entries but
+        * its faster and simpler in assembly language to have a
+        * fixed address that can be accessed with a 16 bit signed offset.
+        * Note: the kernel pm_hash field is null, user pm_hash fields are
+        * either the table or zero_pmap_hash.
+        */
+       kernel_pmap_store.pm_hash = (pmap_hash_t)0;
+       for (i = 0; i < PMAP_HASH_KPAGES; i++) {
+               MachTLBWriteIndexed(i + UPAGES + PMAP_HASH_UPAGES,
+                       PMAP_HASH_KADDR + (i << PGSHIFT),
+                       firstaddr | PG_V | PG_M | PG_G);
+               firstaddr += NBPG;
+       }
+
+       /*
+        * Allocate an empty TLB hash table for initial pmap's.
+        */
+       zero_pmap_hash = (pmap_hash_t)firstaddr;
+       firstaddr += PMAP_HASH_UPAGES * NBPG;
+       /* init proc[0]'s pmap hash table */
+       for (i = 0; i < PMAP_HASH_UPAGES; i++) {
+               kernel_pmap_store.pm_hash_ptes[i] =
+                       ((u_int)zero_pmap_hash + (i << PGSHIFT)) | PG_V | PG_RO;
+               MachTLBWriteIndexed(i + UPAGES,
+                       (PMAP_HASH_UADDR + (i << PGSHIFT)) |
+                               (1 << VMMACH_TLB_PID_SHIFT),
+                       kernel_pmap_store.pm_hash_ptes[i]);
+       }
+
+       /*
+        * Allocate memory for pv_table.
+        * This will allocate more entries than we really need.
+        * We should do this in pmap_init when we know the actual
+        * phys_start and phys_end but its better to use phys addresses
+        * rather than kernel virtual addresses mapped through the TLB.
+        */
+       i = (maxmem - pmax_btop(firstaddr)) * sizeof(struct pv_entry);
+       i = pmax_round_page(i);
+       pv_table = (pv_entry_t)firstaddr;
+       firstaddr += i;
+
+       /*
+        * Clear allocated memory.
+        */
+       bzero((caddr_t)start, firstaddr - start);
+
+       avail_start = firstaddr;
+       avail_end = pmax_ptob(maxmem);
+       mem_size = avail_end - avail_start;
+
+       virtual_avail = VM_MIN_KERNEL_ADDRESS;
+       virtual_end = VM_MIN_KERNEL_ADDRESS + PMAP_HASH_KPAGES * NPTEPG * NBPG;
+       /* XXX need to decide how to set cnt.v_page_size */
+       pmaxpagesperpage = 1;
+
+       /*
+        * The kernel's pmap is statically allocated so we don't
+        * have to use pmap_create, which is unlikely to work
+        * correctly at this part of the boot sequence.
+        */
+       kernel_pmap = cur_pmap = &kernel_pmap_store;
+       simple_lock_init(&kernel_pmap->pm_lock);
+       kernel_pmap->pm_count = 1;
+}
+
+/*
+ * Bootstrap memory allocator. This function allows for early dynamic
+ * memory allocation until the virtual memory system has been bootstrapped.
+ * After that point, either kmem_alloc or malloc should be used. This
+ * function works by stealing pages from the (to be) managed page pool,
+ * stealing virtual address space, then mapping the pages and zeroing them.
+ *
+ * It should be used from pmap_bootstrap till vm_page_startup, afterwards
+ * it cannot be used, and will generate a panic if tried. Note that this
+ * memory will never be freed, and in essence it is wired down.
+ */
+void *
+pmap_bootstrap_alloc(size)
+       int size;
+{
+       vm_offset_t val;
+       extern boolean_t vm_page_startup_initialized;
+
+       if (vm_page_startup_initialized)
+               panic("pmap_bootstrap_alloc: called after startup initialized");
+
+       val = avail_start;
+       size = round_page(size);
+       avail_start += size;
+
+       blkclr((caddr_t) val, size);
+       return ((void *) val);
+}
+
+/*
+ *     Initialize the pmap module.
+ *     Called by vm_init, to initialize any structures that the pmap
+ *     system needs to map virtual memory.
+ */
+void
+pmap_init(phys_start, phys_end)
+       vm_offset_t phys_start, phys_end;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_init(%x, %x)\n", phys_start, phys_end);
+#endif
+}
+
+/*
+ *     Used to map a range of physical addresses into kernel
+ *     virtual address space.
+ *
+ *     This routine should only be called by vm_page_startup()
+ *     with KSEG0 addresses.
+ */
+vm_offset_t
+pmap_map(virt, start, end, prot)
+       vm_offset_t virt;
+       vm_offset_t start;
+       vm_offset_t end;
+       int prot;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot);
+#endif
+
+       return(round_page(end));
+}
+
+/*
+ *     Create and return a physical map.
+ *
+ *     If the size specified for the map
+ *     is zero, the map is an actual physical
+ *     map, and may be referenced by the
+ *     hardware.
+ *
+ *     If the size specified is non-zero,
+ *     the map will be used in software only, and
+ *     is bounded by that size.
+ */
+pmap_t
+pmap_create(size)
+       vm_size_t size;
+{
+       register pmap_t pmap;
+
+#ifdef DEBUG
+       if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
+               printf("pmap_create(%x)\n", size);
+#endif
+       /*
+        * Software use map does not need a pmap
+        */
+       if (size)
+               return(NULL);
+
+       printf("pmap_create(%x) XXX\n", size); /* XXX */
+       /* XXX: is it ok to wait here? */
+       pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
+#ifdef notifwewait
+       if (pmap == NULL)
+               panic("pmap_create: cannot allocate a pmap");
+#endif
+       bzero(pmap, sizeof(*pmap));
+       pmap_pinit(pmap);
+       return (pmap);
+}
+
+/*
+ * Initialize a preallocated and zeroed pmap structure,
+ * such as one in a vmspace structure.
+ */
+void
+pmap_pinit(pmap)
+       register struct pmap *pmap;
+{
+       register int i;
+       extern struct vmspace vmspace0;
+
+#ifdef DEBUG
+       if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
+               printf("pmap_pinit(%x)\n", pmap);
+#endif
+       simple_lock_init(&pmap->pm_lock);
+       pmap->pm_count = 1;
+       pmap->pm_flags = 0;
+       pmap->pm_hash = zero_pmap_hash;
+       for (i = 0; i < PMAP_HASH_UPAGES; i++)
+               pmap->pm_hash_ptes[i] =
+                       ((u_int)zero_pmap_hash + (i << PGSHIFT)) | PG_V | PG_RO;
+       if (pmap == &vmspace0.vm_pmap)
+               pmap->pm_tlbpid = 1;    /* preallocated in mach_init() */
+       else
+               pmap->pm_tlbpid = -1;   /* none allocated yet */
+}
+
+/*
+ *     Retire the given physical map from service.
+ *     Should only be called if the map contains
+ *     no valid mappings.
+ */
+void
+pmap_destroy(pmap)
+       register pmap_t pmap;
+{
+       int count;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_destroy(%x)\n", pmap);
+#endif
+       if (pmap == NULL)
+               return;
+
+       printf("pmap_destroy(%x) XXX\n", pmap); /* XXX */
+       simple_lock(&pmap->pm_lock);
+       count = --pmap->pm_count;
+       simple_unlock(&pmap->pm_lock);
+       if (count == 0) {
+               pmap_release(pmap);
+               free((caddr_t)pmap, M_VMPMAP);
+       }
+}
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_release(pmap)
+       register pmap_t pmap;
+{
+       register int id;
+#ifdef DIAGNOSTIC
+       register int i;
+#endif
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_release(%x)\n", pmap);
+#endif
+
+       if (pmap->pm_hash && pmap->pm_hash != zero_pmap_hash) {
+               kmem_free(kernel_map, (vm_offset_t)pmap->pm_hash,
+                       PMAP_HASH_SIZE);
+               pmap->pm_hash = zero_pmap_hash;
+       }
+       if ((id = pmap->pm_tlbpid) < 0)
+               return;
+#ifdef DIAGNOSTIC
+       if (!(whichpids[id >> 5] & (1 << (id & 0x1F))))
+               panic("pmap_release: id free");
+#endif
+       MachTLBFlushPID(id);
+       whichpids[id >> 5] &= ~(1 << (id & 0x1F));
+       pmap->pm_flags &= ~PM_MODIFIED;
+       pmap->pm_tlbpid = -1;
+       if (pmap == cur_pmap)
+               cur_pmap = (pmap_t)0;
+#ifdef DIAGNOSTIC
+       /* invalidate user PTE cache */
+       for (i = 0; i < PMAP_HASH_UPAGES; i++)
+               MachTLBWriteIndexed(i + UPAGES, MACH_RESERVED_ADDR, 0);
+#endif
+}
+
+/*
+ *     Add a reference to the specified pmap.
+ */
+void
+pmap_reference(pmap)
+       pmap_t pmap;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_reference(%x)\n", pmap);
+#endif
+       if (pmap != NULL) {
+               simple_lock(&pmap->pm_lock);
+               pmap->pm_count++;
+               simple_unlock(&pmap->pm_lock);
+       }
+}
+
+/*
+ *     Remove the given range of addresses from the specified map.
+ *
+ *     It is assumed that the start and end are properly
+ *     rounded to the page size.
+ */
+void
+pmap_remove(pmap, sva, eva)
+       register pmap_t pmap;
+       vm_offset_t sva, eva;
+{
+       register vm_offset_t va;
+       register pv_entry_t pv, npv;
+       pmap_hash_t hp;
+       unsigned entry;
+
+#ifdef DEBUG
+       if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
+               printf("pmap_remove(%x, %x, %x)\n", pmap, sva, eva);
+       remove_stats.calls++;
+#endif
+       if (pmap == NULL)
+               return;
+
+       /* anything in the cache? */
+       if (pmap->pm_tlbpid < 0 || pmap->pm_hash == zero_pmap_hash)
+               return;
+
+       if (!pmap->pm_hash) {
+               register pt_entry_t *pte;
+
+               /* remove entries from kernel pmap */
+               pte = kvtopte(sva);
+               for (va = sva; va < eva; va += NBPG, pte++) {
+                       entry = pte->pt_entry;
+                       if (!(entry & PG_V))
+                               continue;
+                       if (entry & PG_WIRED)
+                               pmap->pm_stats.wired_count--;
+                       pmap->pm_stats.resident_count--;
+                       pmap_remove_pv(pmap, va, entry & PG_FRAME);
+#ifdef ATTR
+                       pmap_attributes[atop(entry - KERNBASE)] = 0;
+#endif
+                       pte->pt_entry = PG_NV;
+                       /*
+                        * Flush the TLB for the given address.
+                        */
+                       MachTLBFlushAddr(va);
+#ifdef DEBUG
+                       remove_stats.flushes++;
+#endif
+               }
+               return;
+       }
+
+       va = sva | (pmap->pm_tlbpid << VMMACH_TLB_PID_SHIFT);
+       eva |= (pmap->pm_tlbpid << VMMACH_TLB_PID_SHIFT);
+       /*
+        * If we are not in the current address space, just flush the
+        * software cache and not the hardware.
+        */
+       if (pmap != cur_pmap) {
+               for (; va < eva; va += NBPG) {
+                       hp = &pmap->pm_hash[PMAP_HASH(va)];
+                       if (hp->high != va)
+                               continue;
+
+                       hp->high = 0;
+                       entry = hp->low;
+                       if (entry & PG_WIRED)
+                               pmap->pm_stats.wired_count--;
+                       pmap->pm_stats.resident_count--;
+                       pmap_remove_pv(pmap, va & PG_FRAME, entry & PG_FRAME);
+#ifdef ATTR
+                       pmap_attributes[atop(entry - KERNBASE)] = 0;
+#endif
+                       pmap->pm_flags |= PM_MODIFIED;
+#ifdef DEBUG
+                       remove_stats.removes++;
+#endif
+               }
+               return;
+       }
+
+       for (; va < eva; va += NBPG) {
+               hp = &pmap->pm_hash[PMAP_HASH(va)];
+               if (hp->high != va)
+                       continue;
+
+               hp->high = 0;
+               entry = hp->low;
+               if (entry & PG_WIRED)
+                       pmap->pm_stats.wired_count--;
+               pmap->pm_stats.resident_count--;
+               pmap_remove_pv(pmap, va & PG_FRAME, entry & PG_FRAME);
+#ifdef ATTR
+               pmap_attributes[atop(entry - KERNBASE)] = 0;
+#endif
+               /*
+                * Flush the TLB for the given address.
+                */
+               MachTLBFlushAddr(va);
+#ifdef DEBUG
+               remove_stats.flushes++;
+#endif
+       }
+}
+
+/*
+ *     pmap_page_protect:
+ *
+ *     Lower the permission for all mappings to a given page.
+ */
+void
+pmap_page_protect(pa, prot)
+       vm_offset_t pa;
+       vm_prot_t prot;
+{
+       register pv_entry_t pv;
+       register vm_offset_t va;
+       int s;
+
+#ifdef DEBUG
+       if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) ||
+           prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE))
+               printf("pmap_page_protect(%x, %x)\n", pa, prot);
+#endif
+       if (!IS_VM_PHYSADDR(pa))
+               return;
+
+       switch (prot) {
+       case VM_PROT_ALL:
+               break;
+
+       /* copy_on_write */
+       case VM_PROT_READ:
+       case VM_PROT_READ|VM_PROT_EXECUTE:
+               pv = pa_to_pvh(pa);
+               s = splimp();
+               /*
+                * Loop over all current mappings setting/clearing as appropos.
+                */
+               if (pv->pv_pmap != NULL) {
+                       for (; pv; pv = pv->pv_next) {
+                               extern vm_offset_t pager_sva, pager_eva;
+                               va = pv->pv_va;
+
+                               /*
+                                * XXX don't write protect pager mappings
+                                */
+                               if (va >= pager_sva && va < pager_eva)
+                                       continue;
+                               pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE,
+                                       prot);
+                       }
+               }
+               splx(s);
+               break;
+
+       /* remove_all */
+       default:
+               pv = pa_to_pvh(pa);
+               s = splimp();
+               while (pv->pv_pmap != NULL) {
+                       pmap_remove(pv->pv_pmap, pv->pv_va,
+                                   pv->pv_va + PAGE_SIZE);
+               }
+               splx(s);
+       }
+}
+
+/*
+ *     Set the physical protection on the
+ *     specified range of this map as requested.
+ */
+void
+pmap_protect(pmap, sva, eva, prot)
+       register pmap_t pmap;
+       vm_offset_t sva, eva;
+       vm_prot_t prot;
+{
+       register vm_offset_t va;
+       pmap_hash_t hp;
+       u_int p;
+
+#ifdef DEBUG
+       if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
+               printf("pmap_protect(%x, %x, %x, %x)\n", pmap, sva, eva, prot);
+#endif
+       if (pmap == NULL)
+               return;
+
+       /* anything in the software cache? */
+       if (pmap->pm_tlbpid < 0 || pmap->pm_hash == zero_pmap_hash)
+               return;
+
+       if (!(prot & VM_PROT_READ)) {
+               pmap_remove(pmap, sva, eva);
+               return;
+       }
+
+       if (!pmap->pm_hash) {
+               register pt_entry_t *pte;
+
+               /*
+                * Change entries in kernel pmap.
+                * This will trap if the page is writeable (in order to set
+                * the dirty bit) even if the dirty bit is already set. The
+                * optimization isn't worth the effort since this code isn't
+                * executed much. The common case is to make a user page
+                * read-only.
+                */
+               p = (prot & VM_PROT_WRITE) ? PG_RW : PG_RO;
+               pte = kvtopte(sva);
+               for (va = sva; va < eva; va += NBPG, pte++) {
+                       if (!(pte->pt_entry & PG_V))
+                               continue;
+                       pte->pt_entry = (pte->pt_entry & ~(PG_M | PG_RO)) | p;
+                       /*
+                        * Update the TLB if the given address is in the cache.
+                        */
+                       MachTLBUpdate(va, pte->pt_entry);
+               }
+               return;
+       }
+
+       p = (prot & VM_PROT_WRITE) ? PG_RW : PG_RO;
+       va = sva | (pmap->pm_tlbpid << VMMACH_TLB_PID_SHIFT);
+       eva |= (pmap->pm_tlbpid << VMMACH_TLB_PID_SHIFT);
+       /*
+        * If we are not in the current address space, just flush the
+        * software cache and not the hardware.
+        */
+       if (pmap != cur_pmap) {
+               for (; va < eva; va += NBPG) {
+                       hp = &pmap->pm_hash[PMAP_HASH(va)];
+                       if (hp->high != va)
+                               continue;
+
+                       hp->low = (hp->low & ~(PG_M | PG_RO)) | p;
+                       pmap->pm_flags |= PM_MODIFIED;
+               }
+               return;
+       }
+
+       for (; va < eva; va += NBPG) {
+               hp = &pmap->pm_hash[PMAP_HASH(va)];
+               if (hp->high != va)
+                       continue;
+
+               hp->low = (hp->low & ~(PG_M | PG_RO)) | p;
+               /*
+                * Update the TLB if the given address is in the cache.
+                */
+               MachTLBUpdate(hp->high, hp->low);
+       }
+}
+
+/*
+ *     Insert the given physical page (p) at
+ *     the specified virtual address (v) in the
+ *     target physical map with the protection requested.
+ *
+ *     If specified, the page will be wired down, meaning
+ *     that the related pte can not be reclaimed.
+ *
+ *     NB:  This is the only routine which MAY NOT lazy-evaluate
+ *     or lose information.  That is, this routine must actually
+ *     insert this page into the given map NOW.
+ */
+void
+pmap_enter(pmap, va, pa, prot, wired)
+       register pmap_t pmap;
+       vm_offset_t va;
+       register vm_offset_t pa;
+       vm_prot_t prot;
+       boolean_t wired;
+{
+       register pmap_hash_t hp;
+       register u_int npte;
+       register int i;
+
+#ifdef DEBUG
+       if (pmapdebug & (PDB_FOLLOW|PDB_ENTER))
+               printf("pmap_enter(%x, %x, %x, %x, %x)\n",
+                      pmap, va, pa, prot, wired);
+#endif
+#ifdef DIAGNOSTIC
+       if (!pmap)
+               panic("pmap_enter: pmap");
+       if (pmap->pm_tlbpid < 0)
+               panic("pmap_enter: tlbpid");
+       if (pmap == kernel_pmap) {
+               enter_stats.kernel++;
+               if ((va & 0xE0000000) != 0xC0000000)
+                       panic("pmap_enter: kva");
+       } else {
+               enter_stats.user++;
+               if (va & 0x80000000)
+                       panic("pmap_enter: uva");
+       }
+       if (!(prot & VM_PROT_READ))
+               panic("pmap_enter: prot");
+#endif
+
+       /*
+        * See if we need to create a new TLB cache.
+        */
+       if (pmap->pm_hash == zero_pmap_hash) {
+               register vm_offset_t kva;
+               register pt_entry_t *pte;
+
+               kva = kmem_alloc(kernel_map, PMAP_HASH_SIZE);
+               pmap->pm_hash = (pmap_hash_t)kva;
+
+               /*
+                * Convert the kernel virtual address to a physical one
+                * and cache it in the pmap. Note: if the phyical address
+                * can change (due to memory compaction in kmem_alloc?),
+                * we will have to update things.
+                */
+               pte = kvtopte(kva);
+               for (i = 0; i < PMAP_HASH_UPAGES; i++) {
+                       pmap->pm_hash_ptes[i] = pte->pt_entry & ~PG_G;
+                       pte++;
+               }
+
+               /*
+                * Map in new TLB cache if it is current.
+                */
+               if (pmap == cur_pmap) {
+#ifdef DIAGNOSTIC
+                       if (pmap->pm_tlbpid < 0)
+                               panic("pmap_enter: tlbpid");
+#endif
+                       for (i = 0; i < PMAP_HASH_UPAGES; i++) {
+                               MachTLBWriteIndexed(i + UPAGES,
+                                       (PMAP_HASH_UADDR + (i << PGSHIFT)) |
+                                               (pmap->pm_tlbpid  <<
+                                               VMMACH_TLB_PID_SHIFT),
+                                       pmap->pm_hash_ptes[i]);
+                       }
+               }
+#ifdef DIAGNOSTIC
+               for (i = 0; i < PAGE_SIZE; i += sizeof(int), kva += sizeof(int))
+                       if (*(int *)kva != 0)
+                               panic("pmap_enter: *kva != 0");
+#endif
+       }
+
+       if (IS_VM_PHYSADDR(pa)) {
+               register pv_entry_t pv, npv;
+               int s;
+
+               if (!(prot & VM_PROT_WRITE))
+                       npte = PG_RO;
+               else {
+                       register vm_page_t mem;
+
+                       mem = PHYS_TO_VM_PAGE(pa);
+                       if ((int)va < 0) {
+                               /*
+                                * Don't bother to trap on kernel writes,
+                                * just record page as dirty.
+                                */
+                               npte = PG_M;
+                               mem->clean = FALSE;
+                       } else
+#ifdef ATTR
+                               if ((pmap_attributes[atop(pa - KERNBASE)] &
+                                   PMAP_ATTR_MOD) || !mem->clean)
+#else
+                               if (!mem->clean)
+#endif
+                                       npte = PG_M;
+                       else
+                               npte = 0;
+               }
+
+#ifdef DEBUG
+               enter_stats.managed++;
+#endif
+               /*
+                * Enter the pmap and virtual address into the
+                * physical to virtual map table.
+                */
+               pv = pa_to_pvh(pa);
+               s = splimp();
+#ifdef DEBUG
+               if (pmapdebug & PDB_ENTER)
+                       printf("pmap_enter: pv %x: was %x/%x/%x\n",
+                              pv, pv->pv_va, pv->pv_pmap, pv->pv_next);
+#endif
+               if (pv->pv_pmap == NULL) {
+                       /*
+                        * No entries yet, use header as the first entry
+                        */
+#ifdef DEBUG
+                       enter_stats.firstpv++;
+#endif
+                       pv->pv_va = va;
+                       pv->pv_pmap = pmap;
+                       pv->pv_next = NULL;
+                       pv->pv_flags = 0;
+               } else {
+                       /*
+                        * There is at least one other VA mapping this page.
+                        * Place this entry after the header.
+                        *
+                        * Note: the entry may already be in the table if
+                        * we are only changing the protection bits.
+                        */
+                       for (npv = pv; npv; npv = npv->pv_next)
+                               if (pmap == npv->pv_pmap && va == npv->pv_va) {
+#ifdef DIAGNOSTIC
+                                   if (!pmap->pm_hash) {
+                                       unsigned entry;
+
+                                       entry = kvtopte(va)->pt_entry;
+                                       if (!(entry & PG_V) ||
+                                           (entry & PG_FRAME) != pa)
+                       printf("found kva %x pa %x in pv_table but != %x\n",
+                               va, pa, entry);
+                                   } else {
+                                       hp = &pmap->pm_hash[PMAP_HASH(va)];
+                                       if (hp->high != (va |
+                                           (pmap->pm_tlbpid <<
+                                           VMMACH_TLB_PID_SHIFT)) ||
+                                           (hp->low & PG_FRAME) != pa)
+                       printf("found va %x pa %x in pv_table but != %x %x\n",
+                               va, pa, hp->high, hp->low);
+                                   }
+#endif
+                                       goto fnd;
+                               }
+                       /* can this cause us to recurse forever? */
+                       npv = (pv_entry_t)
+                               malloc(sizeof *npv, M_VMPVENT, M_NOWAIT);
+                       npv->pv_va = va;
+                       npv->pv_pmap = pmap;
+                       npv->pv_next = pv->pv_next;
+                       pv->pv_next = npv;
+#ifdef DEBUG
+                       if (!npv->pv_next)
+                               enter_stats.secondpv++;
+#endif
+               fnd:
+                       ;
+               }
+               splx(s);
+       } else {
+               /*
+                * Assumption: if it is not part of our managed memory
+                * then it must be device memory which may be volitile.
+                */
+#ifdef DEBUG
+               enter_stats.unmanaged++;
+#endif
+               printf("pmap_enter: UNMANAGED ADDRESS va %x pa %x\n",
+                       va, pa); /* XXX */
+               npte = (prot & VM_PROT_WRITE) ? PG_M : PG_RO;
+       }
+
+       if (!pmap->pm_hash) {
+               register pt_entry_t *pte;
+
+               /* enter entries into kernel pmap */
+               pte = kvtopte(va);
+               npte |= pa | PG_V | PG_G;
+               if (wired) {
+                       pmap->pm_stats.wired_count += pmaxpagesperpage;
+                       npte |= PG_WIRED;
+               }
+               i = pmaxpagesperpage;
+               do {
+                       if (!(pte->pt_entry & PG_V)) {
+                               pmap->pm_stats.resident_count++;
+                               MachTLBWriteRandom(va, npte);
+                       } else {
+                               /*
+                                * Update the same virtual address entry.
+                                */
+                               MachTLBUpdate(va, npte);
+                       }
+                       pte->pt_entry = npte;
+                       va += NBPG;
+                       npte += NBPG;
+                       pte++;
+               } while (--i != 0);
+               return;
+       }
+
+       /*
+        * Now validate mapping with desired protection/wiring.
+        * Assume uniform modified and referenced status for all
+        * PMAX pages in a MACH page.
+        */
+       npte |= pa | PG_V;
+       if (wired) {
+               pmap->pm_stats.wired_count += pmaxpagesperpage;
+               npte |= PG_WIRED;
+       }
+#ifdef DEBUG
+       if (pmapdebug & PDB_ENTER)
+               printf("pmap_enter: new pte value %x\n", npte);
+#endif
+       va |= (pmap->pm_tlbpid << VMMACH_TLB_PID_SHIFT);
+       i = pmaxpagesperpage;
+       do {
+               hp = &pmap->pm_hash[PMAP_HASH(va)];
+               if (!hp->high) {
+                       pmap->pm_stats.resident_count++;
+                       hp->high = va;
+                       hp->low = npte;
+                       MachTLBWriteRandom(va, npte);
+               } else {
+#ifdef DEBUG
+                       enter_stats.cachehit++;
+#endif
+                       if (hp->high == va) {
+                               /*
+                                * Update the same entry.
+                                */
+                               hp->low = npte;
+                               MachTLBUpdate(va, npte);
+                       } else if (!(hp->low & PG_WIRED)) {
+                               MachTLBFlushAddr(hp->high);
+                               pmap_remove_pv(pmap, hp->high & PG_FRAME,
+                                       hp->low & PG_FRAME);
+                               hp->high = va;
+                               hp->low = npte;
+                               MachTLBWriteRandom(va, npte);
+                       } else {
+                               /*
+                                * Don't replace wired entries, just update
+                                * the hardware TLB.
+                                * Bug: routines to flush the TLB won't know
+                                * that the entry is in the hardware.
+                                */
+                               printf("pmap_enter: wired va %x %x\n", va,
+                                       hp->low); /* XXX */
+                               panic("pmap_enter: wired"); /* XXX */
+                               MachTLBWriteRandom(va, npte);
+                       }
+               }
+               va += NBPG;
+               npte += NBPG;
+       } while (--i != 0);
+}
+
+/*
+ *     Routine:        pmap_change_wiring
+ *     Function:       Change the wiring attribute for a map/virtual-address
+ *                     pair.
+ *     In/out conditions:
+ *                     The mapping must already exist in the pmap.
+ */
+void
+pmap_change_wiring(pmap, va, wired)
+       register pmap_t pmap;
+       vm_offset_t va;
+       boolean_t wired;
+{
+       register pmap_hash_t hp;
+       u_int p;
+       int i;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_change_wiring(%x, %x, %x)\n", pmap, va, wired);
+#endif
+       if (pmap == NULL)
+               return;
+
+       p = wired ? PG_WIRED : 0;
+
+       /*
+        * Don't need to flush the TLB since PG_WIRED is only in software.
+        */
+       if (!pmap->pm_hash) {
+               register pt_entry_t *pte;
+
+               /* change entries in kernel pmap */
+               pte = kvtopte(va);
+               i = pmaxpagesperpage;
+               if (!(pte->pt_entry & PG_WIRED) && p)
+                       pmap->pm_stats.wired_count += i;
+               else if ((pte->pt_entry & PG_WIRED) && !p)
+                       pmap->pm_stats.wired_count -= i;
+               do {
+                       if (!(pte->pt_entry & PG_V))
+                               continue;
+                       pte->pt_entry = (pte->pt_entry & ~PG_WIRED) | p;
+                       pte++;
+               } while (--i != 0);
+       } else if (pmap->pm_tlbpid >= 0 && pmap->pm_hash != zero_pmap_hash) {
+               i = pmaxpagesperpage;
+               do {
+                       hp = &pmap->pm_hash[PMAP_HASH(va)];
+                       if (!hp->high)
+                               continue;
+                       if (!(hp->low & PG_WIRED) && p)
+                               pmap->pm_stats.wired_count++;
+                       else if ((hp->low & PG_WIRED) && !p)
+                               pmap->pm_stats.wired_count--;
+                       hp->low = (hp->low & ~PG_WIRED) | p;
+                       va += NBPG;
+               } while (--i != 0);
+       }
+}
+
+/*
+ *     Routine:        pmap_extract
+ *     Function:
+ *             Extract the physical page address associated
+ *             with the given map/virtual_address pair.
+ */
+vm_offset_t
+pmap_extract(pmap, va)
+       register pmap_t pmap;
+       vm_offset_t va;
+{
+       register vm_offset_t pa;
+       register pmap_hash_t hp;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_extract(%x, %x) -> ", pmap, va);
+#endif
+
+       if (!pmap->pm_hash)
+               pa = kvtopte(va)->pt_entry & PG_FRAME;
+       else if (pmap->pm_tlbpid >= 0) {
+               hp = &pmap->pm_hash[PMAP_HASH(va)];
+               if (hp->high)
+                       pa = hp->low & PG_FRAME;
+               else
+                       pa = 0;
+       } else
+               pa = 0;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("%x\n", pa);
+#endif
+       return(pa);
+}
+
+/*
+ *     Copy the range specified by src_addr/len
+ *     from the source map to the range dst_addr/len
+ *     in the destination map.
+ *
+ *     This routine is only advisory and need not do anything.
+ */
+void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
+       pmap_t dst_pmap;
+       pmap_t src_pmap;
+       vm_offset_t dst_addr;
+       vm_size_t len;
+       vm_offset_t src_addr;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_copy(%x, %x, %x, %x, %x)\n",
+                      dst_pmap, src_pmap, dst_addr, len, src_addr);
+#endif
+}
+
+/*
+ *     Require that all active physical maps contain no
+ *     incorrect entries NOW.  [This update includes
+ *     forcing updates of any address map caching.]
+ *
+ *     Generally used to insure that a thread about
+ *     to run will see a semantically correct world.
+ */
+void pmap_update()
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_update()\n");
+#endif
+}
+
+/*
+ *     Routine:        pmap_collect
+ *     Function:
+ *             Garbage collects the physical map system for
+ *             pages which are no longer used.
+ *             Success need not be guaranteed -- that is, there
+ *             may well be pages which are not referenced, but
+ *             others may be collected.
+ *     Usage:
+ *             Called by the pageout daemon when pages are scarce.
+ */
+void
+pmap_collect(pmap)
+       pmap_t pmap;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_collect(%x)\n", pmap);
+#endif
+}
+
+/*
+ *     pmap_zero_page zeros the specified (machine independent)
+ *     page.
+ */
+void
+pmap_zero_page(phys)
+       register vm_offset_t phys;
+{
+       register vm_offset_t end;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_zero_page(%x)\n", phys);
+#endif
+       end = phys + PAGE_SIZE;
+       do {
+               ((unsigned *)phys)[0] = 0;
+               ((unsigned *)phys)[1] = 0;
+               ((unsigned *)phys)[2] = 0;
+               ((unsigned *)phys)[3] = 0;
+               phys += 4 * sizeof(unsigned);
+       } while (phys != end);
+}
+
+/*
+ *     pmap_copy_page copies the specified (machine independent)
+ *     page.
+ */
+void
+pmap_copy_page(src, dst)
+       register vm_offset_t src, dst;
+{
+       register vm_offset_t end;
+       register unsigned tmp0, tmp1, tmp2, tmp3;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_copy_page(%x, %x)\n", src, dst);
+#endif
+       end = src + PAGE_SIZE;
+       do {
+               tmp0 = ((unsigned *)src)[0];
+               tmp1 = ((unsigned *)src)[1];
+               tmp2 = ((unsigned *)src)[2];
+               tmp3 = ((unsigned *)src)[3];
+               ((unsigned *)dst)[0] = tmp0;
+               ((unsigned *)dst)[1] = tmp1;
+               ((unsigned *)dst)[2] = tmp2;
+               ((unsigned *)dst)[3] = tmp3;
+               src += 4 * sizeof(unsigned);
+               dst += 4 * sizeof(unsigned);
+       } while (src != end);
+}
+
+/*
+ *     Routine:        pmap_pageable
+ *     Function:
+ *             Make the specified pages (by pmap, offset)
+ *             pageable (or not) as requested.
+ *
+ *             A page which is not pageable may not take
+ *             a fault; therefore, its page table entry
+ *             must remain valid for the duration.
+ *
+ *             This routine is merely advisory; pmap_enter
+ *             will specify that these pages are to be wired
+ *             down (or not) as appropriate.
+ */
+void
+pmap_pageable(pmap, sva, eva, pageable)
+       pmap_t          pmap;
+       vm_offset_t     sva, eva;
+       boolean_t       pageable;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_pageable(%x, %x, %x, %x)\n",
+                      pmap, sva, eva, pageable);
+#endif
+}
+
+/*
+ *     Clear the modify bits on the specified physical page.
+ */
+void
+pmap_clear_modify(pa)
+       vm_offset_t pa;
+{
+       pmap_hash_t hp;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_clear_modify(%x)\n", pa);
+#endif
+#ifdef ATTR
+       pmap_attributes[atop(pa - KERNBASE)] &= ~PMAP_ATTR_MOD;
+#endif
+}
+
+/*
+ *     pmap_clear_reference:
+ *
+ *     Clear the reference bit on the specified physical page.
+ */
+void
+pmap_clear_reference(pa)
+       vm_offset_t pa;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_clear_reference(%x)\n", pa);
+#endif
+#ifdef ATTR
+       pmap_attributes[atop(pa - KERNBASE)] &= ~PMAP_ATTR_REF;
+#endif
+}
+
+/*
+ *     pmap_is_referenced:
+ *
+ *     Return whether or not the specified physical page is referenced
+ *     by any physical maps.
+ */
+boolean_t
+pmap_is_referenced(pa)
+       vm_offset_t pa;
+{
+#ifdef ATTR
+       return(pmap_attributes[atop(pa - KERNBASE)] & PMAP_ATTR_REF);
+#else
+       return(FALSE);
+#endif
+}
+
+/*
+ *     pmap_is_modified:
+ *
+ *     Return whether or not the specified physical page is modified
+ *     by any physical maps.
+ */
+boolean_t
+pmap_is_modified(pa)
+       vm_offset_t pa;
+{
+#ifdef ATTR
+       return(pmap_attributes[atop(pa - KERNBASE)] & PMAP_ATTR_MOD);
+#else
+       return(FALSE);
+#endif
+}
+
+vm_offset_t
+pmap_phys_address(ppn)
+       int ppn;
+{
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_phys_address(%x)\n", ppn);
+#endif
+       panic("pmap_phys_address"); /* XXX */
+       return(pmax_ptob(ppn));
+}
+
+/*
+ * Miscellaneous support routines
+ */
+
+/*
+ * Allocate a hardware PID and return it.
+ * Also, change the hardwired TLB entry to point to the current TLB cache.
+ * This is called by swtch().
+ */
+int
+pmap_alloc_tlbpid(p)
+       register struct proc *p;
+{
+       register pmap_t pmap;
+       register u_int i;
+       register int id;
+
+       pmap = &p->p_vmspace->vm_pmap;
+       if ((id = pmap->pm_tlbpid) >= 0) {
+               if (pmap->pm_flags & PM_MODIFIED) {
+                       pmap->pm_flags &= ~PM_MODIFIED;
+                       MachTLBFlushPID(id);
+               }
+               goto done;
+       }
+
+       if ((i = whichpids[0]) != 0xFFFFFFFF)
+               id = 0;
+       else if ((i = whichpids[1]) != 0xFFFFFFFF)
+               id = 32;
+       else {
+               register struct proc *q;
+               register pmap_t q_pmap;
+
+               /*
+                * Have to find a tlbpid to recycle.
+                * There is probably a better way to do this.
+                */
+               for (q = allproc; q != NULL; q = q->p_nxt) {
+                       q_pmap = &q->p_vmspace->vm_pmap;
+                       if ((id = q_pmap->pm_tlbpid) < 0)
+                               continue;
+                       if (q->p_stat != SRUN)
+                               goto fnd;
+               }
+               if (id < 0)
+                       panic("TLBPidAlloc");
+       fnd:
+               printf("pmap_alloc_tlbpid: recycle pid %d (%s) tlbpid %d\n",
+                       q->p_pid, q->p_comm, id); /* XXX */
+               /*
+                * Even though the virtual to physical mapping hasn't changed,
+                * we need to clear the PID tag in the high entry of the cache.
+                */
+               if (q_pmap->pm_hash != zero_pmap_hash) {
+                       register pmap_hash_t hp;
+
+                       hp = q_pmap->pm_hash;
+                       for (i = 0; i < PMAP_HASH_NUM_ENTRIES; i++, hp++) {
+                               if (!hp->high)
+                                       continue;
+
+                               if (hp->low & PG_WIRED) {
+                                       printf("Clearing wired user entry! h %x l %x\n", hp->high, hp->low);
+                                       panic("pmap_alloc_tlbpid: wired");
+                               }
+                               pmap_remove_pv(pmap, hp->high & PG_FRAME,
+                                       hp->low & PG_FRAME);
+                               hp->high = 0;
+                               q_pmap->pm_stats.resident_count--;
+                       }
+               }
+               q_pmap->pm_tlbpid = -1;
+               MachTLBFlushPID(id);
+#ifdef DEBUG
+               remove_stats.pidflushes++;
+#endif
+               pmap->pm_tlbpid = id;
+               goto done;
+       }
+       while (i & 1) {
+               i >>= 1;
+               id++;
+       }
+       whichpids[id >> 5] |= 1 << (id & 0x1F);
+       pmap->pm_tlbpid = id;
+done:
+       /*
+        * Map in new TLB cache.
+        */
+       if (pmap == cur_pmap)
+               return (id);
+       cur_pmap = pmap;
+       for (i = 0; i < PMAP_HASH_UPAGES; i++) {
+               MachTLBWriteIndexed(i + UPAGES,
+                       (PMAP_HASH_UADDR + (i << PGSHIFT)) |
+                               (id << VMMACH_TLB_PID_SHIFT),
+                       pmap->pm_hash_ptes[i]);
+       }
+       return (id);
+}
+
+/*
+ * Remove a physical to virtual address translation.
+ */
+void
+pmap_remove_pv(pmap, va, pa)
+       pmap_t pmap;
+       vm_offset_t va, pa;
+{
+       register pv_entry_t pv, npv;
+       int s;
+
+#ifdef DEBUG
+       if (pmapdebug & PDB_FOLLOW)
+               printf("pmap_remove_pv(%x, %x, %x)\n", pmap, va, pa);
+#endif
+       /*
+        * Remove page from the PV table (raise IPL since we
+        * may be called at interrupt time).
+        */
+       if (!IS_VM_PHYSADDR(pa))
+               return;
+       pv = pa_to_pvh(pa);
+       s = splimp();
+       /*
+        * If it is the first entry on the list, it is actually
+        * in the header and we must copy the following entry up
+        * to the header.  Otherwise we must search the list for
+        * the entry.  In either case we free the now unused entry.
+        */
+       if (pmap == pv->pv_pmap && va == pv->pv_va) {
+               npv = pv->pv_next;
+               if (npv) {
+                       *pv = *npv;
+                       free((caddr_t)npv, M_VMPVENT);
+               } else
+                       pv->pv_pmap = NULL;
+#ifdef DEBUG
+               remove_stats.pvfirst++;
+#endif
+       } else {
+               for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) {
+#ifdef DEBUG
+                       remove_stats.pvsearch++;
+#endif
+                       if (pmap == npv->pv_pmap && va == npv->pv_va)
+                               goto fnd;
+               }
+#ifdef DIAGNOSTIC
+               printf("pmap_remove_pv(%x, %x, %x) not found\n", pmap, va, pa);
+               panic("pmap_remove_pv");
+#endif
+       fnd:
+               pv->pv_next = npv->pv_next;
+               free((caddr_t)npv, M_VMPVENT);
+       }
+       splx(s);
+}
+
+#ifdef DEBUG
+pmap_print(pmap)
+       pmap_t pmap;
+{
+       register pmap_hash_t hp;
+       register int i;
+
+       printf("\tpmap_print(%x)\n", pmap);
+
+       if (pmap->pm_hash == zero_pmap_hash) {
+               printf("pm_hash == zero\n");
+               return;
+       }
+       if (pmap->pm_hash == (pmap_hash_t)0) {
+               printf("pm_hash == kernel\n");
+               return;
+       }
+       hp = pmap->pm_hash;
+       for (i = 0; i < PMAP_HASH_NUM_ENTRIES; i++, hp++) {
+               if (!hp->high)
+                       continue;
+               printf("%d: hi %x low %x\n", i, hp->high, hp->low);
+       }
+}
+#endif
diff --git a/usr/src/sys/pmax/pmax/swapgeneric.c b/usr/src/sys/pmax/pmax/swapgeneric.c
new file mode 100644 (file)
index 0000000..280dd9d
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)swapgeneric.c       7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "buf.h"
+#include "systm.h"
+#include "reboot.h"
+
+#include "../dev/device.h"
+
+/*
+ * Generic configuration;  all in one
+ */
+dev_t  rootdev = NODEV;
+dev_t  argdev = NODEV;
+dev_t  dumpdev = NODEV;
+int    nswap;
+struct swdevt swdevt[] = {
+       { -1,   1,      0 },
+       { 0,    0,      0 },
+};
+int    dmmin, dmmax, dmtext;
+
+extern struct driver rzdriver;
+
+struct genericconf {
+       caddr_t gc_driver;
+       char    *gc_name;
+       dev_t   gc_root;
+} genericconf[] = {
+       { (caddr_t)&rzdriver,   "rz",   makedev(0, 0),  },
+       { 0 },
+};
+
+setconf()
+{
+       register struct scsi_device *dp;
+       register struct genericconf *gc;
+       register char *cp, *gp;
+       int unit, swaponroot = 0;
+
+       if (rootdev != NODEV)
+               goto doswap;
+       unit = 0;
+       if (boothowto & RB_ASKNAME) {
+               char name[128];
+retry:
+               printf("root device? ");
+               gets(name);
+               for (gc = genericconf; gc->gc_driver; gc++)
+                   for (cp = name, gp = gc->gc_name; *cp == *gp; cp++)
+                       if (*++gp == 0)
+                               goto gotit;
+               printf("use one of:");
+               for (gc = genericconf; gc->gc_driver; gc++)
+                       printf(" %s%%d", gc->gc_name);
+               printf("\n");
+               goto retry;
+gotit:
+               if (*++cp < '0' || *cp > '9') {
+                       printf("bad/missing unit number\n");
+                       goto retry;
+               }
+               while (*cp >= '0' && *cp <= '9')
+                       unit = 10 * unit + *cp++ - '0';
+               if (*cp == '*')
+                       swaponroot++;
+               goto found;
+       }
+       for (gc = genericconf; gc->gc_driver; gc++) {
+               for (dp = scsi_dinit; dp->sd_driver; dp++) {
+                       if (dp->sd_alive == 0)
+                               continue;
+                       if (dp->sd_unit == unit &&
+                           dp->sd_driver == (struct driver *)gc->gc_driver) {
+                               printf("root on %s%d%c\n",
+                                       dp->sd_driver->d_name, unit,
+                                       "ab"[swaponroot]);
+                               goto found;
+                       }
+               }
+       }
+       printf("no suitable root\n");
+       goto retry;
+found:
+       gc->gc_root = makedev(major(gc->gc_root), unit*8);
+       rootdev = gc->gc_root;
+doswap:
+       swdevt[0].sw_dev = argdev = dumpdev =
+           makedev(major(rootdev), minor(rootdev)+1);
+       /* swap size and dumplo set during autoconfigure */
+       if (swaponroot)
+               rootdev = dumpdev;
+}
+
+gets(cp)
+       char *cp;
+{
+       register char *lp;
+       register c;
+       int s;
+
+       lp = cp;
+       s = spltty();
+       for (;;) {
+               cnputc(c = cngetc());
+               switch (c) {
+               case '\r':
+                       cnputc('\n');
+                       *lp++ = '\0';
+                       break;
+               case '\n':
+                       cnputc('\r');
+                       *lp++ = '\0';
+                       break;
+               case '\b':
+               case '\177':
+                       if (lp > cp) {
+                               lp--;
+                               cnputc(' ');
+                               cnputc('\b');
+                       }
+                       continue;
+               case '#':
+                       lp--;
+                       if (lp < cp)
+                               lp = cp;
+                       continue;
+               case '@':
+               case 'u'&037:
+                       lp = cp;
+                       cnputc('\n');
+                       continue;
+               default:
+                       *lp++ = c;
+                       continue;
+               }
+               break;
+       }
+       splx(s);
+}
diff --git a/usr/src/sys/pmax/pmax/sys_machdep.c b/usr/src/sys/pmax/pmax/sys_machdep.c
new file mode 100644 (file)
index 0000000..806b2db
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)sys_machdep.c       7.1 (Berkeley) %G%
+ */
+
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/ioctl.h"
+#include "sys/file.h"
+#include "sys/time.h"
+#include "sys/proc.h"
+#include "sys/uio.h"
+#include "sys/kernel.h"
+#include "sys/mtio.h"
+#include "sys/buf.h"
+#include "sys/trace.h"
+
+#ifdef TRACE
+int    nvualarm;
+
+vtrace(p, uap, retval)
+       struct proc *p;
+       register struct args {
+               int     request;
+               int     value;
+       } *uap;
+       int *retval;
+{
+       int vdoualarm();
+
+       switch (uap->request) {
+
+       case VTR_DISABLE:               /* disable a trace point */
+       case VTR_ENABLE:                /* enable a trace point */
+               if (uap->value < 0 || uap->value >= TR_NFLAGS)
+                       return (EINVAL);
+               *retval = traceflags[uap->value];
+               traceflags[uap->value] = uap->request;
+               break;
+
+       case VTR_VALUE:         /* return a trace point setting */
+               if (uap->value < 0 || uap->value >= TR_NFLAGS)
+                       return (EINVAL);
+               *retval = traceflags[uap->value];
+               break;
+
+       case VTR_UALARM:        /* set a real-time ualarm, less than 1 min */
+               if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5)
+                       return (EINVAL);
+               nvualarm++;
+               timeout(vdoualarm, (caddr_t)p->p_pid, uap->value);
+               break;
+
+       case VTR_STAMP:
+               trace(TR_STAMP, uap->value, p->p_pid);
+               break;
+       }
+       return (0);
+}
+
+vdoualarm(arg)
+       int arg;
+{
+       register struct proc *p;
+
+       p = pfind(arg);
+       if (p)
+               psignal(p, 16);
+       nvualarm--;
+}
+#endif
diff --git a/usr/src/sys/pmax/pmax/trap.c b/usr/src/sys/pmax/pmax/trap.c
new file mode 100644 (file)
index 0000000..4525a55
--- /dev/null
@@ -0,0 +1,1048 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: trap.c 1.32 91/04/06$
+ *
+ *     @(#)trap.c      7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "kernel.h"
+#include "signalvar.h"
+#include "user.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+#include "net/netisr.h"
+
+#include "../include/trap.h"
+#include "../include/psl.h"
+#include "../include/reg.h"
+#include "../include/cpu.h"
+#include "pte.h"
+#include "clockreg.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+/*
+ * This is a kludge to allow X windows to work.
+ */
+#define X_KLUGE
+
+#ifdef X_KLUGE
+#define USER_MAP_ADDR  0x4000
+#define NPTES 300
+static pt_entry_t UserMapPtes[NPTES];
+static unsigned nUserMapPtes;
+static pid_t UserMapPid;
+#endif
+
+struct proc *machFPCurProcPtr;         /* pointer to last proc to use FP */
+
+extern void MachKernGenException();
+extern void MachUserGenException();
+extern void MachKernIntr();
+extern void MachUserIntr();
+extern void MachTLBModException();
+extern void MachTLBMissException();
+extern void MemErrorInterrupt();
+
+void (*machExceptionTable[])() = {
+/*
+ * The kernel exception handlers.
+ */
+       MachKernIntr,                   /* external interrupt */
+       MachKernGenException,           /* TLB modification */
+       MachTLBMissException,           /* TLB miss (load or instr. fetch) */
+       MachTLBMissException,           /* TLB miss (store) */
+       MachKernGenException,           /* address error (load or I-fetch) */
+       MachKernGenException,           /* address error (store) */
+       MachKernGenException,           /* bus error (I-fetch) */
+       MachKernGenException,           /* bus error (load or store) */
+       MachKernGenException,           /* system call */
+       MachKernGenException,           /* breakpoint */
+       MachKernGenException,           /* reserved instruction */
+       MachKernGenException,           /* coprocessor unusable */
+       MachKernGenException,           /* arithmetic overflow */
+       MachKernGenException,           /* reserved */
+       MachKernGenException,           /* reserved */
+       MachKernGenException,           /* reserved */
+/*
+ * The user exception handlers.
+ */
+       MachUserIntr,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+       MachUserGenException,
+};
+
+char   *trap_type[] = {
+       "external interrupt",
+       "TLB modification",
+       "TLB miss (load or instr. fetch)",
+       "TLB miss (store)",
+       "address error (load or I-fetch)",
+       "address error (store)",
+       "bus error (I-fetch)",
+       "bus error (load or store)",
+       "system call",
+       "breakpoint",
+       "reserved instruction",
+       "coprocessor unusable",
+       "arithmetic overflow",
+       "reserved 13",
+       "reserved 14",
+       "reserved 15",
+};
+
+#ifdef DEBUG
+#define TRAPSIZE       10
+struct trapdebug {             /* trap history buffer for debugging */
+       u_int   status;
+       u_int   cause;
+       u_int   vadr;
+       u_int   pc;
+       u_int   ra;
+       u_int   code;
+} trapdebug[TRAPSIZE], *trp = trapdebug;
+#endif
+
+/*
+ * Handle an exception.
+ * Called from MachKernGenException() or MachUserGenException()
+ * when a processor trap occurs.
+ * In the case of a kernel trap, we return the pc where to resume if
+ * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc.
+ */
+unsigned
+trap(statusReg, causeReg, vadr, pc, args /* XXX */)
+       unsigned statusReg;     /* status register at time of the exception */
+       unsigned causeReg;      /* cause register at time of exception */
+       unsigned vadr;          /* address (if any) the fault occured on */
+       unsigned pc;            /* program counter where to continue */
+{
+       register int type, i;
+       unsigned ucode = 0;
+       register struct proc *p = curproc;
+       struct timeval syst;
+       vm_prot_t ftype;
+       extern unsigned onfault_table[];
+
+#ifdef DEBUG
+       trp->status = statusReg;
+       trp->cause = causeReg;
+       trp->vadr = vadr;
+       trp->pc = pc;
+       trp->ra = !USERMODE(statusReg) ? ((int *)&args)[19] : p->p_regs[RA];
+       trp->code = 0;
+       if (++trp == &trapdebug[TRAPSIZE])
+               trp = trapdebug;
+#endif
+
+       cnt.v_trap++;
+       type = (causeReg & MACH_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT;
+       if (USERMODE(statusReg)) {
+               type |= T_USER;
+               syst = p->p_stime;
+       }
+
+       /*
+        * Enable hardware interrupts if they were on before.
+        * We only respond to software interrupts when returning to user mode.
+        */
+       if (statusReg & MACH_SR_INT_ENA_PREV)
+               splx((statusReg & MACH_HARD_INT_MASK) | MACH_SR_INT_ENA_CUR);
+
+       switch (type) {
+       case T_TLB_MOD:
+               if ((int)vadr < 0) {
+                       register pt_entry_t *pte;
+                       register unsigned entry;
+#ifndef ATTR
+                       register vm_offset_t pa;
+#endif
+
+                       pte = kvtopte(vadr);
+                       entry = pte->pt_entry;
+                       if (entry & PG_RO) {
+                               /* write to read only page in the kernel */
+                               ftype = VM_PROT_WRITE;
+                               goto kernel_fault;
+                       }
+                       entry |= PG_M;
+                       pte->pt_entry = entry;
+                       vadr &= PG_FRAME;
+                       printf("trap: TLBupdate hi %x lo %x i %x\n", vadr,
+                               entry, MachTLBUpdate(vadr, entry)); /* XXX */
+#ifdef ATTR
+                       pmap_attributes[atop(entry - KERNBASE)] |= PMAP_ATTR_MOD;
+#else
+                       pa = entry & PG_FRAME;
+                       if (!IS_VM_PHYSADDR(pa))
+                               panic("trap: kmod");
+                       PHYS_TO_VM_PAGE(pa)->clean = FALSE;
+#endif
+                       return (pc);
+               }
+               /* FALLTHROUGH */
+
+       case T_TLB_MOD+T_USER:
+           {
+               pmap_hash_t hp;
+#ifndef ATTR
+               vm_offset_t pa;
+#endif
+#ifdef DIAGNOSTIC
+               extern pmap_hash_t zero_pmap_hash;
+               extern pmap_t cur_pmap;
+
+               if (cur_pmap->pm_hash == zero_pmap_hash)
+                       panic("tlbmod");
+#endif
+               hp = &((pmap_hash_t)PMAP_HASH_UADDR)[PMAP_HASH(vadr)];
+               if (hp->low & PG_RO) {
+                       ftype = VM_PROT_WRITE;
+                       goto dofault;
+               }
+               hp->low |= PG_M;
+               printf("trap: TLBupdate hi %x lo %x i %x\n", hp->high, hp->low,
+                       MachTLBUpdate(hp->high, hp->low)); /* XXX */
+#ifdef ATTR
+               pmap_attributes[atop(hp->low - KERNBASE)] |= PMAP_ATTR_MOD;
+#else
+               pa = hp->low & PG_FRAME;
+               if (!IS_VM_PHYSADDR(pa))
+                       panic("trap: umod");
+               PHYS_TO_VM_PAGE(pa)->clean = FALSE;
+#endif
+               if (!USERMODE(statusReg))
+                       return (pc);
+               goto out;
+           }
+
+       case T_TLB_LD_MISS:
+       case T_TLB_ST_MISS:
+               ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ;
+               if ((int)vadr < 0) {
+                       register vm_offset_t va;
+                       int rv;
+
+               kernel_fault:
+                       va = trunc_page((vm_offset_t)vadr);
+                       rv = vm_fault(kernel_map, va, ftype, FALSE);
+                       if (rv == KERN_SUCCESS)
+                               return (pc);
+                       if (i = ((struct pcb *)UADDR)->pcb_onfault) {
+                               ((struct pcb *)UADDR)->pcb_onfault = 0;
+                               return (onfault_table[i]);
+                       }
+                       goto err;
+               }
+               goto dofault;
+
+       case T_TLB_LD_MISS+T_USER:
+               ftype = VM_PROT_READ;
+               goto dofault;
+
+       case T_TLB_ST_MISS+T_USER:
+               ftype = VM_PROT_WRITE;
+       dofault:
+           {
+               register vm_offset_t va;
+               register struct vmspace *vm = p->p_vmspace;
+               register vm_map_t map = &vm->vm_map;
+               int rv;
+
+#ifdef X_KLUGE
+               if (p->p_pid == UserMapPid &&
+                   (va = pmax_btop(vadr - USER_MAP_ADDR)) < nUserMapPtes) {
+                       register pt_entry_t *pte;
+
+                       pte = &UserMapPtes[va];
+                       MachTLBWriteRandom((vadr & PG_FRAME) |
+                               (vm->vm_pmap.pm_tlbpid << VMMACH_TLB_PID_SHIFT),
+                               pte->pt_entry);
+                       return (pc);
+               }
+#endif
+               va = trunc_page((vm_offset_t)vadr);
+               rv = vm_fault(map, va, ftype, FALSE);
+               if (rv != KERN_SUCCESS) {
+                       printf("vm_fault(%x, %x, %x, 0) -> %x ADR %x PC %x RA %x\n",
+                               map, va, ftype, rv, vadr, pc,
+                               !USERMODE(statusReg) ? ((int *)&args)[19] :
+                                       p->p_regs[RA]); /* XXX */
+                       printf("\tpid %d %s PC %x RA %x\n", p->p_pid,
+                               p->p_comm, p->p_regs[PC], p->p_regs[RA]); /* XXX */
+                       trapDump("vm_fault");
+               }
+               /*
+                * If this was a stack access we keep track of the maximum
+                * accessed stack size.  Also, if vm_fault gets a protection
+                * failure it is due to accessing the stack region outside
+                * the current limit and we need to reflect that as an access
+                * error.
+                */
+               if ((caddr_t)va >= vm->vm_maxsaddr) {
+                       if (rv == KERN_SUCCESS) {
+                               unsigned nss;
+
+                               nss = clrnd(btoc(USRSTACK-(unsigned)va));
+                               if (nss > vm->vm_ssize)
+                                       vm->vm_ssize = nss;
+                       } else if (rv == KERN_PROTECTION_FAILURE)
+                               rv = KERN_INVALID_ADDRESS;
+               }
+               if (rv == KERN_SUCCESS) {
+                       if (!USERMODE(statusReg))
+                               return (pc);
+                       goto out;
+               }
+               if (!USERMODE(statusReg)) {
+                       if (i = ((struct pcb *)UADDR)->pcb_onfault) {
+                               ((struct pcb *)UADDR)->pcb_onfault = 0;
+                               return (onfault_table[i]);
+                       }
+                       goto err;
+               }
+               ucode = vadr;
+               i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+               break;
+           }
+
+       case T_ADDR_ERR_LD+T_USER:      /* misaligned or kseg access */
+               if (vadr == KERNBASE) {
+                       struct args {
+                               int     i[1];
+                       } args;
+                       int rval[2];
+
+                       /*
+                        * Assume a signal handler is trying to return
+                        * (see sendsig() and sigreturn()). We have to
+                        * pop the sigframe struct to get the address of
+                        * the sigcontext.
+                        */
+                       args.i[0] = p->p_regs[SP] + 4 * sizeof(int);
+                       (void) sigreturn(curproc, &args, rval);
+                       goto out;
+               }
+               /* FALLTHROUGH */
+
+       case T_ADDR_ERR_ST+T_USER:      /* misaligned or kseg access */
+       case T_BUS_ERR_IFETCH+T_USER:   /* BERR asserted to cpu */
+       case T_BUS_ERR_LD_ST+T_USER:    /* BERR asserted to cpu */
+               i = SIGSEGV;
+               break;
+
+       case T_SYSCALL+T_USER:
+           {
+               register int *locr0 = p->p_regs;
+               register struct sysent *callp;
+               int code, numsys;
+               struct args {
+                       int i[8];
+               } args;
+               int rval[2];
+               struct sysent *systab;
+               extern unsigned MachEmulateBranch();
+               extern int nsysent;
+#ifdef ULTRIXCOMPAT
+               extern struct sysent ultrixsysent[];
+               extern int ultrixnsysent;
+#endif
+
+               cnt.v_syscall++;
+               /* compute next PC after syscall instruction */
+               if ((int)causeReg < 0)
+                       locr0[PC] = MachEmulateBranch(locr0, pc, 0, 0);
+               else
+                       locr0[PC] += 4;
+               systab = sysent;
+               numsys = nsysent;
+#ifdef ULTRIXCOMPAT
+               if (p->p_md.md_flags & MDP_ULTRIX) {
+                       systab = ultrixsysent;
+                       numsys = ultrixnsysent;
+               }
+#endif
+               code = locr0[V0];
+               if (code == 0) {                        /* indir */
+                       code = locr0[A0];
+                       if (code >= numsys)
+                               callp = &systab[0];     /* indir (illegal) */
+                       else
+                               callp = &systab[code];
+                       i = callp->sy_narg;
+                       args.i[0] = locr0[A1];
+                       args.i[1] = locr0[A2];
+                       args.i[2] = locr0[A3];
+                       if (i > 3) {
+                               i = copyin((caddr_t)(locr0[SP] +
+                                               3 * sizeof(int)),
+                                       (caddr_t)&args.i[3],
+                                       (u_int)(i - 3) * sizeof(int));
+                               if (i) {
+                                       locr0[V0] = i;
+                                       locr0[A3] = 1;
+#ifdef KTRACE
+                                       if (KTRPOINT(p, KTR_SYSCALL))
+                                               ktrsyscall(p->p_tracep, code,
+                                                       callp->sy_narg, args.i);
+#endif
+                                       goto done;
+                               }
+                       }
+               } else {
+                       if (code >= numsys)
+                               callp = &systab[0];     /* indir (illegal) */
+                       else
+                               callp = &systab[code];
+                       i = callp->sy_narg;
+                       args.i[0] = locr0[A0];
+                       args.i[1] = locr0[A1];
+                       args.i[2] = locr0[A2];
+                       args.i[3] = locr0[A3];
+                       if (i > 4) {
+                               i = copyin((caddr_t)(locr0[SP] +
+                                               4 * sizeof(int)),
+                                       (caddr_t)&args.i[4],
+                                       (u_int)(i - 4) * sizeof(int));
+                               if (i) {
+                                       locr0[V0] = i;
+                                       locr0[A3] = 1;
+#ifdef KTRACE
+                                       if (KTRPOINT(p, KTR_SYSCALL))
+                                               ktrsyscall(p->p_tracep, code,
+                                                       callp->sy_narg, args.i);
+#endif
+                                       goto done;
+                               }
+                       }
+               }
+#ifdef KTRACE
+               if (KTRPOINT(p, KTR_SYSCALL))
+                       ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
+#endif
+               rval[0] = 0;
+               rval[1] = locr0[V1];
+#ifdef DEBUG
+               if (trp == trapdebug)
+                       trapdebug[TRAPSIZE - 1].code = code;
+               else
+                       trp[-1].code = code;
+#endif
+               i = (*callp->sy_call)(p, &args, rval);
+               /*
+                * Reinitialize proc pointer `p' as it may be different
+                * if this is a child returning from fork syscall.
+                */
+               p = curproc;
+               locr0 = p->p_regs;
+#ifdef DEBUG
+               { int s;
+               s = splhigh();
+               trp->status = statusReg;
+               trp->cause = causeReg;
+               trp->vadr = locr0[SP];
+               trp->pc = locr0[PC];
+               trp->ra = locr0[RA];
+               trp->code = -code;
+               if (++trp == &trapdebug[TRAPSIZE])
+                       trp = trapdebug;
+               splx(s);
+               }
+#endif
+               if (i == ERESTART)
+                       locr0[PC] = pc;
+               else if (i != EJUSTRETURN) {
+                       if (i) {
+                               locr0[V0] = i;
+                               locr0[A3] = 1;
+                       } else {
+                               locr0[V0] = rval[0];
+                               locr0[V1] = rval[1];
+                               locr0[A3] = 0;
+                       }
+               }
+               /* else if (i == EJUSTRETURN) */
+                       /* nothing to do */
+       done:
+#ifdef KTRACE
+               if (KTRPOINT(p, KTR_SYSRET))
+                       ktrsysret(p->p_tracep, code, i, rval[0]);
+#endif
+               goto out;
+           }
+
+       case T_BREAK+T_USER:
+               i = SIGTRAP;
+               break;
+
+       case T_RES_INST+T_USER:
+               i = SIGILL;
+               break;
+
+       case T_COP_UNUSABLE+T_USER:
+               if ((causeReg & MACH_CR_COP_ERR) != 0x10000000) {
+                       i = SIGILL;     /* only FPU instructions allowed */
+                       break;
+               }
+               MachSwitchFPState(machFPCurProcPtr, p->p_regs);
+               machFPCurProcPtr = p;
+               p->p_regs[PS] |= MACH_SR_COP_1_BIT;
+               p->p_md.md_flags |= MDP_FPUSED;
+               goto out;
+
+       case T_OVFLOW+T_USER:
+               i = SIGFPE;
+               break;
+
+       case T_ADDR_ERR_LD:     /* misaligned access */
+       case T_ADDR_ERR_ST:     /* misaligned access */
+       case T_BUS_ERR_LD_ST:   /* BERR asserted to cpu */
+               if (i = ((struct pcb *)UADDR)->pcb_onfault) {
+                       ((struct pcb *)UADDR)->pcb_onfault = 0;
+                       return (onfault_table[i]);
+               }
+               /* FALLTHROUGH */
+
+       default:
+       err:
+               panic("trap");
+       }
+       printf("trap: pid %d %s sig %d adr %x pc %x ra %x\n", p->p_pid,
+               p->p_comm, i, vadr, pc, p->p_regs[RA]); /* XXX */
+       trapsignal(p, i, ucode);
+out:
+       /*
+        * Note: we should only get here if returning to user mode.
+        */
+       astpending = 0;
+       while (i = CURSIG(p))
+               psig(i);
+       p->p_pri = p->p_usrpri;
+       if (want_resched) {
+               /*
+                * Since we are curproc, clock will normally just change
+                * our priority without moving us from one queue to another
+                * (since the running process is not on a queue.)
+                * If that happened after we setrq ourselves but before we
+                * swtch()'ed, we might not be on the queue indicated by
+                * our priority.
+                */
+               (void) splclock();
+               setrq(p);
+               p->p_stats->p_ru.ru_nivcsw++;
+               swtch();
+               while (i = CURSIG(p))
+                       psig(i);
+       }
+       if (p->p_stats->p_prof.pr_scale) {
+               int ticks;
+               struct timeval *tv = &p->p_stime;
+
+               ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+                       (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+               if (ticks)
+                       addupc(pc, &p->p_stats->p_prof, ticks);
+       }
+       curpri = p->p_pri;
+       return (pc);
+}
+
+int temp; /*XXX*/
+
+/*
+ * Handle an interrupt.
+ * Called from MachKernIntr() or MachUserIntr()
+ * Note: curproc might be NULL.
+ */
+interrupt(statusReg, causeReg, pc)
+       unsigned statusReg;     /* status register at time of the exception */
+       unsigned causeReg;      /* cause register at time of exception */
+       unsigned pc;            /* program counter where to continue */
+{
+       register int i;
+       register unsigned mask;
+       clockframe cf;
+
+#ifdef DEBUG
+       trp->status = statusReg;
+       trp->cause = causeReg;
+       trp->vadr = 0;
+       trp->pc = pc;
+       trp->ra = 0;
+       trp->code = 0;
+       if (++trp == &trapdebug[TRAPSIZE])
+               trp = trapdebug;
+#endif
+
+       cnt.v_intr++;
+       mask = causeReg & statusReg;    /* pending interrupts & enable mask */
+       /*
+        * Enable hardware interrupts which were enabled but not pending.
+        * We only respond to software interrupts when returning to spl0.
+        */
+       splx((statusReg & ~causeReg & MACH_HARD_INT_MASK) |
+               MACH_SR_INT_ENA_CUR);
+       /*
+        * The first three tests should probably use
+        * some kind of table generated by 'config'.
+        */
+       if (mask & MACH_INT_MASK_0)
+               siiintr();
+       if (mask & MACH_INT_MASK_1)
+               leintr();
+       if (mask & MACH_INT_MASK_2)
+               dcintr();
+       if (mask & MACH_INT_MASK_3) {
+               register volatile struct chiptime *c =
+                       (volatile struct chiptime *)MACH_CLOCK_ADDR;
+
+               temp = c->regc; /* clear interrupt bits */
+               cf.pc = pc;
+               cf.ps = statusReg;
+               hardclock(cf);
+       }
+       if (mask & MACH_INT_MASK_4)
+               MemErrorInterrupt();
+       if (mask & MACH_INT_MASK_5) {
+               printf("FPU interrupt: PC %x CR %x SR %x\n",
+                       pc, causeReg, statusReg); /* XXX */
+               if (!USERMODE(statusReg)) {
+#ifdef DEBUG
+                       trapDump("fpintr");
+#else
+                       printf("FPU interrupt: PC %x CR %x SR %x\n",
+                               pc, causeReg, statusReg);
+#endif
+               } else
+                       MachFPInterrupt(statusReg, causeReg, pc);
+       }
+       if (mask & MACH_SOFT_INT_MASK_0) {
+               clockframe cf;
+
+               clearsoftclock();
+               cf.pc = pc;
+               cf.ps = statusReg;
+               softclock(cf);
+       }
+       /* process network interrupt if we trapped or will very soon */
+       if ((mask & MACH_SOFT_INT_MASK_1) ||
+           netisr && (statusReg & MACH_SOFT_INT_MASK_1)) {
+               clearsoftnet();
+#ifdef INET
+               if (netisr & (1 << NETISR_ARP)) {
+                       netisr &= ~(1 << NETISR_ARP);
+                       arpintr();
+               }
+               if (netisr & (1 << NETISR_IP)) {
+                       netisr &= ~(1 << NETISR_IP);
+                       ipintr();
+               }
+#endif
+#ifdef NS
+               if (netisr & (1 << NETISR_NS)) {
+                       netisr &= ~(1 << NETISR_NS);
+                       nsintr();
+               }
+#endif
+#ifdef ISO
+               if (netisr & (1 << NETISR_ISO)) {
+                       netisr &= ~(1 << NETISR_ISO);
+                       clnlintr();
+               }
+#endif
+       }
+}
+
+/*
+ * This is called from MachUserIntr() if astpending is set.
+ * This is very similar to the tail of trap().
+ */
+softintr(statusReg, pc)
+       unsigned statusReg;     /* status register at time of the exception */
+       unsigned pc;            /* program counter where to continue */
+{
+       register struct proc *p = curproc;
+       register int i;
+
+       cnt.v_soft++;
+       astpending = 0;
+       while (i = CURSIG(p))
+               psig(i);
+       p->p_pri = p->p_usrpri;
+       if (want_resched) {
+               /*
+                * Since we are curproc, clock will normally just change
+                * our priority without moving us from one queue to another
+                * (since the running process is not on a queue.)
+                * If that happened after we setrq ourselves but before we
+                * swtch()'ed, we might not be on the queue indicated by
+                * our priority.
+                */
+               (void) splclock();
+               setrq(p);
+               p->p_stats->p_ru.ru_nivcsw++;
+               swtch();
+               while (i = CURSIG(p))
+                       psig(i);
+       }
+       curpri = p->p_pri;
+}
+
+#ifdef DEBUG
+trapDump(msg)
+       char *msg;
+{
+       register int i;
+       int s;
+
+       s = splhigh();
+       printf("trapDump(%s)\n", msg);
+       for (i = 0; i < TRAPSIZE; i++) {
+               if (trp == trapdebug)
+                       trp = &trapdebug[TRAPSIZE - 1];
+               else
+                       trp--;
+               if (trp->cause == 0)
+                       break;
+               printf("%s: ADR %x PC %x CR %x SR %x\n",
+                       trap_type[(trp->cause & MACH_CR_EXC_CODE) >>
+                               MACH_CR_EXC_CODE_SHIFT],
+                       trp->vadr, trp->pc, trp->cause, trp->status);
+               printf("   RA %x code %d\n", trp-> ra, trp->code);
+       }
+       bzero(trapdebug, sizeof(trapdebug));
+       trp = trapdebug;
+       splx(s);
+}
+#endif
+
+#ifdef X_KLUGE
+/*
+ * This is a kludge to allow X windows to work.
+ */
+caddr_t
+vmUserMap(size, pa)
+       int size;
+       unsigned pa;
+{
+       register caddr_t v;
+       unsigned off, entry;
+
+       if (nUserMapPtes == 0)
+               UserMapPid = curproc->p_pid;
+       else if (UserMapPid != curproc->p_pid)
+               return ((caddr_t)0);
+       off = pa & PGOFSET;
+       size = btoc(off + size);
+       if (nUserMapPtes + size > NPTES)
+               return ((caddr_t)0);
+       v = (caddr_t)(USER_MAP_ADDR + pmax_ptob(nUserMapPtes) + off);
+       entry = (pa & 0x9ffff000) | PG_V | PG_M;
+       if (pa >= MACH_UNCACHED_MEMORY_ADDR)
+               entry |= PG_N;
+       while (size > 0) {
+               UserMapPtes[nUserMapPtes].pt_entry = entry;
+               entry += NBPG;
+               nUserMapPtes++;
+               size--;
+       }
+       return (v);
+}
+
+vmUserUnmap()
+{
+       int id;
+
+       nUserMapPtes = 0;
+       if (UserMapPid == curproc->p_pid) {
+               id = curproc->p_vmspace->vm_pmap.pm_tlbpid;
+               if (id >= 0)
+                       MachTLBFlushPID(id);
+       }
+       UserMapPid = 0;
+}
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * MemErrorInterrupt --
+ *
+ *     Handler an interrupt for the control register.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+MemErrorInterrupt()
+{
+       volatile u_short *sysCSRPtr = (u_short *)MACH_SYS_CSR_ADDR;
+       u_short csr;
+
+       csr = *sysCSRPtr;
+
+       if (csr & MACH_CSR_MEM_ERR) {
+               printf("Memory error at 0x%x\n",
+                       *(unsigned *)MACH_WRITE_ERROR_ADDR);
+               panic("Mem error interrupt");
+       }
+       *sysCSRPtr = (csr & ~MACH_CSR_MBZ) | 0xff;
+}
+
+/* machDis.c -
+ *
+ *             This contains the routine which disassembles an instruction to find
+ *     the target.
+ *
+ *     Copyright (C) 1989 Digital Equipment Corporation.
+ *     Permission to use, copy, modify, and distribute this software and
+ *     its documentation for any purpose and without fee is hereby granted,
+ *     provided that the above copyright notice appears in all copies.  
+ *     Digital Equipment Corporation makes no representations about the
+ *     suitability of this software for any purpose.  It is provided "as is"
+ *     without express or implied warranty.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: /sprite/src/kernel/mach/ds3100.md/RCS/machDis.c,v 1.1 89/07/11 17:55:43 nelson Exp $ SPRITE (Berkeley)";
+#endif not lint
+
+/*
+ * Define the instruction formats.
+ */
+typedef union {
+       unsigned word;
+
+       struct {
+               unsigned imm: 16;
+               unsigned f2: 5;
+               unsigned f1: 5;
+               unsigned op: 6;
+       } IType;
+
+       struct {
+               unsigned target: 26;
+               unsigned op: 6;
+       } JType;
+
+       struct {
+               unsigned funct: 6;
+               unsigned f4: 5;
+               unsigned f3: 5;
+               unsigned f2: 5;
+               unsigned f1: 5;
+               unsigned op: 6;
+       } RType;
+
+       struct {
+               unsigned funct: 6;
+               unsigned fd: 5;
+               unsigned fs: 5;
+               unsigned ft: 5;
+               unsigned fmt: 4;
+               unsigned : 1;           /* always '1' */
+               unsigned op: 6;         /* always '0x11' */
+       } FRType;
+} InstFmt;
+
+/*
+ * Opcodes of the branch instructions.
+ */
+#define OP_SPECIAL     0x00
+#define OP_BCOND       0x01
+#define OP_J           0x02
+#define        OP_JAL          0x03
+#define OP_BEQ         0x04
+#define OP_BNE         0x05
+#define OP_BLEZ                0x06
+#define OP_BGTZ                0x07
+
+/*
+ * Branch subops of the special opcode.
+ */
+#define OP_JR          0x08
+#define OP_JALR                0x09
+
+/*
+ * Sub-ops for OP_BCOND code.
+ */
+#define OP_BLTZ                0x00
+#define OP_BGEZ                0x01
+#define OP_BLTZAL      0x10
+#define OP_BGEZAL      0x11
+
+/*
+ * Coprocessor branch masks.
+ */
+#define COPz_BC_MASK   0x1a
+#define COPz_BC                0x08
+#define COPz_BC_TF_MASK        0x01
+#define COPz_BC_TRUE   0x01
+#define COPz_BC_FALSE  0x00
+
+/*
+ * Coprocessor 1 operation.
+ */
+#define OP_COP_1       0x11
+
+/*
+ * Return the resulting PC as if the branch was executed.
+ */
+unsigned
+MachEmulateBranch(regsPtr, instPC, fpcCSR, allowNonBranch)
+       unsigned *regsPtr;
+       unsigned instPC;
+       unsigned fpcCSR;
+       int allowNonBranch;
+{
+       InstFmt *instPtr;
+       unsigned retAddr;
+       int condition;
+       extern unsigned GetBranchDest();
+
+#ifdef notdef
+       printf("regsPtr=%x PC=%x Inst=%x fpcCsr=%x\n", regsPtr, instPC,
+               *instPC, fpcCSR);
+#endif
+
+       instPtr = (InstFmt *)instPC;
+       switch ((int)instPtr->JType.op) {
+       case OP_SPECIAL:
+               switch ((int)instPtr->RType.funct) {
+               case OP_JR:
+               case OP_JALR:
+                       retAddr = regsPtr[instPtr->RType.f1];
+                       break;
+
+               default:
+                       if (!allowNonBranch)
+                               panic("MachEmulateBranch: Non-branch");
+                       retAddr = instPC + 4;
+                       break;
+               }
+               break;
+
+       case OP_BCOND:
+               switch ((int)instPtr->IType.f2) {
+               case OP_BLTZ:
+               case OP_BLTZAL:
+                       if ((int)(regsPtr[instPtr->RType.f1]) < 0)
+                               retAddr = GetBranchDest(instPtr);
+                       else
+                               retAddr = instPC + 8;
+                       break;
+
+               case OP_BGEZAL:
+               case OP_BGEZ:
+                       if ((int)(regsPtr[instPtr->RType.f1]) >= 0)
+                               retAddr = GetBranchDest(instPtr);
+                       else
+                               retAddr = instPC + 8;
+                       break;
+
+               default:
+                       panic("MachEmulateBranch: Bad branch cond");
+               }
+               break;
+
+       case OP_J:
+       case OP_JAL:
+               retAddr = (instPtr->JType.target << 2) | 
+                       ((unsigned)instPC & 0xF0000000);
+               break;
+
+       case OP_BEQ:
+               if (regsPtr[instPtr->RType.f1] == regsPtr[instPtr->RType.f2])
+                       retAddr = GetBranchDest(instPtr);
+               else
+                       retAddr = instPC + 8;
+               break;
+
+       case OP_BNE:
+               if (regsPtr[instPtr->RType.f1] != regsPtr[instPtr->RType.f2])
+                       retAddr = GetBranchDest(instPtr);
+               else
+                       retAddr = instPC + 8;
+               break;
+
+       case OP_BLEZ:
+               if ((int)(regsPtr[instPtr->RType.f1]) <= 0)
+                       retAddr = GetBranchDest(instPtr);
+               else
+                       retAddr = instPC + 8;
+               break;
+
+       case OP_BGTZ:
+               if ((int)(regsPtr[instPtr->RType.f1]) > 0)
+                       retAddr = GetBranchDest(instPtr);
+               else
+                       retAddr = instPC + 8;
+               break;
+
+       case OP_COP_1:
+               if ((instPtr->RType.f1 & COPz_BC_MASK) == COPz_BC) {
+                       if ((instPtr->RType.f2 & COPz_BC_TF_MASK) ==
+                           COPz_BC_TRUE)
+                               condition = fpcCSR & MACH_FPC_COND_BIT;
+                       else
+                               condition = !(fpcCSR & MACH_FPC_COND_BIT);
+                       if (condition)
+                               retAddr = GetBranchDest(instPtr);
+                       else
+                               retAddr = instPC + 8;
+               } else if (allowNonBranch)
+                       retAddr = instPC + 4;
+               else
+                       panic("MachEmulateBranch: Bad coproc branch instruction");
+               break;
+
+       default:
+               if (!allowNonBranch)
+                       panic("MachEmulateBranch: Non-branch instruction");
+               retAddr = instPC + 4;
+       }
+#ifdef notdef
+       printf("Target addr=%x\n", retAddr);
+#endif
+       return (retAddr);
+}
+
+unsigned
+GetBranchDest(InstPtr)
+       InstFmt *InstPtr;
+{
+       return ((unsigned)InstPtr + 4 + ((short)InstPtr->IType.imm << 2));
+}
diff --git a/usr/src/sys/pmax/pmax/vm_machdep.c b/usr/src/sys/pmax/pmax/vm_machdep.c
new file mode 100644 (file)
index 0000000..8d48825
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and Ralph Campbell.
+ *
+ * %sccs.include.redist.c%
+ *
+ * from: Utah $Hdr: vm_machdep.c 1.21 91/04/06$
+ *
+ *     @(#)vm_machdep.c        7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "malloc.h"
+#include "buf.h"
+#include "user.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+#include "pte.h"
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the kernel stack and pcb, making the child
+ * ready to run, and marking it so that it can return differently
+ * than the parent.  Returns 1 in the child process, 0 in the parent.
+ * We currently double-map the user area so that the stack is at the same
+ * address in each process; in the future we will probably relocate
+ * the frame pointers on the stack after copying.
+ */
+cpu_fork(p1, p2)
+       register struct proc *p1, *p2;
+{
+       register struct user *up = p2->p_addr;
+       register pt_entry_t *pte;
+       register int i;
+
+       p2->p_regs = up->u_pcb.pcb_regs;
+       p2->p_md.md_flags = p1->p_md.md_flags & (MDP_FPUSED | MDP_ULTRIX);
+
+       /*
+        * Convert the user struct virtual address to a physical one
+        * and cache it in the proc struct. Note: if the phyical address
+        * can change (due to memory compaction in kmem_alloc?),
+        * we will have to update things.
+        */
+       pte = kvtopte(up);
+       for (i = 0; i < UPAGES; i++) {
+               p2->p_md.md_upte[i] = pte->pt_entry & ~PG_G;
+               pte++;
+       }
+
+       /*
+        * Copy pcb and stack from proc p1 to p2. 
+        * We do this as cheaply as possible, copying only the active
+        * part of the stack.  The stack and pcb need to agree;
+        */
+       p2->p_addr->u_pcb = p1->p_addr->u_pcb;
+
+       /*
+        * Arrange for a non-local goto when the new process
+        * is started, to resume here, returning nonzero from setjmp.
+        */
+#ifdef DIAGNOSTIC
+       if (p1 != curproc)
+               panic("cpu_fork: curproc");
+#endif
+       if (copykstack(up)) {
+               /*
+                * Return 1 in child.
+                */
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * cpu_exit is called as the last action during exit.
+ * We release the address space and machine-dependent resources,
+ * including the memory for the user structure and kernel stack.
+ * Once finished, we call swtch_exit, which switches to a temporary
+ * pcb and stack and never returns.  We block memory allocation
+ * until swtch_exit has made things safe again.
+ */
+cpu_exit(p)
+       struct proc *p;
+{
+       extern struct proc *machFPCurProcPtr;
+
+       if (machFPCurProcPtr == p)
+               machFPCurProcPtr = (struct proc *)0;
+
+       vmspace_free(p->p_vmspace);
+
+       (void) splhigh();
+       kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+       swtch_exit();
+       /* NOTREACHED */
+}
+
+/*
+ * Move pages from one kernel virtual address to another.
+ * Both addresses are assumed to reside in the Sysmap,
+ * and size must be a multiple of CLSIZE.
+ */
+pagemove(from, to, size)
+       register caddr_t from, to;
+       int size;
+{
+       register pt_entry_t *fpte, *tpte;
+
+       if (size % CLBYTES)
+               panic("pagemove");
+       fpte = kvtopte(from);
+       tpte = kvtopte(to);
+       while (size > 0) {
+               MachTLBFlushAddr(from);
+               MachTLBUpdate(to, *fpte);
+               *tpte++ = *fpte;
+               fpte->pt_entry = 0;
+               fpte++;
+               size -= NBPG;
+               from += NBPG;
+               to += NBPG;
+       }
+}
+
+extern vm_map_t phys_map;
+
+/*
+ * Map an IO request into kernel virtual address space.  Requests fall into
+ * one of five catagories:
+ *
+ *     B_PHYS|B_UAREA: User u-area swap.
+ *                     Address is relative to start of u-area (p_addr).
+ *     B_PHYS|B_PAGET: User page table swap.
+ *                     Address is a kernel VA in usrpt (Usrptmap).
+ *     B_PHYS|B_DIRTY: Dirty page push.
+ *                     Address is a VA in proc2's address space.
+ *     B_PHYS|B_PGIN:  Kernel pagein of user pages.
+ *                     Address is VA in user's address space.
+ *     B_PHYS:         User "raw" IO request.
+ *                     Address is VA in user's address space.
+ *
+ * All requests are (re)mapped into kernel VA space via the phys_map
+ */
+vmapbuf(bp)
+       register struct buf *bp;
+{
+       register caddr_t addr;
+       register vm_size_t sz;
+       struct proc *p;
+       int off;
+       vm_offset_t kva;
+       register vm_offset_t pa;
+
+       if ((bp->b_flags & B_PHYS) == 0)
+               panic("vmapbuf");
+       addr = bp->b_saveaddr = bp->b_un.b_addr;
+       off = (int)addr & PGOFSET;
+       p = bp->b_proc;
+       sz = round_page(bp->b_bcount + off);
+       kva = kmem_alloc_wait(phys_map, sz);
+       bp->b_un.b_addr = (caddr_t) (kva + off);
+       sz = atop(sz);
+       while (sz--) {
+               pa = pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map),
+                       (vm_offset_t)addr);
+               if (pa == 0)
+                       panic("vmapbuf: null page frame");
+               pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa),
+                       VM_PROT_READ|VM_PROT_WRITE, TRUE);
+               addr += PAGE_SIZE;
+               kva += PAGE_SIZE;
+       }
+}
+
+/*
+ * Free the io map PTEs associated with this IO operation.
+ * We also invalidate the TLB entries and restore the original b_addr.
+ */
+vunmapbuf(bp)
+       register struct buf *bp;
+{
+       register caddr_t addr = bp->b_un.b_addr;
+       register vm_size_t sz;
+       vm_offset_t kva;
+
+       if ((bp->b_flags & B_PHYS) == 0)
+               panic("vunmapbuf");
+       sz = round_page(bp->b_bcount + ((int)addr & PGOFSET));
+       kva = (vm_offset_t)((int)addr & ~PGOFSET);
+       kmem_free_wakeup(phys_map, kva, sz);
+       bp->b_un.b_addr = bp->b_saveaddr;
+       bp->b_saveaddr = NULL;
+}