summaryrefslogtreecommitdiff
path: root/libkern
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libkern
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libkern')
-rw-r--r--libkern/NOTICE29
-rw-r--r--libkern/abort.c7
-rw-r--r--libkern/abs.c17
-rw-r--r--libkern/atol.c47
-rw-r--r--libkern/charstod.c68
-rw-r--r--libkern/cistrcmp.c25
-rw-r--r--libkern/cistrncmp.c27
-rw-r--r--libkern/cistrstr.c22
-rw-r--r--libkern/cleanname.c51
-rw-r--r--libkern/convD2M.c94
-rw-r--r--libkern/convM2D.c93
-rw-r--r--libkern/convM2S.c314
-rw-r--r--libkern/convS2M.c385
-rw-r--r--libkern/div-arm.s119
-rw-r--r--libkern/dofmt.c532
-rw-r--r--libkern/exp.c39
-rw-r--r--libkern/fcallfmt.c240
-rw-r--r--libkern/floor.c26
-rw-r--r--libkern/fmt.c188
-rw-r--r--libkern/fmtdef.h85
-rw-r--r--libkern/fmtprint.c44
-rw-r--r--libkern/fmtquote.c259
-rw-r--r--libkern/fmtstr.c23
-rw-r--r--libkern/fmtvprint.c43
-rw-r--r--libkern/frexp-386.c79
-rw-r--r--libkern/frexp-68000.c80
-rw-r--r--libkern/frexp-arm.c79
-rw-r--r--libkern/frexp-mips.c80
-rw-r--r--libkern/frexp-power.c79
-rw-r--r--libkern/frexp-sparc.c79
-rw-r--r--libkern/frexp-thumb.c79
-rw-r--r--libkern/getfcr-386.s27
-rw-r--r--libkern/getfcr-68000.s19
-rw-r--r--libkern/getfcr-arm.s12
-rw-r--r--libkern/getfcr-mips.s15
-rw-r--r--libkern/getfcr-power.s28
-rw-r--r--libkern/getfcr-sparc.s27
-rw-r--r--libkern/getfcr-thumb.s12
-rw-r--r--libkern/getfields.c35
-rw-r--r--libkern/log.c57
-rw-r--r--libkern/memccpy-power.s23
-rw-r--r--libkern/memccpy.c17
-rw-r--r--libkern/memchr.c16
-rw-r--r--libkern/memcmp-power.s110
-rw-r--r--libkern/memcmp.c22
-rw-r--r--libkern/memcpy-386.s58
-rw-r--r--libkern/memcpy-arm.c35
-rw-r--r--libkern/memcpy-thumb.c35
-rw-r--r--libkern/memmove-386.s58
-rw-r--r--libkern/memmove-68000.s124
-rw-r--r--libkern/memmove-arm.s223
-rw-r--r--libkern/memmove-mips.s237
-rw-r--r--libkern/memmove-power.s170
-rw-r--r--libkern/memmove-sparc.s162
-rw-r--r--libkern/memmove-thumb.s223
-rw-r--r--libkern/memmove.c43
-rw-r--r--libkern/memset-386.s35
-rw-r--r--libkern/memset-68000.s57
-rw-r--r--libkern/memset-arm.s66
-rw-r--r--libkern/memset-mips.s88
-rw-r--r--libkern/memset-power.s73
-rw-r--r--libkern/memset-sparc.s88
-rw-r--r--libkern/memset-thumb.s66
-rw-r--r--libkern/memset.c15
-rw-r--r--libkern/mkfile81
-rw-r--r--libkern/mkfile-38612
-rw-r--r--libkern/mkfile-6800012
-rw-r--r--libkern/mkfile-arm13
-rw-r--r--libkern/mkfile-mips13
-rw-r--r--libkern/mkfile-power13
-rw-r--r--libkern/mkfile-sparc13
-rw-r--r--libkern/mkfile-spim8
-rw-r--r--libkern/mkfile-thumb12
-rw-r--r--libkern/muldiv-68000.s172
-rw-r--r--libkern/nan-386.c69
-rw-r--r--libkern/nan-68000.c70
-rw-r--r--libkern/nan-arm.c69
-rw-r--r--libkern/nan-mips.c70
-rw-r--r--libkern/nan-power.c69
-rw-r--r--libkern/nan-sparc.c69
-rw-r--r--libkern/nan-thumb.c69
-rw-r--r--libkern/netmkaddr.c50
-rw-r--r--libkern/pow.c68
-rw-r--r--libkern/pow10.c40
-rw-r--r--libkern/qsort.c122
-rw-r--r--libkern/rune.c162
-rw-r--r--libkern/runestrlen.c13
-rw-r--r--libkern/seprint.c26
-rw-r--r--libkern/sin.c67
-rw-r--r--libkern/smprint.c26
-rw-r--r--libkern/snprint.c27
-rw-r--r--libkern/sqrt.c53
-rw-r--r--libkern/strcat.c9
-rw-r--r--libkern/strchr-386.s29
-rw-r--r--libkern/strchr-68000.s27
-rw-r--r--libkern/strchr-arm.s52
-rw-r--r--libkern/strchr-mips.c0
-rw-r--r--libkern/strchr-mips.s63
-rw-r--r--libkern/strchr-power.s16
-rw-r--r--libkern/strchr-sparc.s73
-rw-r--r--libkern/strchr-thumb.s52
-rw-r--r--libkern/strchr.c18
-rw-r--r--libkern/strcmp-power.s21
-rw-r--r--libkern/strcmp.c19
-rw-r--r--libkern/strcpy.c15
-rw-r--r--libkern/strdup.c12
-rw-r--r--libkern/strecpy.c16
-rw-r--r--libkern/strlen.c8
-rw-r--r--libkern/strncmp-power.s29
-rw-r--r--libkern/strncmp.c21
-rw-r--r--libkern/strncpy.c17
-rw-r--r--libkern/strrchr.c14
-rw-r--r--libkern/strstr.c21
-rw-r--r--libkern/strtod.c31
-rw-r--r--libkern/strtol.c94
-rw-r--r--libkern/strtoll.c81
-rw-r--r--libkern/strtoul.c96
-rw-r--r--libkern/tokenize.c58
-rw-r--r--libkern/toupper.c16
-rw-r--r--libkern/u16.c52
-rw-r--r--libkern/u32.c109
-rw-r--r--libkern/u64.c126
-rw-r--r--libkern/utfecpy.c20
-rw-r--r--libkern/utflen.c22
-rw-r--r--libkern/utfnlen.c25
-rw-r--r--libkern/utfrrune.c30
-rw-r--r--libkern/utfrune.c29
-rw-r--r--libkern/vlop-386.s44
-rw-r--r--libkern/vlop-arm.s34
-rw-r--r--libkern/vlop-mips.s17
-rw-r--r--libkern/vlop-power.s14
-rw-r--r--libkern/vlop-sparc.s112
-rw-r--r--libkern/vlop-thumb.s34
-rw-r--r--libkern/vlrt-386.c695
-rw-r--r--libkern/vlrt-68000.c771
-rw-r--r--libkern/vlrt-arm.c718
-rw-r--r--libkern/vlrt-mips.c719
-rw-r--r--libkern/vlrt-power.c718
-rw-r--r--libkern/vlrt-sparc.c718
-rw-r--r--libkern/vlrt-thumb.c718
-rw-r--r--libkern/vseprint.c34
-rw-r--r--libkern/vsmprint.c74
-rw-r--r--libkern/vsnprint.c34
143 files changed, 13871 insertions, 0 deletions
diff --git a/libkern/NOTICE b/libkern/NOTICE
new file mode 100644
index 00000000..d2099067
--- /dev/null
+++ b/libkern/NOTICE
@@ -0,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory. If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below. It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+ Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ Revisions Copyright © 2000-2006 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/libkern/abort.c b/libkern/abort.c
new file mode 100644
index 00000000..f71c01c3
--- /dev/null
+++ b/libkern/abort.c
@@ -0,0 +1,7 @@
+#include <lib9.h>
+void
+abort(void)
+{
+ while(*(int*)0)
+ ;
+}
diff --git a/libkern/abs.c b/libkern/abs.c
new file mode 100644
index 00000000..6bb51107
--- /dev/null
+++ b/libkern/abs.c
@@ -0,0 +1,17 @@
+#include <lib9.h>
+
+int
+abs(int a)
+{
+ if(a < 0)
+ return -a;
+ return a;
+}
+
+long
+labs(long a)
+{
+ if(a < 0)
+ return -a;
+ return a;
+}
diff --git a/libkern/atol.c b/libkern/atol.c
new file mode 100644
index 00000000..18a34b77
--- /dev/null
+++ b/libkern/atol.c
@@ -0,0 +1,47 @@
+#include <lib9.h>
+
+long
+atol(char *s)
+{
+ long n;
+ int f;
+
+ n = 0;
+ f = 0;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ if(*s == '-' || *s == '+') {
+ if(*s++ == '-')
+ f = 1;
+ while(*s == ' ' || *s == '\t')
+ s++;
+ }
+ if(s[0]=='0' && s[1]){
+ if(s[1]=='x' || s[1]=='X'){
+ s += 2;
+ for(;;){
+ if(*s >= '0' && *s <= '9')
+ n = n*16 + *s++ - '0';
+ else if(*s >= 'a' && *s <= 'f')
+ n = n*16 + *s++ - 'a' + 10;
+ else if(*s >= 'A' && *s <= 'F')
+ n = n*16 + *s++ - 'A' + 10;
+ else
+ break;
+ }
+ } else
+ while(*s >= '0' && *s <= '7')
+ n = n*8 + *s++ - '0';
+ } else
+ while(*s >= '0' && *s <= '9')
+ n = n*10 + *s++ - '0';
+ if(f)
+ n = -n;
+ return n;
+}
+
+atoi(char *s)
+{
+
+ return atol(s);
+}
diff --git a/libkern/charstod.c b/libkern/charstod.c
new file mode 100644
index 00000000..203e5379
--- /dev/null
+++ b/libkern/charstod.c
@@ -0,0 +1,68 @@
+#include <lib9.h>
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp). The last call it makes to f terminates the
+ * scan, so is not a character in the number. It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+double
+charstod(int(*f)(void*), void *vp)
+{
+ double num, dem;
+ int neg, eneg, dig, exp, c;
+
+ num = 0;
+ neg = 0;
+ dig = 0;
+ exp = 0;
+ eneg = 0;
+
+ c = (*f)(vp);
+ while(c == ' ' || c == '\t')
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ if(c == '-')
+ neg = 1;
+ c = (*f)(vp);
+ }
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ c = (*f)(vp);
+ }
+ if(c == '.')
+ c = (*f)(vp);
+ while(c >= '0' && c <= '9'){
+ num = num*10 + c-'0';
+ dig++;
+ c = (*f)(vp);
+ }
+ if(c == 'e' || c == 'E'){
+ c = (*f)(vp);
+ if(c == '-' || c == '+'){
+ if(c == '-'){
+ dig = -dig;
+ eneg = 1;
+ }
+ c = (*f)(vp);
+ }
+ while(c >= '0' && c <= '9'){
+ exp = exp*10 + c-'0';
+ c = (*f)(vp);
+ }
+ }
+ exp -= dig;
+ if(exp < 0){
+ exp = -exp;
+ eneg = !eneg;
+ }
+ dem = pow10(exp);
+ if(eneg)
+ num /= dem;
+ else
+ num *= dem;
+ if(neg)
+ return -num;
+ return num;
+}
diff --git a/libkern/cistrcmp.c b/libkern/cistrcmp.c
new file mode 100644
index 00000000..fc7d84e4
--- /dev/null
+++ b/libkern/cistrcmp.c
@@ -0,0 +1,25 @@
+#include "lib9.h"
+
+int
+cistrcmp(char *s1, char *s2)
+{
+ int c1, c2;
+
+ while(*s1){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ return -*s2;
+}
diff --git a/libkern/cistrncmp.c b/libkern/cistrncmp.c
new file mode 100644
index 00000000..1d55d71b
--- /dev/null
+++ b/libkern/cistrncmp.c
@@ -0,0 +1,27 @@
+#include "lib9.h"
+
+int
+cistrncmp(char *s1, char *s2, int n)
+{
+ int c1, c2;
+
+ while(*s1 && n-- > 0){
+ c1 = *(uchar*)s1++;
+ c2 = *(uchar*)s2++;
+
+ if(c1 == c2)
+ continue;
+
+ if(c1 >= 'A' && c1 <= 'Z')
+ c1 -= 'A' - 'a';
+
+ if(c2 >= 'A' && c2 <= 'Z')
+ c2 -= 'A' - 'a';
+
+ if(c1 != c2)
+ return c1 - c2;
+ }
+ if(n <= 0)
+ return 0;
+ return -*s2;
+}
diff --git a/libkern/cistrstr.c b/libkern/cistrstr.c
new file mode 100644
index 00000000..20d3205d
--- /dev/null
+++ b/libkern/cistrstr.c
@@ -0,0 +1,22 @@
+#include "lib9.h"
+
+char*
+cistrstr(char *s, char *sub)
+{
+ int c, csub, n;
+
+ csub = *sub;
+ if(csub == '\0')
+ return s;
+ if(csub >= 'A' && csub <= 'Z')
+ csub -= 'A' - 'a';
+ sub++;
+ n = strlen(sub);
+ for(; c = *s; s++){
+ if(c >= 'A' && c <= 'Z')
+ c -= 'A' - 'a';
+ if(c == csub && cistrncmp(s+1, sub, n) == 0)
+ return s;
+ }
+ return nil;
+}
diff --git a/libkern/cleanname.c b/libkern/cleanname.c
new file mode 100644
index 00000000..fb8f370a
--- /dev/null
+++ b/libkern/cleanname.c
@@ -0,0 +1,51 @@
+#include "lib9.h"
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x) ((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+ char *p, *q, *dotdot;
+ int rooted;
+
+ rooted = name[0] == '/';
+
+ /*
+ * invariants:
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ * dotdot points just past the point where .. cannot backtrack
+ * any further (no slash).
+ */
+ p = q = dotdot = name+rooted;
+ while(*p) {
+ if(p[0] == '/') /* null element */
+ p++;
+ else if(p[0] == '.' && SEP(p[1]))
+ p += 1; /* don't count the separator in case it is nul */
+ else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+ p += 2;
+ if(q > dotdot) { /* can backtrack */
+ while(--q > dotdot && *q != '/')
+ ;
+ } else if(!rooted) { /* /.. is / but ./../ is .. */
+ if(q != name)
+ *q++ = '/';
+ *q++ = '.';
+ *q++ = '.';
+ dotdot = q;
+ }
+ } else { /* real path element */
+ if(q != name+rooted)
+ *q++ = '/';
+ while((*q = *p) != '/' && *q != 0)
+ p++, q++;
+ }
+ }
+ if(q == name) /* empty string is really ``.'' */
+ *q++ = '.';
+ *q = '\0';
+ return name;
+}
diff --git a/libkern/convD2M.c b/libkern/convD2M.c
new file mode 100644
index 00000000..29f0cd55
--- /dev/null
+++ b/libkern/convD2M.c
@@ -0,0 +1,94 @@
+#include "lib9.h"
+#include "fcall.h"
+
+uint
+sizeD2M(Dir *d)
+{
+ char *sv[4];
+ int i, ns;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++)
+ if(sv[i])
+ ns += strlen(sv[i]);
+
+ return STATFIXLEN + ns;
+}
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns, nsv[4], ss;
+
+ if(nbuf < BIT16SZ)
+ return 0;
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ sv[0] = d->name;
+ sv[1] = d->uid;
+ sv[2] = d->gid;
+ sv[3] = d->muid;
+
+ ns = 0;
+ for(i = 0; i < 4; i++){
+ if(sv[i])
+ nsv[i] = strlen(sv[i]);
+ else
+ nsv[i] = 0;
+ ns += nsv[i];
+ }
+
+ ss = STATFIXLEN + ns;
+
+ /* set size befor erroring, so user can know how much is needed */
+ /* note that length excludes count field itself */
+ PBIT16(p, ss-BIT16SZ);
+ p += BIT16SZ;
+
+ if(ss > nbuf)
+ return BIT16SZ;
+
+ PBIT16(p, d->type);
+ p += BIT16SZ;
+ PBIT32(p, d->dev);
+ p += BIT32SZ;
+ PBIT8(p, d->qid.type);
+ p += BIT8SZ;
+ PBIT32(p, d->qid.vers);
+ p += BIT32SZ;
+ PBIT64(p, d->qid.path);
+ p += BIT64SZ;
+ PBIT32(p, d->mode);
+ p += BIT32SZ;
+ PBIT32(p, d->atime);
+ p += BIT32SZ;
+ PBIT32(p, d->mtime);
+ p += BIT32SZ;
+ PBIT64(p, d->length);
+ p += BIT64SZ;
+
+ for(i = 0; i < 4; i++){
+ ns = nsv[i];
+ if(p + ns + BIT16SZ > ebuf)
+ return 0;
+ PBIT16(p, ns);
+ p += BIT16SZ;
+ if(ns)
+ memmove(p, sv[i], ns);
+ p += ns;
+ }
+
+ if(ss != p - buf)
+ return 0;
+
+ return p - buf;
+}
diff --git a/libkern/convM2D.c b/libkern/convM2D.c
new file mode 100644
index 00000000..156bd763
--- /dev/null
+++ b/libkern/convM2D.c
@@ -0,0 +1,93 @@
+#include "lib9.h"
+#include "fcall.h"
+
+int
+statcheck(uchar *buf, uint nbuf)
+{
+ uchar *ebuf;
+ int i;
+
+ ebuf = buf + nbuf;
+
+ if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
+ return -1;
+
+ buf += STATFIXLEN - 4 * BIT16SZ;
+
+ for(i = 0; i < 4; i++){
+ if(buf + BIT16SZ > ebuf)
+ return -1;
+ buf += BIT16SZ + GBIT16(buf);
+ }
+
+ if(buf != ebuf)
+ return -1;
+
+ return 0;
+}
+
+static char nullstring[] = "";
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+ uchar *p, *ebuf;
+ char *sv[4];
+ int i, ns;
+
+ if(nbuf < STATFIXLEN)
+ return 0;
+
+ p = buf;
+ ebuf = buf + nbuf;
+
+ p += BIT16SZ; /* ignore size */
+ d->type = GBIT16(p);
+ p += BIT16SZ;
+ d->dev = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.type = GBIT8(p);
+ p += BIT8SZ;
+ d->qid.vers = GBIT32(p);
+ p += BIT32SZ;
+ d->qid.path = GBIT64(p);
+ p += BIT64SZ;
+ d->mode = GBIT32(p);
+ p += BIT32SZ;
+ d->atime = GBIT32(p);
+ p += BIT32SZ;
+ d->mtime = GBIT32(p);
+ p += BIT32SZ;
+ d->length = GBIT64(p);
+ p += BIT64SZ;
+
+ for(i = 0; i < 4; i++){
+ if(p + BIT16SZ > ebuf)
+ return 0;
+ ns = GBIT16(p);
+ p += BIT16SZ;
+ if(p + ns > ebuf)
+ return 0;
+ if(strs){
+ sv[i] = strs;
+ memmove(strs, p, ns);
+ strs += ns;
+ *strs++ = '\0';
+ }
+ p += ns;
+ }
+
+ if(strs){
+ d->name = sv[0];
+ d->uid = sv[1];
+ d->gid = sv[2];
+ d->muid = sv[3];
+ }else{
+ d->name = nullstring;
+ d->uid = nullstring;
+ d->gid = nullstring;
+ d->muid = nullstring;
+ }
+
+ return p - buf;
+}
diff --git a/libkern/convM2S.c b/libkern/convM2S.c
new file mode 100644
index 00000000..443d1957
--- /dev/null
+++ b/libkern/convM2S.c
@@ -0,0 +1,314 @@
+#include "lib9.h"
+#include "fcall.h"
+
+static
+uchar*
+gstring(uchar *p, uchar *ep, char **s)
+{
+ uint n;
+
+ if(p+BIT16SZ > ep)
+ return nil;
+ n = GBIT16(p);
+ p += BIT16SZ - 1;
+ if(p+n+1 > ep)
+ return nil;
+ /* move it down, on top of count, to make room for '\0' */
+ memmove(p, p + 1, n);
+ p[n] = '\0';
+ *s = (char*)p;
+ p += n+1;
+ return p;
+}
+
+static
+uchar*
+gqid(uchar *p, uchar *ep, Qid *q)
+{
+ if(p+QIDSZ > ep)
+ return nil;
+ q->type = GBIT8(p);
+ p += BIT8SZ;
+ q->vers = GBIT32(p);
+ p += BIT32SZ;
+ q->path = GBIT64(p);
+ p += BIT64SZ;
+ return p;
+}
+
+/*
+ * no syntactic checks.
+ * three causes for error:
+ * 1. message size field is incorrect
+ * 2. input buffer too short for its own data (counts too long, etc.)
+ * 3. too many names or qids
+ * gqid() and gstring() return nil if they would reach beyond buffer.
+ * main switch statement checks range and also can fall through
+ * to test at end of routine.
+ */
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+ uchar *p, *ep;
+ uint i, size;
+
+ p = ap;
+ ep = p + nap;
+
+ if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
+ return 0;
+ size = GBIT32(p);
+ p += BIT32SZ;
+
+ if(size < BIT32SZ+BIT8SZ+BIT16SZ)
+ return 0;
+
+ f->type = GBIT8(p);
+ p += BIT8SZ;
+ f->tag = GBIT16(p);
+ p += BIT16SZ;
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->msize = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->version);
+ break;
+
+ case Tflush:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->oldtag = GBIT16(p);
+ p += BIT16SZ;
+ break;
+
+ case Tauth:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->afid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->uname);
+ if(p == nil)
+ break;
+ p = gstring(p, ep, &f->aname);
+ if(p == nil)
+ break;
+ break;
+
+ case Tattach:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->afid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->uname);
+ if(p == nil)
+ break;
+ p = gstring(p, ep, &f->aname);
+ if(p == nil)
+ break;
+ break;
+
+ case Twalk:
+ if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->newfid = GBIT32(p);
+ p += BIT32SZ;
+ f->nwname = GBIT16(p);
+ p += BIT16SZ;
+ if(f->nwname > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwname; i++){
+ p = gstring(p, ep, &f->wname[i]);
+ if(p == nil)
+ break;
+ }
+ break;
+
+ case Topen:
+ if(p+BIT32SZ+BIT8SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->mode = GBIT8(p);
+ p += BIT8SZ;
+ break;
+
+ case Tcreate:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->name);
+ if(p == nil)
+ break;
+ if(p+BIT32SZ+BIT8SZ > ep)
+ return 0;
+ f->perm = GBIT32(p);
+ p += BIT32SZ;
+ f->mode = GBIT8(p);
+ p += BIT8SZ;
+ break;
+
+ case Tread:
+ if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->offset = GBIT64(p);
+ p += BIT64SZ;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Twrite:
+ if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->offset = GBIT64(p);
+ p += BIT64SZ;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ if(p+f->count > ep)
+ return 0;
+ f->data = (char*)p;
+ p += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Tstat:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Twstat:
+ if(p+BIT32SZ+BIT16SZ > ep)
+ return 0;
+ f->fid = GBIT32(p);
+ p += BIT32SZ;
+ f->nstat = GBIT16(p);
+ p += BIT16SZ;
+ if(p+f->nstat > ep)
+ return 0;
+ f->stat = p;
+ p += f->nstat;
+ break;
+
+/*
+ */
+ case Rversion:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->msize = GBIT32(p);
+ p += BIT32SZ;
+ p = gstring(p, ep, &f->version);
+ break;
+
+ case Rerror:
+ p = gstring(p, ep, &f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ p = gqid(p, ep, &f->aqid);
+ if(p == nil)
+ break;
+ break;
+
+ case Rattach:
+ p = gqid(p, ep, &f->qid);
+ if(p == nil)
+ break;
+ break;
+
+ case Rwalk:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->nwqid = GBIT16(p);
+ p += BIT16SZ;
+ if(f->nwqid > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwqid; i++){
+ p = gqid(p, ep, &f->wqid[i]);
+ if(p == nil)
+ break;
+ }
+ break;
+
+ case Ropen:
+ case Rcreate:
+ p = gqid(p, ep, &f->qid);
+ if(p == nil)
+ break;
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->iounit = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Rread:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ if(p+f->count > ep)
+ return 0;
+ f->data = (char*)p;
+ p += f->count;
+ break;
+
+ case Rwrite:
+ if(p+BIT32SZ > ep)
+ return 0;
+ f->count = GBIT32(p);
+ p += BIT32SZ;
+ break;
+
+ case Rclunk:
+ case Rremove:
+ break;
+
+ case Rstat:
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->nstat = GBIT16(p);
+ p += BIT16SZ;
+ if(p+f->nstat > ep)
+ return 0;
+ f->stat = p;
+ p += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+
+ if(p==nil || p>ep)
+ return 0;
+ if(ap+size == p)
+ return size;
+ return 0;
+}
diff --git a/libkern/convS2M.c b/libkern/convS2M.c
new file mode 100644
index 00000000..7035373f
--- /dev/null
+++ b/libkern/convS2M.c
@@ -0,0 +1,385 @@
+#include "lib9.h"
+#include "fcall.h"
+
+static
+uchar*
+pstring(uchar *p, char *s)
+{
+ uint n;
+
+ if(s == nil){
+ PBIT16(p, 0);
+ p += BIT16SZ;
+ return p;
+ }
+
+ n = strlen(s);
+ PBIT16(p, n);
+ p += BIT16SZ;
+ memmove(p, s, n);
+ p += n;
+ return p;
+}
+
+static
+uchar*
+pqid(uchar *p, Qid *q)
+{
+ PBIT8(p, q->type);
+ p += BIT8SZ;
+ PBIT32(p, q->vers);
+ p += BIT32SZ;
+ PBIT64(p, q->path);
+ p += BIT64SZ;
+ return p;
+}
+
+static
+uint
+stringsz(char *s)
+{
+ if(s == nil)
+ return BIT16SZ;
+
+ return BIT16SZ+strlen(s);
+}
+
+uint
+sizeS2M(Fcall *f)
+{
+ uint n;
+ int i;
+
+ n = 0;
+ n += BIT32SZ; /* size */
+ n += BIT8SZ; /* type */
+ n += BIT16SZ; /* tag */
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ n += BIT32SZ;
+ n += stringsz(f->version);
+ break;
+
+ case Tflush:
+ n += BIT16SZ;
+ break;
+
+ case Tauth:
+ n += BIT32SZ;
+ n += stringsz(f->uname);
+ n += stringsz(f->aname);
+ break;
+
+ case Tattach:
+ n += BIT32SZ;
+ n += BIT32SZ;
+ n += stringsz(f->uname);
+ n += stringsz(f->aname);
+ break;
+
+ case Twalk:
+ n += BIT32SZ;
+ n += BIT32SZ;
+ n += BIT16SZ;
+ for(i=0; i<f->nwname; i++)
+ n += stringsz(f->wname[i]);
+ break;
+
+ case Topen:
+ n += BIT32SZ;
+ n += BIT8SZ;
+ break;
+
+ case Tcreate:
+ n += BIT32SZ;
+ n += stringsz(f->name);
+ n += BIT32SZ;
+ n += BIT8SZ;
+ break;
+
+ case Tread:
+ n += BIT32SZ;
+ n += BIT64SZ;
+ n += BIT32SZ;
+ break;
+
+ case Twrite:
+ n += BIT32SZ;
+ n += BIT64SZ;
+ n += BIT32SZ;
+ n += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ n += BIT32SZ;
+ break;
+
+ case Tstat:
+ n += BIT32SZ;
+ break;
+
+ case Twstat:
+ n += BIT32SZ;
+ n += BIT16SZ;
+ n += f->nstat;
+ break;
+/*
+ */
+
+ case Rversion:
+ n += BIT32SZ;
+ n += stringsz(f->version);
+ break;
+
+ case Rerror:
+ n += stringsz(f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ n += QIDSZ;
+ break;
+
+ case Rattach:
+ n += QIDSZ;
+ break;
+
+ case Rwalk:
+ n += BIT16SZ;
+ n += f->nwqid*QIDSZ;
+ break;
+
+ case Ropen:
+ case Rcreate:
+ n += QIDSZ;
+ n += BIT32SZ;
+ break;
+
+ case Rread:
+ n += BIT32SZ;
+ n += f->count;
+ break;
+
+ case Rwrite:
+ n += BIT32SZ;
+ break;
+
+ case Rclunk:
+ break;
+
+ case Rremove:
+ break;
+
+ case Rstat:
+ n += BIT16SZ;
+ n += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+ return n;
+}
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+ uchar *p;
+ uint i, size;
+
+ size = sizeS2M(f);
+ if(size == 0)
+ return 0;
+ if(size > nap)
+ return 0;
+
+ p = (uchar*)ap;
+
+ PBIT32(p, size);
+ p += BIT32SZ;
+ PBIT8(p, f->type);
+ p += BIT8SZ;
+ PBIT16(p, f->tag);
+ p += BIT16SZ;
+
+ switch(f->type)
+ {
+ default:
+ return 0;
+
+ case Tversion:
+ PBIT32(p, f->msize);
+ p += BIT32SZ;
+ p = pstring(p, f->version);
+ break;
+
+ case Tflush:
+ PBIT16(p, f->oldtag);
+ p += BIT16SZ;
+ break;
+
+ case Tauth:
+ PBIT32(p, f->afid);
+ p += BIT32SZ;
+ p = pstring(p, f->uname);
+ p = pstring(p, f->aname);
+ break;
+
+ case Tattach:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT32(p, f->afid);
+ p += BIT32SZ;
+ p = pstring(p, f->uname);
+ p = pstring(p, f->aname);
+ break;
+
+ case Twalk:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT32(p, f->newfid);
+ p += BIT32SZ;
+ PBIT16(p, f->nwname);
+ p += BIT16SZ;
+ if(f->nwname > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwname; i++)
+ p = pstring(p, f->wname[i]);
+ break;
+
+ case Topen:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT8(p, f->mode);
+ p += BIT8SZ;
+ break;
+
+ case Tcreate:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ p = pstring(p, f->name);
+ PBIT32(p, f->perm);
+ p += BIT32SZ;
+ PBIT8(p, f->mode);
+ p += BIT8SZ;
+ break;
+
+ case Tread:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT64(p, f->offset);
+ p += BIT64SZ;
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ break;
+
+ case Twrite:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT64(p, f->offset);
+ p += BIT64SZ;
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ memmove(p, f->data, f->count);
+ p += f->count;
+ break;
+
+ case Tclunk:
+ case Tremove:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ break;
+
+ case Tstat:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ break;
+
+ case Twstat:
+ PBIT32(p, f->fid);
+ p += BIT32SZ;
+ PBIT16(p, f->nstat);
+ p += BIT16SZ;
+ memmove(p, f->stat, f->nstat);
+ p += f->nstat;
+ break;
+/*
+ */
+
+ case Rversion:
+ PBIT32(p, f->msize);
+ p += BIT32SZ;
+ p = pstring(p, f->version);
+ break;
+
+ case Rerror:
+ p = pstring(p, f->ename);
+ break;
+
+ case Rflush:
+ break;
+
+ case Rauth:
+ p = pqid(p, &f->aqid);
+ break;
+
+ case Rattach:
+ p = pqid(p, &f->qid);
+ break;
+
+ case Rwalk:
+ PBIT16(p, f->nwqid);
+ p += BIT16SZ;
+ if(f->nwqid > MAXWELEM)
+ return 0;
+ for(i=0; i<f->nwqid; i++)
+ p = pqid(p, &f->wqid[i]);
+ break;
+
+ case Ropen:
+ case Rcreate:
+ p = pqid(p, &f->qid);
+ PBIT32(p, f->iounit);
+ p += BIT32SZ;
+ break;
+
+ case Rread:
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ memmove(p, f->data, f->count);
+ p += f->count;
+ break;
+
+ case Rwrite:
+ PBIT32(p, f->count);
+ p += BIT32SZ;
+ break;
+
+ case Rclunk:
+ break;
+
+ case Rremove:
+ break;
+
+ case Rstat:
+ PBIT16(p, f->nstat);
+ p += BIT16SZ;
+ memmove(p, f->stat, f->nstat);
+ p += f->nstat;
+ break;
+
+ case Rwstat:
+ break;
+ }
+ if(size != p-ap)
+ return 0;
+ return size;
+}
diff --git a/libkern/div-arm.s b/libkern/div-arm.s
new file mode 100644
index 00000000..a08289f9
--- /dev/null
+++ b/libkern/div-arm.s
@@ -0,0 +1,119 @@
+Q = 0
+N = 1
+D = 2
+CC = 3
+TMP = 11
+
+TEXT save<>(SB), 1, $0
+ MOVW R(Q), 0(FP)
+ MOVW R(N), 4(FP)
+ MOVW R(D), 8(FP)
+ MOVW R(CC), 12(FP)
+
+ MOVW R(TMP), R(Q) /* numerator */
+ MOVW 20(FP), R(D) /* denominator */
+ CMP $0, R(D)
+ BNE s1
+ SWI 0
+/* MOVW -1(R(D)), R(TMP) /* divide by zero fault */
+s1: RET
+
+TEXT rest<>(SB), 1, $0
+ MOVW 0(FP), R(Q)
+ MOVW 4(FP), R(N)
+ MOVW 8(FP), R(D)
+ MOVW 12(FP), R(CC)
+/*
+ * return to caller
+ * of rest<>
+ */
+ MOVW 0(R13), R14
+ ADD $20, R13
+ B (R14)
+
+TEXT div<>(SB), 1, $0
+ MOVW $32, R(CC)
+/*
+ * skip zeros 8-at-a-time
+ */
+e1:
+ AND.S $(0xff<<24),R(Q), R(N)
+ BNE e2
+ SLL $8, R(Q)
+ SUB.S $8, R(CC)
+ BNE e1
+ RET
+e2:
+ MOVW $0, R(N)
+
+loop:
+/*
+ * shift R(N||Q) left one
+ */
+ SLL $1, R(N)
+ CMP $0, R(Q)
+ ORR.LT $1, R(N)
+ SLL $1, R(Q)
+
+/*
+ * compare numerator to denominator
+ * if less, subtract and set quotent bit
+ */
+ CMP R(D), R(N)
+ ORR.HS $1, R(Q)
+ SUB.HS R(D), R(N)
+ SUB.S $1, R(CC)
+ BNE loop
+ RET
+
+TEXT _div(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(Q)
+ BGE d1
+ RSB $0, R(Q), R(Q)
+ CMP $0, R(D)
+ BGE d2
+ RSB $0, R(D), R(D)
+d0:
+ BL div<>(SB) /* none/both neg */
+ MOVW R(Q), R(TMP)
+ B out
+d1:
+ CMP $0, R(D)
+ BGE d0
+ RSB $0, R(D), R(D)
+d2:
+ BL div<>(SB) /* one neg */
+ RSB $0, R(Q), R(TMP)
+ B out
+
+TEXT _mod(SB), 1, $16
+ BL save<>(SB)
+ CMP $0, R(D)
+ RSB.LT $0, R(D), R(D)
+ CMP $0, R(Q)
+ BGE m1
+ RSB $0, R(Q), R(Q)
+ BL div<>(SB) /* neg numerator */
+ RSB $0, R(N), R(TMP)
+ B out
+m1:
+ BL div<>(SB) /* pos numerator */
+ MOVW R(N), R(TMP)
+ B out
+
+TEXT _divu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(Q), R(TMP)
+ B out
+
+TEXT _modu(SB), 1, $16
+ BL save<>(SB)
+ BL div<>(SB)
+ MOVW R(N), R(TMP)
+ B out
+
+out:
+ BL rest<>(SB)
+ B out
diff --git a/libkern/dofmt.c b/libkern/dofmt.c
new file mode 100644
index 00000000..0f47c85d
--- /dev/null
+++ b/libkern/dofmt.c
@@ -0,0 +1,532 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted */
+int
+dofmt(Fmt *f, char *fmt)
+{
+ Rune rune, *rt, *rs;
+ int r;
+ char *t, *s;
+ int n, nfmt;
+
+ nfmt = f->nfmt;
+ for(;;){
+ if(f->runes){
+ rt = f->to;
+ rs = f->stop;
+ while((r = *(uchar*)fmt) && r != '%'){
+ if(r < Runeself)
+ fmt++;
+ else{
+ fmt += chartorune(&rune, fmt);
+ r = rune;
+ }
+ FMTRCHAR(f, rt, rs, r);
+ }
+ fmt++;
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = rs;
+ }else{
+ t = f->to;
+ s = f->stop;
+ while((r = *(uchar*)fmt) && r != '%'){
+ if(r < Runeself){
+ FMTCHAR(f, t, s, r);
+ fmt++;
+ }else{
+ n = chartorune(&rune, fmt);
+ if(t + n > s){
+ t = _fmtflush(f, t, n);
+ if(t != nil)
+ s = f->stop;
+ else
+ return -1;
+ }
+ while(n--)
+ *t++ = *fmt++;
+ }
+ }
+ fmt++;
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(!r)
+ return f->nfmt - nfmt;
+ f->stop = s;
+ }
+
+ fmt = _fmtdispatch(f, fmt, 0);
+ if(fmt == nil)
+ return -1;
+ }
+ return 0; /* not reached */
+}
+
+void *
+_fmtflush(Fmt *f, void *t, int len)
+{
+ if(f->runes)
+ f->nfmt += (Rune*)t - (Rune*)f->to;
+ else
+ f->nfmt += (char*)t - (char *)f->to;
+ f->to = t;
+ if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+ f->stop = f->to;
+ return nil;
+ }
+ return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width charactes
+ */
+int
+_fmtpad(Fmt *f, int n)
+{
+ char *t, *s;
+ int i;
+
+ t = f->to;
+ s = f->stop;
+ for(i = 0; i < n; i++)
+ FMTCHAR(f, t, s, ' ');
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ return 0;
+}
+
+int
+_rfmtpad(Fmt *f, int n)
+{
+ Rune *t, *s;
+ int i;
+
+ t = f->to;
+ s = f->stop;
+ for(i = 0; i < n; i++)
+ FMTRCHAR(f, t, s, ' ');
+ f->nfmt += t - (Rune *)f->to;
+ f->to = t;
+ return 0;
+}
+
+int
+_fmtcpy(Fmt *f, void *vm, int n, int sz)
+{
+ Rune *rt, *rs, r;
+ char *t, *s, *m, *me;
+ ulong fl;
+ int nc, w;
+
+ m = vm;
+ me = m + sz;
+ w = f->width;
+ fl = f->flags;
+ if((fl & FmtPrec) && n > f->prec)
+ n = f->prec;
+ if(f->runes){
+ if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
+ return -1;
+ rt = f->to;
+ rs = f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRCHAR(f, rt, rs, r);
+ }
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(m < me)
+ return -1;
+ if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+ return -1;
+ t = f->to;
+ s = f->stop;
+ for(nc = n; nc > 0; nc--){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ FMTRUNE(f, t, s, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+_fmtrcpy(Fmt *f, void *vm, int n)
+{
+ Rune r, *m, *me, *rt, *rs;
+ char *t, *s;
+ ulong fl;
+ int w;
+
+ m = vm;
+ w = f->width;
+ fl = f->flags;
+ if((fl & FmtPrec) && n > f->prec)
+ n = f->prec;
+ if(f->runes){
+ if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
+ return -1;
+ rt = f->to;
+ rs = f->stop;
+ for(me = m + n; m < me; m++)
+ FMTRCHAR(f, rt, rs, *m);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+ return -1;
+ t = f->to;
+ s = f->stop;
+ for(me = m + n; m < me; m++){
+ r = *m;
+ FMTRUNE(f, t, s, r);
+ }
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/* fmt out one character */
+int
+_charfmt(Fmt *f)
+{
+ char x[1];
+
+ x[0] = va_arg(f->args, int);
+ f->prec = 1;
+ return _fmtcpy(f, x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+_runefmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = va_arg(f->args, int);
+ return _fmtrcpy(f, x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+ int p, i;
+ if(!s)
+ return _fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(i = 0; i < p; i++)
+ if(s[i] == 0)
+ break;
+ return _fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
+ }
+
+ return _fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+_strfmt(Fmt *f)
+{
+ char *s;
+
+ s = va_arg(f->args, char *);
+ return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+ Rune *e;
+ int n, p;
+
+ if(!s)
+ return _fmtcpy(f, "<nil>", 5, 5);
+ /* if precision is specified, make sure we don't wander off the end */
+ if(f->flags & FmtPrec){
+ p = f->prec;
+ for(n = 0; n < p; n++)
+ if(s[n] == 0)
+ break;
+ }else{
+ for(e = s; *e; e++)
+ ;
+ n = e - s;
+ }
+ return _fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+_runesfmt(Fmt *f)
+{
+ Rune *s;
+
+ s = va_arg(f->args, Rune *);
+ return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+_percentfmt(Fmt *f)
+{
+ Rune x[1];
+
+ x[0] = f->r;
+ f->prec = 1;
+ return _fmtrcpy(f, x, 1);
+}
+
+/* fmt an integer */
+int
+_ifmt(Fmt *f)
+{
+ char buf[70], *p, *conv;
+ uvlong vu;
+ ulong u;
+ int neg, base, i, n, fl, w, isv;
+
+ neg = 0;
+ fl = f->flags;
+ isv = 0;
+ vu = 0;
+ u = 0;
+ if(f->r == 'p'){
+ u = (ulong)va_arg(f->args, void*);
+ f->r = 'x';
+ fl |= FmtUnsigned;
+ }else if(fl & FmtVLong){
+ isv = 1;
+ if(fl & FmtUnsigned)
+ vu = va_arg(f->args, uvlong);
+ else
+ vu = va_arg(f->args, vlong);
+ }else if(fl & FmtLong){
+ if(fl & FmtUnsigned)
+ u = va_arg(f->args, ulong);
+ else
+ u = va_arg(f->args, long);
+ }else if(fl & FmtByte){
+ if(fl & FmtUnsigned)
+ u = (uchar)va_arg(f->args, int);
+ else
+ u = (char)va_arg(f->args, int);
+ }else if(fl & FmtShort){
+ if(fl & FmtUnsigned)
+ u = (ushort)va_arg(f->args, int);
+ else
+ u = (short)va_arg(f->args, int);
+ }else{
+ if(fl & FmtUnsigned)
+ u = va_arg(f->args, uint);
+ else
+ u = va_arg(f->args, int);
+ }
+ conv = "0123456789abcdef";
+ switch(f->r){
+ case 'd':
+ base = 10;
+ break;
+ case 'x':
+ base = 16;
+ break;
+ case 'X':
+ base = 16;
+ conv = "0123456789ABCDEF";
+ break;
+ case 'b':
+ base = 2;
+ break;
+ case 'o':
+ base = 8;
+ break;
+ default:
+ return -1;
+ }
+ if(!(fl & FmtUnsigned)){
+ if(isv && (vlong)vu < 0){
+ vu = -(vlong)vu;
+ neg = 1;
+ }else if(!isv && (long)u < 0){
+ u = -(long)u;
+ neg = 1;
+ }
+ }
+ p = buf + sizeof buf - 1;
+ n = 0;
+ if(isv){
+ while(vu){
+ i = vu % base;
+ vu /= base;
+ if((fl & FmtComma) && n % 4 == 3){
+ *p-- = ',';
+ n++;
+ }
+ *p-- = conv[i];
+ n++;
+ }
+ }else{
+ while(u){
+ i = u % base;
+ u /= base;
+ if((fl & FmtComma) && n % 4 == 3){
+ *p-- = ',';
+ n++;
+ }
+ *p-- = conv[i];
+ n++;
+ }
+ }
+ if(n == 0){
+ *p-- = '0';
+ n = 1;
+ }
+ for(w = f->prec; n < w && p > buf+3; n++)
+ *p-- = '0';
+ if(neg || (fl & (FmtSign|FmtSpace)))
+ n++;
+ if(fl & FmtSharp){
+ if(base == 16)
+ n += 2;
+ else if(base == 8){
+ if(p[1] == '0')
+ fl &= ~FmtSharp;
+ else
+ n++;
+ }
+ }
+ if((fl & FmtZero) && !(fl & FmtLeft)){
+ for(w = f->width; n < w && p > buf+3; n++)
+ *p-- = '0';
+ f->width = 0;
+ }
+ if(fl & FmtSharp){
+ if(base == 16)
+ *p-- = f->r;
+ if(base == 16 || base == 8)
+ *p-- = '0';
+ }
+ if(neg)
+ *p-- = '-';
+ else if(fl & FmtSign)
+ *p-- = '+';
+ else if(fl & FmtSpace)
+ *p-- = ' ';
+ f->flags &= ~FmtPrec;
+ return _fmtcpy(f, p + 1, n, n);
+}
+
+int
+_countfmt(Fmt *f)
+{
+ void *p;
+ ulong fl;
+
+ fl = f->flags;
+ p = va_arg(f->args, void*);
+ if(fl & FmtVLong){
+ *(vlong*)p = f->nfmt;
+ }else if(fl & FmtLong){
+ *(long*)p = f->nfmt;
+ }else if(fl & FmtByte){
+ *(char*)p = f->nfmt;
+ }else if(fl & FmtShort){
+ *(short*)p = f->nfmt;
+ }else{
+ *(int*)p = f->nfmt;
+ }
+ return 0;
+}
+
+int
+_flagfmt(Fmt *f)
+{
+ switch(f->r){
+ case ',':
+ f->flags |= FmtComma;
+ break;
+ case '-':
+ f->flags |= FmtLeft;
+ break;
+ case '+':
+ f->flags |= FmtSign;
+ break;
+ case '#':
+ f->flags |= FmtSharp;
+ break;
+ case ' ':
+ f->flags |= FmtSpace;
+ break;
+ case 'u':
+ f->flags |= FmtUnsigned;
+ break;
+ case 'h':
+ if(f->flags & FmtShort)
+ f->flags |= FmtByte;
+ f->flags |= FmtShort;
+ break;
+ case 'l':
+ if(f->flags & FmtLong)
+ f->flags |= FmtVLong;
+ f->flags |= FmtLong;
+ break;
+ }
+ return 1;
+}
+
+/* default error format */
+int
+_badfmt(Fmt *f)
+{
+ char x[3];
+
+ x[0] = '%';
+ x[1] = f->r;
+ x[2] = '%';
+ f->prec = 3;
+ _fmtcpy(f, x, 3, 3);
+ return 0;
+}
diff --git a/libkern/exp.c b/libkern/exp.c
new file mode 100644
index 00000000..3098194b
--- /dev/null
+++ b/libkern/exp.c
@@ -0,0 +1,39 @@
+/*
+ exp returns the exponential function of its
+ floating-point argument.
+
+ The coefficients are #1069 from Hart and Cheney. (22.35D)
+*/
+
+#include <lib9.h>
+
+#define p0 .2080384346694663001443843411e7
+#define p1 .3028697169744036299076048876e5
+#define p2 .6061485330061080841615584556e2
+#define q0 .6002720360238832528230907598e7
+#define q1 .3277251518082914423057964422e6
+#define q2 .1749287689093076403844945335e4
+#define log2e 1.4426950408889634073599247
+#define sqrt2 1.4142135623730950488016887
+#define maxf 10000
+
+double
+exp(double arg)
+{
+ double fract, temp1, temp2, xsq;
+ int ent;
+
+ if(arg == 0)
+ return 1;
+ if(arg < -maxf)
+ return 0;
+ if(arg > maxf)
+ return Inf(1);
+ arg *= log2e;
+ ent = floor(arg);
+ fract = (arg-ent) - 0.5;
+ xsq = fract*fract;
+ temp1 = ((p2*xsq+p1)*xsq+p0)*fract;
+ temp2 = ((xsq+q2)*xsq+q1)*xsq + q0;
+ return ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent);
+}
diff --git a/libkern/fcallfmt.c b/libkern/fcallfmt.c
new file mode 100644
index 00000000..e8659b2e
--- /dev/null
+++ b/libkern/fcallfmt.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright © 2001, 2002 Lucent Technologies Inc. All rights reserved.
+ * Use, distribution etc are subject to the terms of the
+ * Lucent Technologies Inc. Plan 9 Open Source Licence Agreement
+ * available at http://plan9.bell-labs.com/plan9dist/license.html
+ */
+
+#include <lib9.h>
+#include <fcall.h>
+
+static uint dumpsome(char*, char*, char*, long);
+static void fdirconv(char*, char*, Dir*);
+static char *qidtype(char*, uchar);
+
+#define QIDFMT "(%.16llux %lud %s)"
+
+int
+fcallfmt(Fmt *fmt)
+{
+ Fcall *f;
+ int fid, type, tag, i;
+ char buf[512], tmp[200];
+ char *p, *e;
+ Dir *d;
+ Qid *q;
+
+ e = buf+sizeof(buf);
+ f = va_arg(fmt->args, Fcall*);
+ type = f->type;
+ fid = f->fid;
+ tag = f->tag;
+ switch(type){
+ case Tversion: /* 100 */
+ seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+ break;
+ case Rversion:
+ seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+ break;
+ case Tauth: /* 102 */
+ seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
+ f->afid, f->uname, f->aname);
+ break;
+ case Rauth:
+ seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
+ f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
+ break;
+ case Tattach: /* 104 */
+ seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
+ fid, f->afid, f->uname, f->aname);
+ break;
+ case Rattach:
+ seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
+ break;
+ case Rerror: /* 107; 106 (Terror) illegal */
+ seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
+ break;
+ case Tflush: /* 108 */
+ seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
+ break;
+ case Rflush:
+ seprint(buf, e, "Rflush tag %ud", tag);
+ break;
+ case Twalk: /* 110 */
+ p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
+ if(f->nwname <= MAXWELEM)
+ for(i=0; i<f->nwname; i++)
+ p = seprint(p, e, "%d:%s ", i, f->wname[i]);
+ break;
+ case Rwalk:
+ p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
+ if(f->nwqid <= MAXWELEM)
+ for(i=0; i<f->nwqid; i++){
+ q = &f->wqid[i];
+ p = seprint(p, e, "%d:" QIDFMT " ", i,
+ q->path, q->vers, qidtype(tmp, q->type));
+ }
+ break;
+ case Topen: /* 112 */
+ seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
+ break;
+ case Ropen:
+ seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+ break;
+ case Tcreate: /* 114 */
+ seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode);
+ break;
+ case Rcreate:
+ seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
+ f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+ break;
+ case Tread: /* 116 */
+ seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
+ tag, fid, f->offset, f->count);
+ break;
+ case Rread:
+ p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
+ dumpsome(p, e, f->data, f->count);
+ break;
+ case Twrite: /* 118 */
+ p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
+ tag, fid, f->offset, f->count);
+ dumpsome(p, e, f->data, f->count);
+ break;
+ case Rwrite:
+ seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
+ break;
+ case Tclunk: /* 120 */
+ seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
+ break;
+ case Rclunk:
+ seprint(buf, e, "Rclunk tag %ud", tag);
+ break;
+ case Tremove: /* 122 */
+ seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
+ break;
+ case Rremove:
+ seprint(buf, e, "Rremove tag %ud", tag);
+ break;
+ case Tstat: /* 124 */
+ seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
+ break;
+ case Rstat:
+ p = seprint(buf, e, "Rstat tag %ud ", tag);
+ if(f->nstat > sizeof tmp)
+ seprint(p, e, " stat(%d bytes)", f->nstat);
+ else{
+ d = (Dir*)tmp;
+ convM2D(f->stat, f->nstat, d, (char*)(d+1));
+ seprint(p, e, " stat ");
+ fdirconv(p+6, e, d);
+ }
+ break;
+ case Twstat: /* 126 */
+ p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
+ if(f->nstat > sizeof tmp)
+ seprint(p, e, " stat(%d bytes)", f->nstat);
+ else{
+ d = (Dir*)tmp;
+ convM2D(f->stat, f->nstat, d, (char*)(d+1));
+ seprint(p, e, " stat ");
+ fdirconv(p+6, e, d);
+ }
+ break;
+ case Rwstat:
+ seprint(buf, e, "Rwstat tag %ud", tag);
+ break;
+ default:
+ seprint(buf, e, "unknown type %d", type);
+ }
+ return fmtstrcpy(fmt, buf);
+}
+
+static char*
+qidtype(char *s, uchar t)
+{
+ char *p;
+
+ p = s;
+ if(t & QTDIR)
+ *p++ = 'd';
+ if(t & QTAPPEND)
+ *p++ = 'a';
+ if(t & QTEXCL)
+ *p++ = 'l';
+ if(t & QTAUTH)
+ *p++ = 'A';
+ *p = '\0';
+ return s;
+}
+
+int
+dirfmt(Fmt *fmt)
+{
+ char buf[160];
+
+ fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
+ return fmtstrcpy(fmt, buf);
+}
+
+static void
+fdirconv(char *buf, char *e, Dir *d)
+{
+ char tmp[16];
+
+ seprint(buf, e, "'%s' '%s' '%s' '%s' "
+ "q " QIDFMT " m %#luo "
+ "at %ld mt %ld l %lld "
+ "t %d d %d",
+ d->name, d->uid, d->gid, d->muid,
+ d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
+ d->atime, d->mtime, d->length,
+ d->type, d->dev);
+}
+
+/*
+ * dump out count (or DUMPL, if count is bigger) bytes from
+ * buf to ans, as a string if they are all printable,
+ * else as a series of hex bytes
+ */
+#define DUMPL 64
+
+static uint
+dumpsome(char *ans, char *e, char *buf, long count)
+{
+ int i, printable;
+ char *p;
+
+ if(buf == nil){
+ seprint(ans, e, "<no data>");
+ return strlen(ans);
+ }
+ printable = 1;
+ if(count > DUMPL)
+ count = DUMPL;
+ for(i=0; i<count && printable; i++)
+ if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127)
+ printable = 0;
+ p = ans;
+ *p++ = '\'';
+ if(printable){
+ if(count > e-p-2)
+ count = e-p-2;
+ memmove(p, buf, count);
+ p += count;
+ }else{
+ if(2*count > e-p-2)
+ count = (e-p-2)/2;
+ for(i=0; i<count; i++){
+ if(i>0 && i%4==0)
+ *p++ = ' ';
+ sprint(p, "%2.2ux", buf[i]);
+ p += 2;
+ }
+ }
+ *p++ = '\'';
+ *p = 0;
+ return p - ans;
+}
diff --git a/libkern/floor.c b/libkern/floor.c
new file mode 100644
index 00000000..86e6c816
--- /dev/null
+++ b/libkern/floor.c
@@ -0,0 +1,26 @@
+#include <lib9.h>
+/*
+ * floor and ceil-- greatest integer <= arg
+ * (resp least >=)
+ */
+
+double
+floor(double d)
+{
+ double fract;
+
+ if(d < 0) {
+ fract = modf(-d, &d);
+ if(fract != 0.0)
+ d += 1;
+ d = -d;
+ } else
+ modf(d, &d);
+ return d;
+}
+
+double
+ceil(double d)
+{
+ return -floor(-d);
+}
diff --git a/libkern/fmt.c b/libkern/fmt.c
new file mode 100644
index 00000000..11aac065
--- /dev/null
+++ b/libkern/fmt.c
@@ -0,0 +1,188 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+enum
+{
+ Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+ int c;
+ volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+struct
+{
+ /* lock by calling _fmtlock, _fmtunlock */
+ int nfmt;
+ Convfmt fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+ ' ', _flagfmt,
+ '#', _flagfmt,
+ '%', _percentfmt,
+ '+', _flagfmt,
+ ',', _flagfmt,
+ '-', _flagfmt,
+ 'C', _runefmt,
+ 'S', _runesfmt,
+ 'X', _ifmt,
+ 'b', _ifmt,
+ 'c', _charfmt,
+ 'd', _ifmt,
+ 'h', _flagfmt,
+ 'l', _flagfmt,
+ 'n', _countfmt,
+ 'o', _ifmt,
+ 'p', _ifmt,
+ 'r', errfmt,
+ 's', _strfmt,
+ 'u', _flagfmt,
+ 'x', _ifmt,
+ 0, nil,
+};
+
+int (*doquote)(int);
+
+static Fmts
+fmtfmt(int c)
+{
+ Convfmt *p, *ep;
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ return p->fmt;
+
+ /* is this a predefined format char? */
+ for(p=knownfmt; p->c; p++)
+ if(p->c == c){
+ /* no need to lock; fmtinstall is idempotent */
+ fmtinstall(p->c, p->fmt);
+ while(p->fmt == nil) /* loop until value is updated */
+ ;
+ return p->fmt;
+ }
+
+ return _badfmt;
+}
+
+int
+fmtinstall(int c, Fmts f)
+{
+ Convfmt *p, *ep;
+
+ if(c<=0 || c>=65536)
+ return -1;
+ if(!f)
+ f = _badfmt;
+
+ _fmtlock();
+
+ ep = &fmtalloc.fmt[fmtalloc.nfmt];
+ for(p=fmtalloc.fmt; p<ep; p++)
+ if(p->c == c)
+ break;
+
+ if(p == &fmtalloc.fmt[Maxfmt]){
+ _fmtunlock();
+ return -1;
+ }
+
+ p->fmt = f;
+ if(p == ep){ /* installing a new format character */
+ fmtalloc.nfmt++;
+ p->c = c;
+ }
+
+ _fmtunlock();
+ return 0;
+}
+
+void*
+_fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+ Rune rune, r;
+ int i, n;
+
+ f->flags = 0;
+ f->width = f->prec = 0;
+
+ for(;;){
+ if(isrunes){
+ r = *(Rune*)fmt;
+ fmt = (Rune*)fmt + 1;
+ }else{
+ fmt = (char*)fmt + chartorune(&rune, fmt);
+ r = rune;
+ }
+ f->r = r;
+ switch(r){
+ case '\0':
+ return nil;
+ case '.':
+ f->flags |= FmtWidth|FmtPrec;
+ continue;
+ case '0':
+ if(!(f->flags & FmtWidth)){
+ f->flags |= FmtZero;
+ continue;
+ }
+ /* fall through */
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ i = 0;
+ while(r >= '0' && r <= '9'){
+ i = i * 10 + r - '0';
+ if(isrunes){
+ r = *(Rune*)fmt;
+ fmt = (Rune*)fmt + 1;
+ }else{
+ r = *(char*)fmt;
+ fmt = (char*)fmt + 1;
+ }
+ }
+ if(isrunes)
+ fmt = (Rune*)fmt - 1;
+ else
+ fmt = (char*)fmt - 1;
+ numflag:
+ if(f->flags & FmtWidth){
+ f->flags |= FmtPrec;
+ f->prec = i;
+ }else{
+ f->flags |= FmtWidth;
+ f->width = i;
+ }
+ continue;
+ case '*':
+ i = va_arg(f->args, int);
+ if(i < 0){
+ i = -i;
+ f->flags |= FmtLeft;
+ }
+ goto numflag;
+ }
+ n = (*fmtfmt(r))(f);
+ if(n < 0)
+ return nil;
+ if(n == 0)
+ return fmt;
+ }
+}
diff --git a/libkern/fmtdef.h b/libkern/fmtdef.h
new file mode 100644
index 00000000..d8f3680f
--- /dev/null
+++ b/libkern/fmtdef.h
@@ -0,0 +1,85 @@
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+ int quoted; /* if set, string must be quoted */
+ int nrunesin; /* number of input runes that can be accepted */
+ int nbytesin; /* number of input bytes that can be accepted */
+ int nrunesout; /* number of runes that will be generated */
+ int nbytesout; /* number of bytes that will be generated */
+};
+
+void *_fmtflush(Fmt*, void*, int);
+void *_fmtdispatch(Fmt*, void*, int);
+int _floatfmt(Fmt*, double);
+int _fmtpad(Fmt*, int);
+int _rfmtpad(Fmt*, int);
+int _fmtFdFlush(Fmt*);
+
+int _efgfmt(Fmt*);
+int _charfmt(Fmt*);
+int _countfmt(Fmt*);
+int _flagfmt(Fmt*);
+int _percentfmt(Fmt*);
+int _ifmt(Fmt*);
+int _runefmt(Fmt*);
+int _runesfmt(Fmt*);
+int _strfmt(Fmt*);
+int _badfmt(Fmt*);
+int _fmtcpy(Fmt*, void*, int, int);
+int _fmtrcpy(Fmt*, void*, int n);
+
+void _fmtlock(void);
+void _fmtunlock(void);
+
+#define FMTCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (char*)s){\
+ t = _fmtflush(f, t, 1);\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+ do{\
+ if(t + 1 > (Rune*)s){\
+ t = _fmtflush(f, t, sizeof(Rune));\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ *t++ = c;\
+ }while(0)
+
+#define FMTRUNE(f, t, s, r)\
+ do{\
+ Rune _rune;\
+ int _runelen;\
+ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+ t = _fmtflush(f, t, _runelen);\
+ if(t != nil)\
+ s = f->stop;\
+ else\
+ return -1;\
+ }\
+ if(r < Runeself)\
+ *t++ = r;\
+ else{\
+ _rune = r;\
+ t += runetochar(t, &_rune);\
+ }\
+ }while(0)
diff --git a/libkern/fmtprint.c b/libkern/fmtprint.c
new file mode 100644
index 00000000..c93cb315
--- /dev/null
+++ b/libkern/fmtprint.c
@@ -0,0 +1,44 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+ va_list va;
+ int n;
+
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ va = f->args;
+ va_start(f->args, fmt);
+ n = dofmt(f, fmt);
+ va_end(f->args);
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ f->args = va;
+ if(n >= 0)
+ return 0;
+ return n;
+}
+
diff --git a/libkern/fmtquote.c b/libkern/fmtquote.c
new file mode 100644
index 00000000..3e6338bf
--- /dev/null
+++ b/libkern/fmtquote.c
@@ -0,0 +1,259 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by _quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ * NUL in input
+ * count exceeded in input
+ * count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+ int w;
+ Rune c;
+
+ q->quoted = 0;
+ q->nbytesout = 0;
+ q->nrunesout = 0;
+ q->nbytesin = 0;
+ q->nrunesin = 0;
+ if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+ if(nout < 2)
+ return;
+ q->quoted = 1;
+ q->nbytesout = 2;
+ q->nrunesout = 2;
+ }
+ for(; nin!=0; nin-=w){
+ if(s)
+ w = chartorune(&c, s);
+ else{
+ c = *r;
+ w = runelen(c);
+ }
+
+ if(c == '\0')
+ break;
+ if(runesout){
+ if(q->nrunesout+1 > nout)
+ break;
+ }else{
+ if(q->nbytesout+w > nout)
+ break;
+ }
+
+ if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
+ if(!q->quoted){
+ if(runesout){
+ if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
+ break;
+ }else{
+ if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
+ break;
+ }
+ q->nrunesout += 2; /* include quotes */
+ q->nbytesout += 2; /* include quotes */
+ q->quoted = 1;
+ }
+ if(c == '\'') {
+ if(runesout){
+ if(1+q->nrunesout+1 > nout) /* no room for quotes */
+ break;
+ }else{
+ if(1+q->nbytesout+w > nout) /* no room for quotes */
+ break;
+ }
+ q->nbytesout++;
+ q->nrunesout++; /* quotes reproduce as two characters */
+ }
+ }
+
+ /* advance input */
+ if(s)
+ s += w;
+ else
+ r++;
+ q->nbytesin += w;
+ q->nrunesin++;
+
+ /* advance output */
+ q->nbytesout += w;
+ q->nrunesout++;
+ }
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+ Rune r, *rm, *rme;
+ char *t, *s, *m, *me;
+ Rune *rt, *rs;
+ ulong fl;
+ int nc, w;
+
+ m = sin;
+ me = m + q->nbytesin;
+ rm = rin;
+ rme = rm + q->nrunesin;
+
+ w = f->width;
+ fl = f->flags;
+ if(f->runes){
+ if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ t = f->to;
+ s = f->stop;
+ rt = f->to;
+ rs = f->stop;
+ if(f->runes)
+ FMTRCHAR(f, rt, rs, '\'');
+ else
+ FMTRUNE(f, t, s, '\'');
+ for(nc = q->nrunesin; nc > 0; nc--){
+ if(sin){
+ r = *(uchar*)m;
+ if(r < Runeself)
+ m++;
+ else if((me - m) >= UTFmax || fullrune(m, me-m))
+ m += chartorune(&r, m);
+ else
+ break;
+ }else{
+ if(rm >= rme)
+ break;
+ r = *rm++;
+ }
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, r);
+ if(r == '\'')
+ FMTRCHAR(f, rt, rs, r);
+ }else{
+ FMTRUNE(f, t, s, r);
+ if(r == '\'')
+ FMTRUNE(f, t, s, r);
+ }
+ }
+
+ if(f->runes){
+ FMTRCHAR(f, rt, rs, '\'');
+ USED(rs);
+ f->nfmt += rt - (Rune *)f->to;
+ f->to = rt;
+ if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
+ return -1;
+ }else{
+ FMTRUNE(f, t, s, '\'');
+ USED(s);
+ f->nfmt += t - (char *)f->to;
+ f->to = t;
+ if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int
+_quotestrfmt(int runesin, Fmt *f)
+{
+ int outlen;
+ Rune *r;
+ char *s;
+ Quoteinfo q;
+
+ f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
+ if(runesin){
+ r = va_arg(f->args, Rune *);
+ s = nil;
+ }else{
+ s = va_arg(f->args, char *);
+ r = nil;
+ }
+ if(!s && !r)
+ return _fmtcpy(f, "<nil>", 5, 5);
+
+ if(f->flush)
+ outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
+ else if(f->runes)
+ outlen = (Rune*)f->stop - (Rune*)f->to;
+ else
+ outlen = (char*)f->stop - (char*)f->to;
+
+ _quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
+//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+
+ if(runesin){
+ if(!q.quoted)
+ return _fmtrcpy(f, r, q.nrunesin);
+ return qstrfmt(nil, r, &q, f);
+ }
+
+ if(!q.quoted)
+ return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
+ return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+ return _quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+ return _quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+ fmtinstall('q', quotestrfmt);
+ fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+_needsquotes(char *s, int *quotelenp)
+{
+ Quoteinfo q;
+
+ _quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nbytesout;
+
+ return q.quoted;
+}
+
+int
+_runeneedsquotes(Rune *r, int *quotelenp)
+{
+ Quoteinfo q;
+
+ _quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+ *quotelenp = q.nrunesout;
+
+ return q.quoted;
+}
diff --git a/libkern/fmtstr.c b/libkern/fmtstr.c
new file mode 100644
index 00000000..9f94d134
--- /dev/null
+++ b/libkern/fmtstr.c
@@ -0,0 +1,23 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+fmtstrflush(Fmt *f)
+{
+ if(f->start == nil)
+ return nil;
+ *(char*)f->to = '\0';
+ return f->start;
+}
diff --git a/libkern/fmtvprint.c b/libkern/fmtvprint.c
new file mode 100644
index 00000000..6682cd33
--- /dev/null
+++ b/libkern/fmtvprint.c
@@ -0,0 +1,43 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+ va_list va;
+ int n;
+
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ va = f->args;
+ f->args = args;
+ n = dofmt(f, fmt);
+ f->flags = 0;
+ f->width = 0;
+ f->prec = 0;
+ f->args = va;
+ if(n >= 0)
+ return 0;
+ return n;
+}
+
diff --git a/libkern/frexp-386.c b/libkern/frexp-386.c
new file mode 100644
index 00000000..8973a14d
--- /dev/null
+++ b/libkern/frexp-386.c
@@ -0,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ls;
+ long ms;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/libkern/frexp-68000.c b/libkern/frexp-68000.c
new file mode 100644
index 00000000..ac22e037
--- /dev/null
+++ b/libkern/frexp-68000.c
@@ -0,0 +1,80 @@
+#include <u.h>
+#include <libc.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/libkern/frexp-arm.c b/libkern/frexp-arm.c
new file mode 100644
index 00000000..0acf6ec1
--- /dev/null
+++ b/libkern/frexp-arm.c
@@ -0,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct /* this is BIGENDIAN */
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/libkern/frexp-mips.c b/libkern/frexp-mips.c
new file mode 100644
index 00000000..ac22e037
--- /dev/null
+++ b/libkern/frexp-mips.c
@@ -0,0 +1,80 @@
+#include <u.h>
+#include <libc.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/libkern/frexp-power.c b/libkern/frexp-power.c
new file mode 100644
index 00000000..b13bbead
--- /dev/null
+++ b/libkern/frexp-power.c
@@ -0,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/libkern/frexp-sparc.c b/libkern/frexp-sparc.c
new file mode 100644
index 00000000..b13bbead
--- /dev/null
+++ b/libkern/frexp-sparc.c
@@ -0,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/libkern/frexp-thumb.c b/libkern/frexp-thumb.c
new file mode 100644
index 00000000..0acf6ec1
--- /dev/null
+++ b/libkern/frexp-thumb.c
@@ -0,0 +1,79 @@
+#include <lib9.h>
+
+#define MASK 0x7ffL
+#define SHIFT 20
+#define BIAS 1022L
+
+typedef union
+{
+ double d;
+ struct /* this is BIGENDIAN */
+ {
+ long ms;
+ long ls;
+ };
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+ Cheat x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x.d = d;
+ *ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= BIAS << SHIFT;
+ return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+ Cheat x;
+
+ if(d == 0)
+ return 0;
+ x.d = d;
+ e += (x.ms >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x.ms &= ~(MASK << SHIFT);
+ x.ms |= (long)e << SHIFT;
+ return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+ Cheat x;
+ int e;
+
+ if(d < 1) {
+ if(d < 0) {
+ x.d = modf(-d, ip);
+ *ip = -*ip;
+ return -x.d;
+ }
+ *ip = 0;
+ return d;
+ }
+ x.d = d;
+ e = ((x.ms >> SHIFT) & MASK) - BIAS;
+ if(e <= SHIFT+1) {
+ x.ms &= ~(0x1fffffL >> e);
+ x.ls = 0;
+ } else
+ if(e <= SHIFT+33)
+ x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+ *ip = x.d;
+ return d - x.d;
+}
diff --git a/libkern/getfcr-386.s b/libkern/getfcr-386.s
new file mode 100644
index 00000000..c3f3d464
--- /dev/null
+++ b/libkern/getfcr-386.s
@@ -0,0 +1,27 @@
+TEXT setfcr(SB), $0
+ MOVL p+0(FP),AX
+ XORB $0x3f,AX
+ PUSHW AX
+ WAIT
+ FLDCW 0(SP)
+ POPW AX
+ RET
+
+TEXT getfcr(SB), $0
+ PUSHW AX
+ WAIT
+ FSTCW 0(SP)
+ POPW AX
+ XORB $0x3f,AX
+ RET
+
+TEXT getfsr(SB), $0
+ WAIT
+ FSTSW AX
+ RET
+
+TEXT setfsr(SB), $0
+ WAIT
+ FCLEX
+ RET
+
diff --git a/libkern/getfcr-68000.s b/libkern/getfcr-68000.s
new file mode 100644
index 00000000..7f67d038
--- /dev/null
+++ b/libkern/getfcr-68000.s
@@ -0,0 +1,19 @@
+TEXT getfsr(SB), $0
+ MOVL $0, R0
+ MOVL FPSR, R0
+ RTS
+
+TEXT setfsr(SB), $0
+ MOVL new+0(FP), R1
+ MOVL R1, FPSR
+ RTS
+
+TEXT getfcr(SB), $0
+ MOVL $0, R0
+ MOVL FPCR, R0
+ RTS
+
+TEXT setfcr(SB), $0
+ MOVL new+0(FP), R1
+ MOVL R1, FPCR
+ RTS
diff --git a/libkern/getfcr-arm.s b/libkern/getfcr-arm.s
new file mode 100644
index 00000000..dc9a207b
--- /dev/null
+++ b/libkern/getfcr-arm.s
@@ -0,0 +1,12 @@
+TEXT setfcr(SB), $0
+ RET
+
+TEXT getfcr(SB), $0
+ RET
+
+TEXT getfsr(SB), $0
+ RET
+
+TEXT setfsr(SB), $0
+ RET
+
diff --git a/libkern/getfcr-mips.s b/libkern/getfcr-mips.s
new file mode 100644
index 00000000..9e84cbcc
--- /dev/null
+++ b/libkern/getfcr-mips.s
@@ -0,0 +1,15 @@
+TEXT getfsr(SB), $0
+ MOVW FCR31, R1
+ RET
+
+TEXT setfsr(SB), $0
+ MOVW R1, FCR31
+ RET
+
+TEXT getfcr(SB), $0
+ MOVW FCR31, R1
+ RET
+
+TEXT setfcr(SB), $0
+ MOVW R1, FCR31
+ RET
diff --git a/libkern/getfcr-power.s b/libkern/getfcr-power.s
new file mode 100644
index 00000000..b61d52e6
--- /dev/null
+++ b/libkern/getfcr-power.s
@@ -0,0 +1,28 @@
+TEXT getfcr(SB), $8
+ MOVFL FPSCR, F3
+ FMOVD F3, f-8(SP)
+ MOVW -4(SP), R3
+ RETURN
+
+TEXT getfsr(SB), $8
+ MOVFL FPSCR, F3
+ FMOVD F3, f-8(SP)
+ MOVW -4(SP), R3
+ RETURN
+
+TEXT setfcr(SB), $8
+ SYNC
+ MOVW R3, -4(SP)
+ FMOVD -8(SP), F3
+ MOVFL F3, FPSCR
+ ISYNC
+ RETURN
+
+TEXT setfsr(SB), $8
+ SYNC
+ MOVW R3, -4(SP)
+ FMOVD -8(SP), F3
+ MOVFL F3, FPSCR
+ ISYNC
+ RETURN
+
diff --git a/libkern/getfcr-sparc.s b/libkern/getfcr-sparc.s
new file mode 100644
index 00000000..0059ada5
--- /dev/null
+++ b/libkern/getfcr-sparc.s
@@ -0,0 +1,27 @@
+TEXT getfsr(SB), $0
+ SUB $4, R1
+ MOVW FSR, (R1)
+ MOVW (R1), R7
+ ADD $4, R1
+ RETURN
+
+TEXT setfsr(SB), $0
+ SUB $4, R1
+ MOVW R7, (R1)
+ MOVW (R1), FSR
+ ADD $4, R1
+ RETURN
+
+TEXT setfcr(SB), $0
+ SUB $4, R1
+ MOVW R7, (R1)
+ MOVW (R1), FSR
+ ADD $4, R1
+ RETURN
+
+TEXT getfcr(SB), $0
+ SUB $4, R1
+ MOVW FSR, (R1)
+ MOVW (R1), R7
+ ADD $4, R1
+ RETURN
diff --git a/libkern/getfcr-thumb.s b/libkern/getfcr-thumb.s
new file mode 100644
index 00000000..dc9a207b
--- /dev/null
+++ b/libkern/getfcr-thumb.s
@@ -0,0 +1,12 @@
+TEXT setfcr(SB), $0
+ RET
+
+TEXT getfcr(SB), $0
+ RET
+
+TEXT getfsr(SB), $0
+ RET
+
+TEXT setfsr(SB), $0
+ RET
+
diff --git a/libkern/getfields.c b/libkern/getfields.c
new file mode 100644
index 00000000..44d7417c
--- /dev/null
+++ b/libkern/getfields.c
@@ -0,0 +1,35 @@
+#include "lib9.h"
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+ Rune r;
+ int nr, intok, narg;
+
+ if(max <= 0)
+ return 0;
+
+ narg = 0;
+ args[narg] = str;
+ if(!mflag)
+ narg++;
+ intok = 0;
+ for(;; str += nr) {
+ nr = chartorune(&r, str);
+ if(r == 0)
+ break;
+ if(utfrune(set, r)) {
+ if(narg >= max)
+ break;
+ *str = 0;
+ intok = 0;
+ args[narg] = str + nr;
+ if(!mflag)
+ narg++;
+ } else {
+ if(!intok && mflag)
+ narg++;
+ intok = 1;
+ }
+ }
+ return narg;
+}
diff --git a/libkern/log.c b/libkern/log.c
new file mode 100644
index 00000000..1387aa3d
--- /dev/null
+++ b/libkern/log.c
@@ -0,0 +1,57 @@
+/*
+ log returns the natural logarithm of its floating
+ point argument.
+
+ The coefficients are #2705 from Hart & Cheney. (19.38D)
+
+ It calls frexp.
+*/
+
+#include <lib9.h>
+
+#define log2 0.693147180559945309e0
+#define ln10o1 .4342944819032518276511
+#define sqrto2 0.707106781186547524e0
+#define p0 -.240139179559210510e2
+#define p1 0.309572928215376501e2
+#define p2 -.963769093377840513e1
+#define p3 0.421087371217979714e0
+#define q0 -.120069589779605255e2
+#define q1 0.194809660700889731e2
+#define q2 -.891110902798312337e1
+
+double
+log(double arg)
+{
+ double x, z, zsq, temp;
+ int exp;
+
+ if(arg <= 0)
+ return NaN();
+ x = frexp(arg, &exp);
+ while(x < 0.5) {
+ x *= 2;
+ exp--;
+ }
+ if(x < sqrto2) {
+ x *= 2;
+ exp--;
+ }
+
+ z = (x-1) / (x+1);
+ zsq = z*z;
+
+ temp = ((p3*zsq + p2)*zsq + p1)*zsq + p0;
+ temp = temp/(((zsq + q2)*zsq + q1)*zsq + q0);
+ temp = temp*z + exp*log2;
+ return temp;
+}
+
+double
+log10(double arg)
+{
+
+ if(arg <= 0)
+ return NaN();
+ return log(arg) * ln10o1;
+}
diff --git a/libkern/memccpy-power.s b/libkern/memccpy-power.s
new file mode 100644
index 00000000..120df6ed
--- /dev/null
+++ b/libkern/memccpy-power.s
@@ -0,0 +1,23 @@
+ TEXT memccpy(SB), $0
+#define BDNZ BC 16,0,
+MOVW R3, s1+0(FP)
+ MOVW n+12(FP), R7
+ MOVW s2+4(FP), R4
+ MOVBZ c+11(FP), R5
+ CMP R7, $0
+ BEQ nf
+ MOVW R7, CTR
+ SUB $1, R3
+ SUB $1, R4
+l1:
+ MOVBZU 1(R4), R6
+ CMP R6, R5
+ MOVBZU R6, 1(R3)
+ BEQ eq
+ BDNZ l1
+nf:
+ MOVW $0, R3
+ RETURN
+eq:
+ ADD $1, R3
+ RETURN
diff --git a/libkern/memccpy.c b/libkern/memccpy.c
new file mode 100644
index 00000000..a7c9118a
--- /dev/null
+++ b/libkern/memccpy.c
@@ -0,0 +1,17 @@
+#include <lib9.h>
+
+void*
+memccpy(void *a1, void *a2, int c, ulong n)
+{
+ uchar *s1, *s2;
+
+ s1 = a1;
+ s2 = a2;
+ c &= 0xFF;
+ while(n > 0) {
+ if((*s1++ = *s2++) == c)
+ return s1;
+ n--;
+ }
+ return 0;
+}
diff --git a/libkern/memchr.c b/libkern/memchr.c
new file mode 100644
index 00000000..5692f435
--- /dev/null
+++ b/libkern/memchr.c
@@ -0,0 +1,16 @@
+#include <lib9.h>
+
+void*
+memchr(void *ap, int c, ulong n)
+{
+ uchar *sp;
+
+ sp = ap;
+ c &= 0xFF;
+ while(n > 0) {
+ if(*sp++ == c)
+ return sp-1;
+ n--;
+ }
+ return 0;
+}
diff --git a/libkern/memcmp-power.s b/libkern/memcmp-power.s
new file mode 100644
index 00000000..f524fa9d
--- /dev/null
+++ b/libkern/memcmp-power.s
@@ -0,0 +1,110 @@
+ TEXT memcmp(SB), $0
+#define BDNZ BC 16,0,
+ MOVW R3, s1+0(FP) /* R3 is pointer1 */
+
+/*
+ * performance:
+ * 67mb/sec aligned; 16mb/sec unaligned
+ */
+
+ MOVW n+8(FP), R4 /* R4 is count */
+ MOVW s2+4(FP), R5 /* R5 is pointer2 */
+
+/*
+ * let LSW do the work for 4 characters or less; aligned and unaligned
+ */
+ CMP R4, $0
+ BLE eq
+ CMP R4, $4
+ BLE out
+
+ XOR R3, R5, R9
+ ANDCC $3, R9
+ BNE l4 /* pointers misaligned; use LSW loop */
+
+/*
+ * do enough bytes to align pointers
+ */
+ ANDCC $3,R3, R9
+ BEQ l2
+ SUBC R9, $4, R9
+ MOVW R9, XER
+ LSW (R3), R10
+ ADD R9, R3
+ LSW (R5), R14
+ ADD R9, R5
+ SUB R9, R4
+ CMPU R10, R14
+ BNE ne
+
+/*
+ * compare 16 at a time
+ */
+l2:
+ SRAWCC $4, R4, R9
+ BLE l4
+ MOVW R9, CTR
+ SUB $4, R3
+ SUB $4, R5
+l3:
+ MOVWU 4(R3), R10
+ MOVWU 4(R5), R12
+ MOVWU 4(R3), R11
+ MOVWU 4(R5), R13
+ CMPU R10, R12
+ BNE ne
+ MOVWU 4(R3), R10
+ MOVWU 4(R5), R12
+ CMPU R11, R13
+ BNE ne
+ MOVWU 4(R3), R11
+ MOVWU 4(R5), R13
+ CMPU R10, R12
+ BNE ne
+ CMPU R11, R13
+ BNE ne
+ BDNZ l3
+ ADD $4, R3
+ ADD $4, R5
+ RLWNMCC $0, R4, $15, R4 /* residue */
+ BEQ eq
+
+/*
+ * do remaining words with LSW; also does unaligned case
+ */
+l4:
+ SRAWCC $2, R4, R9
+ BLE out
+ MOVW R9, CTR
+l5:
+ LSW (R3), $4, R10
+ ADD $4, R3
+ LSW (R5), $4, R11
+ ADD $4, R5
+ CMPU R10, R11
+ BNE ne
+ BDNZ l5
+ RLWNMCC $0, R4, $3, R4 /* residue */
+ BEQ eq
+
+/*
+ * do remaining bytes with final LSW
+ */
+out:
+ MOVW R4, XER
+ LSW (R3), R10
+ LSW (R5), R11
+ CMPU R10, R11
+ BNE ne
+
+eq:
+ MOVW $0, R3
+ RETURN
+
+ne:
+ MOVW $1, R3
+ BGE ret
+ MOVW $-1,R3
+ret:
+ RETURN
+ END
diff --git a/libkern/memcmp.c b/libkern/memcmp.c
new file mode 100644
index 00000000..01be7c62
--- /dev/null
+++ b/libkern/memcmp.c
@@ -0,0 +1,22 @@
+#include <lib9.h>
+
+int
+memcmp(void *a1, void *a2, ulong n)
+{
+ uchar *s1, *s2;
+ uint c1, c2;
+
+ s1 = a1;
+ s2 = a2;
+ while(n > 0) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ n--;
+ }
+ return 0;
+}
diff --git a/libkern/memcpy-386.s b/libkern/memcpy-386.s
new file mode 100644
index 00000000..e85bb232
--- /dev/null
+++ b/libkern/memcpy-386.s
@@ -0,0 +1,58 @@
+ TEXT memmove(SB), $0
+ TEXT memcpy(SB), $0
+
+ MOVL p1+0(FP), DI
+ MOVL p2+4(FP), SI
+ MOVL n+8(FP), BX
+ CMPL BX, $0
+ JGE ok
+ MOVL $0, SI
+ok:
+ CLD
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+back:
+ ADDL BX, DI
+ ADDL BX, SI
+ SUBL $4, DI
+ SUBL $4, SI
+ STD
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ADDL $3, DI
+ ADDL $3, SI
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
diff --git a/libkern/memcpy-arm.c b/libkern/memcpy-arm.c
new file mode 100644
index 00000000..35f0afc5
--- /dev/null
+++ b/libkern/memcpy-arm.c
@@ -0,0 +1,35 @@
+#include <u.h>
+#include <libc.h>
+
+void*
+memmove(void *a1, void *a2, ulong n)
+{
+ char *s1, *s2;
+
+ if((long)n < 0)
+ abort();
+ if(a1 > a2)
+ goto back;
+ s1 = a1;
+ s2 = a2;
+ while(n > 0) {
+ *s1++ = *s2++;
+ n--;
+ }
+ return a1;
+
+back:
+ s1 = (char*)a1 + n;
+ s2 = (char*)a2 + n;
+ while(n > 0) {
+ *--s1 = *--s2;
+ n--;
+ }
+ return a1;
+}
+
+void*
+memcpy(void *a1, void *a2, ulong n)
+{
+ return memmove(a1, a2, n);
+}
diff --git a/libkern/memcpy-thumb.c b/libkern/memcpy-thumb.c
new file mode 100644
index 00000000..35f0afc5
--- /dev/null
+++ b/libkern/memcpy-thumb.c
@@ -0,0 +1,35 @@
+#include <u.h>
+#include <libc.h>
+
+void*
+memmove(void *a1, void *a2, ulong n)
+{
+ char *s1, *s2;
+
+ if((long)n < 0)
+ abort();
+ if(a1 > a2)
+ goto back;
+ s1 = a1;
+ s2 = a2;
+ while(n > 0) {
+ *s1++ = *s2++;
+ n--;
+ }
+ return a1;
+
+back:
+ s1 = (char*)a1 + n;
+ s2 = (char*)a2 + n;
+ while(n > 0) {
+ *--s1 = *--s2;
+ n--;
+ }
+ return a1;
+}
+
+void*
+memcpy(void *a1, void *a2, ulong n)
+{
+ return memmove(a1, a2, n);
+}
diff --git a/libkern/memmove-386.s b/libkern/memmove-386.s
new file mode 100644
index 00000000..e85bb232
--- /dev/null
+++ b/libkern/memmove-386.s
@@ -0,0 +1,58 @@
+ TEXT memmove(SB), $0
+ TEXT memcpy(SB), $0
+
+ MOVL p1+0(FP), DI
+ MOVL p2+4(FP), SI
+ MOVL n+8(FP), BX
+ CMPL BX, $0
+ JGE ok
+ MOVL $0, SI
+ok:
+ CLD
+/*
+ * check and set for backwards
+ */
+ CMPL SI, DI
+ JLS back
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ANDL $3, BX
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+back:
+ ADDL BX, DI
+ ADDL BX, SI
+ SUBL $4, DI
+ SUBL $4, SI
+ STD
+/*
+ * copy whole longs
+ */
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; MOVSL
+/*
+ * copy the rest, by bytes
+ */
+ ADDL $3, DI
+ ADDL $3, SI
+ MOVL BX, CX
+ REP; MOVSB
+
+ MOVL p+0(FP),AX
+ RET
diff --git a/libkern/memmove-68000.s b/libkern/memmove-68000.s
new file mode 100644
index 00000000..efb0853e
--- /dev/null
+++ b/libkern/memmove-68000.s
@@ -0,0 +1,124 @@
+ TEXT memmove(SB), $0
+ BRA move
+
+ TEXT memcpy(SB), $0
+move:
+
+ MOVL n+8(FP), R0 /* count */
+ BEQ return
+ BGT ok
+ MOVL 0, R0
+ok:
+ MOVL s1+0(FP), A2 /* dest pointer */
+ MOVL s2+4(FP), A1 /* source pointer */
+
+ CMPL A2,A1
+ BHI back
+
+/*
+ * byte-at-a-time foreward copy to
+ * get source (A1) alligned.
+ */
+f1:
+ MOVL A1, R1
+ ANDL $3, R1
+ BEQ f2
+ SUBL $1, R0
+ BLT return
+ MOVB (A1)+, (A2)+
+ BRA f1
+
+/*
+ * check that dest is alligned
+ * if not, just go byte-at-a-time
+ */
+f2:
+ MOVL A2, R1
+ ANDL $3, R1
+ BEQ f3
+ SUBL $1, R0
+ BLT return
+ BRA f5
+/*
+ * quad-long-at-a-time forward copy
+ */
+f3:
+ SUBL $16, R0
+ BLT f4
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ MOVL (A1)+, (A2)+
+ BRA f3
+
+/*
+ * cleanup byte-at-a-time
+ */
+f4:
+ ADDL $15, R0
+ BLT return
+f5:
+ MOVB (A1)+, (A2)+
+ SUBL $1, R0
+ BGE f5
+ BRA return
+
+return:
+ MOVL s1+0(FP),R0
+ RTS
+
+/*
+ * everything the same, but
+ * copy backwards
+ */
+back:
+ ADDL R0, A1
+ ADDL R0, A2
+
+/*
+ * byte-at-a-time backward copy to
+ * get source (A1) alligned.
+ */
+b1:
+ MOVL A1, R1
+ ANDL $3, R1
+ BEQ b2
+ SUBL $1, R0
+ BLT return
+ MOVB -(A1), -(A2)
+ BRA b1
+
+/*
+ * check that dest is alligned
+ * if not, just go byte-at-a-time
+ */
+b2:
+ MOVL A2, R1
+ ANDL $3, R1
+ BEQ b3
+ SUBL $1, R0
+ BLT return
+ BRA b5
+/*
+ * quad-long-at-a-time backward copy
+ */
+b3:
+ SUBL $16, R0
+ BLT b4
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ MOVL -(A1), -(A2)
+ BRA b3
+
+/*
+ * cleanup byte-at-a-time backward
+ */
+b4:
+ ADDL $15, R0
+ BLT return
+b5:
+ MOVB -(A1), -(A2)
+ SUBL $1, R0
+ BGE b5
+ BRA return
diff --git a/libkern/memmove-arm.s b/libkern/memmove-arm.s
new file mode 100644
index 00000000..8e28200a
--- /dev/null
+++ b/libkern/memmove-arm.s
@@ -0,0 +1,223 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT memcpy(SB), $0
+TEXT memmove(SB), $-4
+_memmove:
+ MOVW R(TS), to+0(FP) /* need to save for return value */
+ MOVW from+4(FP), R(FROM)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TS), R(TE) /* to end pointer */
+
+ CMP R(FROM), R(TS)
+ BLS _forward
+
+_back:
+ ADD R(N), R(FROM) /* from end pointer */
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _b1tail
+
+_b4align: /* align destination on 4 */
+ AND.S $3, R(TE), R(TMP)
+ BEQ _b4aligned
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b4align
+
+_b4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _bunaligned
+
+ ADD $31, R(TS), R(TMP) /* do 32-byte chunks if possible */
+_b32loop:
+ CMP R(TMP), R(TE)
+ BLS _b4tail
+
+ MOVM.DB.W (R(FROM)), [R4-R11]
+ MOVM.DB.W [R4-R11], (R(TE))
+ B _b32loop
+
+_b4tail: /* do remaining words if possible */
+ ADD $3, R(TS), R(TMP)
+_b4loop:
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ MOVW.W -4(R(FROM)), R(TMP1) /* pre-indexed */
+ MOVW.W R(TMP1), -4(R(TE)) /* pre-indexed */
+ B _b4loop
+
+_b1tail: /* remaining bytes */
+ CMP R(TE), R(TS)
+ BEQ _return
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b1tail
+
+_forward:
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _f1tail
+
+_f4align: /* align destination on 4 */
+ AND.S $3, R(TS), R(TMP)
+ BEQ _f4aligned
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f4align
+
+_f4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _funaligned
+
+ SUB $31, R(TE), R(TMP) /* do 32-byte chunks if possible */
+_f32loop:
+ CMP R(TMP), R(TS)
+ BHS _f4tail
+
+ MOVM.IA.W (R(FROM)), [R4-R11]
+ MOVM.IA.W [R4-R11], (R(TS))
+ B _f32loop
+
+_f4tail:
+ SUB $3, R(TE), R(TMP) /* do remaining words if possible */
+_f4loop:
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ MOVW.P 4(R(FROM)), R(TMP1) /* implicit write back */
+ MOVW.P R4, 4(R(TS)) /* implicit write back */
+ B _f4loop
+
+_f1tail:
+ CMP R(TS), R(TE)
+ BEQ _return
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f1tail
+
+_return:
+ MOVW to+0(FP), R0
+ RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 6
+
+BR0 = 7
+BW0 = 8
+BR1 = 8
+BW1 = 9
+BR2 = 9
+BW2 = 10
+BR3 = 10
+BW3 = 11
+
+_bunaligned:
+ CMP $2, R(TMP) /* is R(TMP) < 2 ? */
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n)<<24)|(R(n-1)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $1, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n)<<16)|(R(n-1)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n)<<8)|(R(n-1)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $3, R(OFFSET)
+
+ ADD $16, R(TS), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW (R(FROM)), R(BR0) /* prime first block register */
+
+_bu16loop:
+ CMP R(TMP), R(TE)
+ BLS _bu1tail
+
+ MOVW R(BR0)<<R(LSHIFT), R(BW3)
+ MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+ ORR R(BR3)>>R(RSHIFT), R(BW3)
+
+ MOVW R(BR3)<<R(LSHIFT), R(BW2)
+ ORR R(BR2)>>R(RSHIFT), R(BW2)
+
+ MOVW R(BR2)<<R(LSHIFT), R(BW1)
+ ORR R(BR1)>>R(RSHIFT), R(BW1)
+
+ MOVW R(BR1)<<R(LSHIFT), R(BW0)
+ ORR R(BR0)>>R(RSHIFT), R(BW0)
+
+ MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+ B _bu16loop
+
+_bu1tail:
+ ADD R(OFFSET), R(FROM)
+ B _b1tail
+
+FW0 = 7
+FR0 = 8
+FW1 = 8
+FR1 = 9
+FW2 = 9
+FR2 = 10
+FW3 = 10
+FR3 = 11
+
+_funaligned:
+ CMP $2, R(TMP)
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n+1)<<24)|(R(n)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $3, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n+1)<<16)|(R(n)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n+1)<<8)|(R(n)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $1, R(OFFSET)
+
+ SUB $16, R(TE), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW.P 4(R(FROM)), R(FR3) /* prime last block register, implicit write back */
+
+_fu16loop:
+ CMP R(TMP), R(TS)
+ BHS _fu1tail
+
+ MOVW R(FR3)>>R(RSHIFT), R(FW0)
+ MOVM.IA.W (R(FROM)), [R(FR0)-R(FR3)]
+ ORR R(FR0)<<R(LSHIFT), R(FW0)
+
+ MOVW R(FR0)>>R(RSHIFT), R(FW1)
+ ORR R(FR1)<<R(LSHIFT), R(FW1)
+
+ MOVW R(FR1)>>R(RSHIFT), R(FW2)
+ ORR R(FR2)<<R(LSHIFT), R(FW2)
+
+ MOVW R(FR2)>>R(RSHIFT), R(FW3)
+ ORR R(FR3)<<R(LSHIFT), R(FW3)
+
+ MOVM.IA.W [R(FW0)-R(FW3)], (R(TS))
+ B _fu16loop
+
+_fu1tail:
+ SUB R(OFFSET), R(FROM)
+ B _f1tail
diff --git a/libkern/memmove-mips.s b/libkern/memmove-mips.s
new file mode 100644
index 00000000..c14d2a82
--- /dev/null
+++ b/libkern/memmove-mips.s
@@ -0,0 +1,237 @@
+ TEXT memmove(SB), $0
+
+ JMP move
+
+ TEXT memcpy(SB), $0
+move:
+ MOVW R1, s1+0(FP)
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW R1, R4 /* R4 is to-pointer */
+ SGT R0, R3, R5
+ BEQ R5, ok
+ MOVW (R0), R0 /* abort if negative count */
+ok:
+ MOVW s2+4(FP), R5 /* R5 is from-pointer */
+ ADDU R3,R5, R7 /* R7 is end from-pointer */
+ ADDU R3,R4, R6 /* R6 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ SGT $4,R3, R2
+ SGTU R4,R5, R1
+ BNE R1, back
+
+/*
+ * if not at least 4 chars,
+ * don't even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ BNE R2, fout
+
+
+/*
+ * byte at a time to word align destination
+ */
+f1:
+ AND $3,R4, R1
+ BEQ R1, f2
+ MOVB 0(R5), R8
+ ADDU $1, R5
+ MOVB R8, 0(R4)
+ ADDU $1, R4
+ JMP f1
+
+/*
+ * test if source is now word aligned
+ */
+f2:
+ AND $3, R5, R1
+ BNE R1, fun2
+/*
+ * turn R3 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R6 is smaller than R7 --
+ * there are problems if R7 is 0.
+ */
+ ADDU $-15,R6, R3
+f3:
+ SGTU R3,R4, R1
+ BEQ R1, f4
+ MOVW 0(R5), R8
+ MOVW 4(R5), R9
+ MOVW R8, 0(R4)
+ MOVW 8(R5), R8
+ MOVW R9, 4(R4)
+ MOVW 12(R5), R9
+ ADDU $16, R5
+ MOVW R8, 8(R4)
+ MOVW R9, 12(R4)
+ ADDU $16, R4
+ JMP f3
+
+/*
+ * turn R3 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+ ADDU $-3,R6, R3
+f5:
+ SGTU R3,R4, R1
+ BEQ R1, fout
+ MOVW 0(R5), R8
+ ADDU $4, R5
+ MOVW R8, 0(R4)
+ ADDU $4, R4
+ JMP f5
+
+/*
+ * forward copy, unaligned
+ * turn R3 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R6 is smaller than R7 --
+ * there are problems if R7 is 0.
+ */
+fun2:
+ ADDU $-15,R6, R3
+fun3:
+ SGTU R3,R4, R1
+ BEQ R1, fun4
+ MOVWL 0(R5), R8
+ MOVWR 3(R5), R8
+ MOVWL 4(R5), R9
+ MOVWR 7(R5), R9
+ MOVW R8, 0(R4)
+ MOVWL 8(R5), R8
+ MOVWR 11(R5), R8
+ MOVW R9, 4(R4)
+ MOVWL 12(R5), R9
+ MOVWR 15(R5), R9
+ ADDU $16, R5
+ MOVW R8, 8(R4)
+ MOVW R9, 12(R4)
+ ADDU $16, R4
+ JMP fun3
+
+/*
+ * turn R3 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+fun4:
+ ADDU $-3,R6, R3
+fun5:
+ SGTU R3,R4, R1
+ BEQ R1, fout
+ MOVWL 0(R5), R8
+ MOVWR 3(R5), R8
+ ADDU $4, R5
+ MOVW R8, 0(R4)
+ ADDU $4, R4
+ JMP fun5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+ BEQ R7,R5, ret
+ MOVB 0(R5), R8
+ ADDU $1, R5
+ MOVB R8, 0(R4)
+ ADDU $1, R4
+ JMP fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ BNE R2, bout
+b1:
+ AND $3,R6, R1
+ BEQ R1, b2
+ MOVB -1(R7), R8
+ ADDU $-1, R7
+ MOVB R8, -1(R6)
+ ADDU $-1, R6
+ JMP b1
+
+b2:
+ AND $3, R7, R1
+ BNE R1, bun2
+
+ ADDU $15,R5, R3
+b3:
+ SGTU R7,R3, R1
+ BEQ R1, b4
+ MOVW -4(R7), R8
+ MOVW -8(R7), R9
+ MOVW R8, -4(R6)
+ MOVW -12(R7), R8
+ MOVW R9, -8(R6)
+ MOVW -16(R7), R9
+ ADDU $-16, R7
+ MOVW R8, -12(R6)
+ MOVW R9, -16(R6)
+ ADDU $-16, R6
+ JMP b3
+b4:
+ ADDU $3,R5, R3
+b5:
+ SGTU R7,R3, R1
+ BEQ R1, bout
+ MOVW -4(R7), R8
+ ADDU $-4, R7
+ MOVW R8, -4(R6)
+ ADDU $-4, R6
+ JMP b5
+
+bun2:
+ ADDU $15,R5, R3
+bun3:
+ SGTU R7,R3, R1
+ BEQ R1, bun4
+ MOVWL -4(R7), R8
+ MOVWR -1(R7), R8
+ MOVWL -8(R7), R9
+ MOVWR -5(R7), R9
+ MOVW R8, -4(R6)
+ MOVWL -12(R7), R8
+ MOVWR -9(R7), R8
+ MOVW R9, -8(R6)
+ MOVWL -16(R7), R9
+ MOVWR -13(R7), R9
+ ADDU $-16, R7
+ MOVW R8, -12(R6)
+ MOVW R9, -16(R6)
+ ADDU $-16, R6
+ JMP bun3
+
+bun4:
+ ADDU $3,R5, R3
+bun5:
+ SGTU R7,R3, R1
+ BEQ R1, bout
+ MOVWL -4(R7), R8
+ MOVWR -1(R7), R8
+ ADDU $-4, R7
+ MOVW R8, -4(R6)
+ ADDU $-4, R6
+ JMP bun5
+
+bout:
+ BEQ R7,R5, ret
+ MOVB -1(R7), R8
+ ADDU $-1, R7
+ MOVB R8, -1(R6)
+ ADDU $-1, R6
+ JMP bout
+
+ret:
+ MOVW s1+0(FP), R1
+ RET
+ END
diff --git a/libkern/memmove-power.s b/libkern/memmove-power.s
new file mode 100644
index 00000000..1b27e5d6
--- /dev/null
+++ b/libkern/memmove-power.s
@@ -0,0 +1,170 @@
+#define BDNZ BC 16,0,
+ TEXT memcpy(SB), $0
+ BR move
+
+ TEXT memmove(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+ MOVW R3, s1+0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW R3, R10 /* R10 is to-pointer */
+ CMP R9, $0
+ BEQ ret
+ BLT trap
+ MOVW s2+4(FP), R11 /* R11 is from-pointer */
+
+/*
+ * if no more than 16 bytes, just use one lsw/stsw
+ */
+ CMP R9, $16
+ BLE fout
+
+ ADD R9,R11, R13 /* R13 is end from-pointer */
+ ADD R9,R10, R12 /* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ CMPU R10, R11
+ BGT back
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R10,R11, R7
+ ANDCC $3,R7
+ BNE fbad
+
+/*
+ * move a few bytes to align pointers
+ */
+ ANDCC $3,R10,R7
+ BEQ f2
+ SUBC R7, $4, R7
+ SUB R7, R9
+ MOVW R7, XER
+ LSW (R11), R16
+ ADD R7, R11
+ STSW R16, (R10)
+ ADD R7, R10
+
+/*
+ * turn R14 into doubleword count
+ * copy 16 bytes at a time while there's room.
+ */
+f2:
+ SRAWCC $4, R9, R14
+ BLE fout
+ MOVW R14, CTR
+ SUB $4, R11
+ SUB $4, R10
+f3:
+ MOVWU 4(R11), R16
+ MOVWU R16, 4(R10)
+ MOVWU 4(R11), R17
+ MOVWU R17, 4(R10)
+ MOVWU 4(R11), R16
+ MOVWU R16, 4(R10)
+ MOVWU 4(R11), R17
+ MOVWU R17, 4(R10)
+ BDNZ f3
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+ ADD $4, R11
+ ADD $4, R10
+
+/*
+ * move up to 16 bytes through R16 .. R19; aligned and unaligned
+ */
+fout:
+ MOVW R9, XER
+ LSW (R11), R16
+ STSW R16, (R10)
+ BR ret
+
+/*
+ * loop for unaligned copy, then copy up to 15 remaining bytes
+ */
+fbad:
+ SRAWCC $4, R9, R14
+ BLE f6
+ MOVW R14, CTR
+f5:
+ LSW (R11), $16, R16
+ ADD $16, R11
+ STSW R16, $16, (R10)
+ ADD $16, R10
+ BDNZ f5
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+f6:
+ MOVW R9, XER
+ LSW (R11), R16
+ STSW R16, (R10)
+ BR ret
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ CMP R9, $4
+ BLT bout
+
+ XOR R12,R13, R7
+ ANDCC $3,R7
+ BNE bout
+b1:
+ ANDCC $3,R13, R7
+ BEQ b2
+ MOVBZU -1(R13), R16
+ MOVBZU R16, -1(R12)
+ SUB $1, R9
+ BR b1
+b2:
+ SRAWCC $4, R9, R14
+ BLE b4
+ MOVW R14, CTR
+b3:
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ MOVWU -4(R13), R17
+ MOVWU R17, -4(R12)
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ MOVWU -4(R13), R17
+ MOVWU R17, -4(R12)
+ BDNZ b3
+ RLWNMCC $0, R9, $15, R9 /* residue */
+ BEQ ret
+b4:
+ SRAWCC $2, R9, R14
+ BLE bout
+ MOVW R14, CTR
+b5:
+ MOVWU -4(R13), R16
+ MOVWU R16, -4(R12)
+ BDNZ b5
+ RLWNMCC $0, R9, $3, R9 /* residue */
+ BEQ ret
+
+bout:
+ CMPU R13, R11
+ BLE ret
+ MOVBZU -1(R13), R16
+ MOVBZU R16, -1(R12)
+ BR bout
+
+trap:
+/* MOVW $0, R0 */
+ MOVW R0, 0(R0)
+
+ret:
+ MOVW s1+0(FP), R3
+ RETURN
diff --git a/libkern/memmove-sparc.s b/libkern/memmove-sparc.s
new file mode 100644
index 00000000..1295209a
--- /dev/null
+++ b/libkern/memmove-sparc.s
@@ -0,0 +1,162 @@
+ TEXT memmove(SB), $0
+ JMP move
+
+ TEXT memcpy(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+ MOVW R7, s1+0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW R7, R10 /* R10 is to-pointer */
+ SUBCC R0,R9, R0
+ BGE ok
+ MOVW 0(R0), R0
+
+ok:
+ MOVW s2+4(FP), R11 /* R11 is from-pointer */
+ ADD R9,R11, R13 /* R13 is end from-pointer */
+ ADD R9,R10, R12 /* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+ SUBCC R11,R10, R0
+ BGU back
+
+/*
+ * if not at least 8 chars,
+ * dont even mess around.
+ * 7 chars to guarantee any
+ * rounding up to a word
+ * boundary and 8 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SUBCC $8,R9, R0
+ BL fout
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R10,R11, R7
+ ANDCC $7,R7, R0
+ BNE fout
+
+/*
+ * byte at a time to double align
+ */
+f1:
+ ANDCC $7,R10, R0
+ BE f2
+ MOVB 0(R11), R16
+ ADD $1, R11
+ MOVB R16, 0(R10)
+ ADD $1, R10
+ JMP f1
+
+/*
+ * turn R9 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R12 is smaller than R13 --
+ * there are problems if R13 is 0.
+ */
+f2:
+ SUB $15,R12, R9
+f3:
+ SUBCC R10,R9, R0
+ BLEU f4
+ MOVD 0(R11), R16
+ MOVD R16, 0(R10)
+ MOVD 8(R11), R16
+ ADD $16, R11
+ MOVD R16, 8(R10)
+ ADD $16, R10
+ JMP f3
+
+/*
+ * turn R9 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+ SUB $3,R12, R9
+f5:
+ SUBCC R10,R9, R0
+ BLEU fout
+ MOVW 0(R11), R16
+ ADD $4, R11
+ MOVW R16, 0(R10)
+ ADD $4, R10
+ JMP f5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+ SUBCC R11,R13, R0
+ BLEU ret
+ MOVB 0(R11), R16
+ ADD $1, R11
+ MOVB R16, 0(R10)
+ ADD $1, R10
+ JMP fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+ SUBCC $8,R9, R0
+ BL bout
+
+ XOR R12,R13, R7
+ ANDCC $7,R7, R0
+ BNE bout
+b1:
+ ANDCC $7,R13, R0
+ BE b2
+ MOVB -1(R13), R16
+ SUB $1, R13
+ MOVB R16, -1(R12)
+ SUB $1, R12
+ JMP b1
+b2:
+ ADD $15,R11, R9
+b3:
+ SUBCC R9,R13, R0
+ BLEU b4
+
+ MOVD -8(R13), R16
+ MOVD R16, -8(R12)
+ MOVD -16(R13), R16
+ SUB $16, R13
+ MOVD R16, -16(R12);
+ SUB $16, R12
+ JMP b3
+b4:
+ ADD $3,R11, R9
+b5:
+ SUBCC R9,R13, R0
+ BLEU bout
+ MOVW -4(R13), R16
+ SUB $4, R13
+ MOVW R16, -4(R12)
+ SUB $4, R12
+ JMP b5
+
+bout:
+ SUBCC R11,R13, R0
+ BLEU ret
+ MOVB -1(R13), R16
+ SUB $1, R13
+ MOVB R16, -1(R12)
+ SUB $1, R12
+ JMP bout
+
+ret:
+ MOVW s1+0(FP), R7
+ RETURN
diff --git a/libkern/memmove-thumb.s b/libkern/memmove-thumb.s
new file mode 100644
index 00000000..8e28200a
--- /dev/null
+++ b/libkern/memmove-thumb.s
@@ -0,0 +1,223 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT memcpy(SB), $0
+TEXT memmove(SB), $-4
+_memmove:
+ MOVW R(TS), to+0(FP) /* need to save for return value */
+ MOVW from+4(FP), R(FROM)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TS), R(TE) /* to end pointer */
+
+ CMP R(FROM), R(TS)
+ BLS _forward
+
+_back:
+ ADD R(N), R(FROM) /* from end pointer */
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _b1tail
+
+_b4align: /* align destination on 4 */
+ AND.S $3, R(TE), R(TMP)
+ BEQ _b4aligned
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b4align
+
+_b4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _bunaligned
+
+ ADD $31, R(TS), R(TMP) /* do 32-byte chunks if possible */
+_b32loop:
+ CMP R(TMP), R(TE)
+ BLS _b4tail
+
+ MOVM.DB.W (R(FROM)), [R4-R11]
+ MOVM.DB.W [R4-R11], (R(TE))
+ B _b32loop
+
+_b4tail: /* do remaining words if possible */
+ ADD $3, R(TS), R(TMP)
+_b4loop:
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ MOVW.W -4(R(FROM)), R(TMP1) /* pre-indexed */
+ MOVW.W R(TMP1), -4(R(TE)) /* pre-indexed */
+ B _b4loop
+
+_b1tail: /* remaining bytes */
+ CMP R(TE), R(TS)
+ BEQ _return
+
+ MOVBU.W -1(R(FROM)), R(TMP) /* pre-indexed */
+ MOVBU.W R(TMP), -1(R(TE)) /* pre-indexed */
+ B _b1tail
+
+_forward:
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _f1tail
+
+_f4align: /* align destination on 4 */
+ AND.S $3, R(TS), R(TMP)
+ BEQ _f4aligned
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f4align
+
+_f4aligned: /* is source now aligned? */
+ AND.S $3, R(FROM), R(TMP)
+ BNE _funaligned
+
+ SUB $31, R(TE), R(TMP) /* do 32-byte chunks if possible */
+_f32loop:
+ CMP R(TMP), R(TS)
+ BHS _f4tail
+
+ MOVM.IA.W (R(FROM)), [R4-R11]
+ MOVM.IA.W [R4-R11], (R(TS))
+ B _f32loop
+
+_f4tail:
+ SUB $3, R(TE), R(TMP) /* do remaining words if possible */
+_f4loop:
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ MOVW.P 4(R(FROM)), R(TMP1) /* implicit write back */
+ MOVW.P R4, 4(R(TS)) /* implicit write back */
+ B _f4loop
+
+_f1tail:
+ CMP R(TS), R(TE)
+ BEQ _return
+
+ MOVBU.P 1(R(FROM)), R(TMP) /* implicit write back */
+ MOVBU.P R(TMP), 1(R(TS)) /* implicit write back */
+ B _f1tail
+
+_return:
+ MOVW to+0(FP), R0
+ RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 6
+
+BR0 = 7
+BW0 = 8
+BR1 = 8
+BW1 = 9
+BR2 = 9
+BW2 = 10
+BR3 = 10
+BW3 = 11
+
+_bunaligned:
+ CMP $2, R(TMP) /* is R(TMP) < 2 ? */
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n)<<24)|(R(n-1)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $1, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n)<<16)|(R(n-1)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n)<<8)|(R(n-1)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $3, R(OFFSET)
+
+ ADD $16, R(TS), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW (R(FROM)), R(BR0) /* prime first block register */
+
+_bu16loop:
+ CMP R(TMP), R(TE)
+ BLS _bu1tail
+
+ MOVW R(BR0)<<R(LSHIFT), R(BW3)
+ MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+ ORR R(BR3)>>R(RSHIFT), R(BW3)
+
+ MOVW R(BR3)<<R(LSHIFT), R(BW2)
+ ORR R(BR2)>>R(RSHIFT), R(BW2)
+
+ MOVW R(BR2)<<R(LSHIFT), R(BW1)
+ ORR R(BR1)>>R(RSHIFT), R(BW1)
+
+ MOVW R(BR1)<<R(LSHIFT), R(BW0)
+ ORR R(BR0)>>R(RSHIFT), R(BW0)
+
+ MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+ B _bu16loop
+
+_bu1tail:
+ ADD R(OFFSET), R(FROM)
+ B _b1tail
+
+FW0 = 7
+FR0 = 8
+FW1 = 8
+FR1 = 9
+FW2 = 9
+FR2 = 10
+FW3 = 10
+FR3 = 11
+
+_funaligned:
+ CMP $2, R(TMP)
+
+ MOVW.LT $8, R(RSHIFT) /* (R(n+1)<<24)|(R(n)>>8) */
+ MOVW.LT $24, R(LSHIFT)
+ MOVW.LT $3, R(OFFSET)
+
+ MOVW.EQ $16, R(RSHIFT) /* (R(n+1)<<16)|(R(n)>>16) */
+ MOVW.EQ $16, R(LSHIFT)
+ MOVW.EQ $2, R(OFFSET)
+
+ MOVW.GT $24, R(RSHIFT) /* (R(n+1)<<8)|(R(n)>>24) */
+ MOVW.GT $8, R(LSHIFT)
+ MOVW.GT $1, R(OFFSET)
+
+ SUB $16, R(TE), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ AND $~0x03, R(FROM) /* align source */
+ MOVW.P 4(R(FROM)), R(FR3) /* prime last block register, implicit write back */
+
+_fu16loop:
+ CMP R(TMP), R(TS)
+ BHS _fu1tail
+
+ MOVW R(FR3)>>R(RSHIFT), R(FW0)
+ MOVM.IA.W (R(FROM)), [R(FR0)-R(FR3)]
+ ORR R(FR0)<<R(LSHIFT), R(FW0)
+
+ MOVW R(FR0)>>R(RSHIFT), R(FW1)
+ ORR R(FR1)<<R(LSHIFT), R(FW1)
+
+ MOVW R(FR1)>>R(RSHIFT), R(FW2)
+ ORR R(FR2)<<R(LSHIFT), R(FW2)
+
+ MOVW R(FR2)>>R(RSHIFT), R(FW3)
+ ORR R(FR3)<<R(LSHIFT), R(FW3)
+
+ MOVM.IA.W [R(FW0)-R(FW3)], (R(TS))
+ B _fu16loop
+
+_fu1tail:
+ SUB R(OFFSET), R(FROM)
+ B _f1tail
diff --git a/libkern/memmove.c b/libkern/memmove.c
new file mode 100644
index 00000000..a1455f51
--- /dev/null
+++ b/libkern/memmove.c
@@ -0,0 +1,43 @@
+#include <lib9.h>
+
+/* for testing only */
+void*
+memcpy(void *a1, void *a2, ulong n)
+{
+ return memmove(a1, a2, n);
+}
+
+void*
+memmove(void *a1, void *a2, ulong n)
+{
+ int m = (int)n;
+ uchar *s, *d;
+
+ d = a1;
+ s = a2;
+ if(d > s){
+ s += m;
+ d += m;
+ while(--m >= 0)
+ *--d = *--s;
+ }
+ else{
+ while(--m >= 0)
+ *d++ = *s++;
+ }
+ return a1;
+}
+
+/*
+void
+memset(void *a1, int c, ulong n)
+{
+ int m = (int)n;
+ uchar *d;
+
+ d = a1;
+ while(--m >= 0)
+ *d++ = c;
+}
+*/
+
diff --git a/libkern/memset-386.s b/libkern/memset-386.s
new file mode 100644
index 00000000..dacb2f5f
--- /dev/null
+++ b/libkern/memset-386.s
@@ -0,0 +1,35 @@
+ TEXT memset(SB),$0
+
+ CLD
+ MOVL p+0(FP), DI
+ MOVBLZX c+4(FP), AX
+ MOVL n+8(FP), BX
+/*
+ * if not enough bytes, just copy
+ */
+ CMPL BX, $9
+ JLS c3
+/*
+ * build word in AX
+ */
+ MOVB AL, AH
+ MOVL AX, CX
+ SHLL $16, CX
+ ORL CX, AX
+/*
+ * copy whole longs
+ */
+c1:
+ MOVL BX, CX
+ SHRL $2, CX
+ ANDL $3, BX
+ REP; STOSL
+/*
+ * copy the rest, by bytes
+ */
+c3:
+ MOVL BX, CX
+ REP; STOSB
+ret:
+ MOVL p+0(FP),AX
+ RET
diff --git a/libkern/memset-68000.s b/libkern/memset-68000.s
new file mode 100644
index 00000000..318f61a7
--- /dev/null
+++ b/libkern/memset-68000.s
@@ -0,0 +1,57 @@
+ TEXT memset(SB), $0
+ MOVL n+8(FP), R0
+ BLE return
+ MOVL s1+0(FP), A1
+ CLRL R1
+ MOVB c+7(FP), R1
+ BEQ l1
+
+/*
+ * create 4 replicated copies
+ * of the byte in R1
+ */
+ MOVL R1, R2
+ ASLL $8, R2
+ ORL R2, R1
+ MOVL R1, R2
+ SWAP R2
+ ORL R2, R1
+
+/*
+ * byte-at-a-time until alligned
+ */
+l1:
+ MOVL A1, R1
+ ANDL $3, R1
+ BEQ l2
+ SUBL $1, R0
+ BLT return
+ MOVB R1, (A1)+
+ BRA l1
+
+/*
+ * quad-long-at-a-time set
+ */
+l2:
+ SUBL $16, R0
+ BLT l3
+ MOVL R1, (A1)+
+ MOVL R1, (A1)+
+ MOVL R1, (A1)+
+ MOVL R1, (A1)+
+ BRA l2
+
+/*
+ * cleanup byte-at-a-time
+ */
+l3:
+ ADDL $15, R0
+ BLT return
+l4:
+ MOVB R1, (A1)+
+ SUBL $1, R0
+ BGE l4
+
+return:
+ MOVL s1+0(FP),R0
+ RTS
diff --git a/libkern/memset-arm.s b/libkern/memset-arm.s
new file mode 100644
index 00000000..92355c11
--- /dev/null
+++ b/libkern/memset-arm.s
@@ -0,0 +1,66 @@
+TO = 1
+TOE = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+
+TEXT memset(SB), $0
+ MOVW R0, R(TO)
+ MOVW data+4(FP), R(4)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TO), R(TOE) /* to end pointer */
+
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _1tail
+
+ AND $0xFF, R(4) /* it's a byte */
+ SLL $8, R(4), R(TMP) /* replicate to a word */
+ ORR R(TMP), R(4)
+ SLL $16, R(4), R(TMP)
+ ORR R(TMP), R(4)
+
+_4align: /* align on 4 */
+ AND.S $3, R(TO), R(TMP)
+ BEQ _4aligned
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _4align
+
+_4aligned:
+ SUB $31, R(TOE), R(TMP) /* do 32-byte chunks if possible */
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVW R4, R5 /* replicate */
+ MOVW R4, R6
+ MOVW R4, R7
+ MOVW R4, R8
+ MOVW R4, R9
+ MOVW R4, R10
+ MOVW R4, R11
+
+_f32loop:
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVM.IA.W [R4-R11], (R(TO))
+ B _f32loop
+
+_4tail:
+ SUB $3, R(TOE), R(TMP) /* do remaining words if possible */
+_4loop:
+ CMP R(TMP), R(TO)
+ BHS _1tail
+
+ MOVW.P R(4), 4(R(TO)) /* implicit write back */
+ B _4loop
+
+_1tail:
+ CMP R(TO), R(TOE)
+ BEQ _return
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _1tail
+
+_return:
+ RET
diff --git a/libkern/memset-mips.s b/libkern/memset-mips.s
new file mode 100644
index 00000000..8c9467f4
--- /dev/null
+++ b/libkern/memset-mips.s
@@ -0,0 +1,88 @@
+ TEXT memset(SB),$12
+MOVW R1, 0(FP)
+
+/*
+ * performance:
+ * about 1us/call and 28mb/sec
+ */
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW p+0(FP), R4 /* R4 is pointer */
+ MOVW c+4(FP), R5 /* R5 is char */
+ ADDU R3,R4, R6 /* R6 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SGT $4,R3, R1
+ BNE R1, out
+
+/*
+ * turn R5 into a word of characters
+ */
+ AND $0xff, R5
+ SLL $8,R5, R1
+ OR R1, R5
+ SLL $16,R5, R1
+ OR R1, R5
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+ AND $3,R4, R1
+ BEQ R1, l2
+ MOVB R5, 0(R4)
+ ADDU $1, R4
+ JMP l1
+
+/*
+ * turn R3 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+ ADDU $-15,R6, R3
+l3:
+ SGTU R3,R4, R1
+ BEQ R1, l4
+ MOVW R5, 0(R4)
+ MOVW R5, 4(R4)
+ ADDU $16, R4
+ MOVW R5, -8(R4)
+ MOVW R5, -4(R4)
+ JMP l3
+
+/*
+ * turn R3 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+ ADDU $-3,R6, R3
+l5:
+ SGTU R3,R4, R1
+ BEQ R1, out
+ MOVW R5, 0(R4)
+ ADDU $4, R4
+ JMP l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+ SGTU R6,R4 ,R1
+ BEQ R1, ret
+ MOVB R5, 0(R4)
+ ADDU $1, R4
+ JMP out
+
+ret:
+ MOVW s1+0(FP), R1
+ RET
+ END
diff --git a/libkern/memset-power.s b/libkern/memset-power.s
new file mode 100644
index 00000000..fa6e8d92
--- /dev/null
+++ b/libkern/memset-power.s
@@ -0,0 +1,73 @@
+ TEXT memset(SB),$0
+#define BDNZ BC 16,0,
+ MOVW R3, p+0(FP) /* R3 is pointer */
+
+/*
+ * performance:
+ * about 100mbytes/sec (8k blocks) on a 603/105 without L2 cache
+ * drops to 40mbytes/sec (10k blocks) and 28mbytes/sec with 32k blocks
+ */
+
+ MOVW n+8(FP), R4 /* R4 is count */
+ CMP R4, $0
+ BLE ret
+ MOVW c+4(FP), R5 /* R5 is char */
+
+/*
+ * create 16 copies of c in R5 .. R8
+ */
+ RLWNM $0, R5, $0xff, R5
+ RLWMI $8, R5, $0xff00, R5
+ RLWMI $16, R5, $0xffff0000, R5
+ MOVW R5, R6
+ MOVW R5, R7
+ MOVW R5, R8
+
+/*
+ * let STSW do the work for 16 characters or less; aligned and unaligned
+ */
+ CMP R4, $16
+ BLE out
+
+/*
+ * store enough bytes to align pointer
+ */
+ ANDCC $7,R3, R9
+ BEQ l2
+ SUBC R9, $8, R9
+ MOVW R9, XER
+ STSW R5, (R3)
+ ADD R9, R3
+ SUB R9, R4
+
+/*
+ * store 16 at a time while there's room
+ * STSW was used here originally, but it's `completion serialised'
+ */
+l2:
+ SRAWCC $4, R4, R9
+ BLE out
+ MOVW R9, CTR
+l3:
+ MOVW R5, 0(R3)
+ ADD $8, R3, R10
+ MOVW R6, 4(R3)
+ MOVW R7, 0(R10)
+ ADD $8, R10, R3
+ MOVW R8, 4(R10)
+ BDNZ l3
+ RLWNMCC $0, R4, $15, R4 /* residue */
+ BEQ ret
+
+/*
+ * store up to 16 bytes from R5 .. R8; aligned and unaligned
+ */
+
+out:
+ MOVW R4, XER
+ STSW R5, (R3)
+
+ret:
+ MOVW 0(FP), R3
+ RETURN
+ END
diff --git a/libkern/memset-sparc.s b/libkern/memset-sparc.s
new file mode 100644
index 00000000..8c7b26c8
--- /dev/null
+++ b/libkern/memset-sparc.s
@@ -0,0 +1,88 @@
+ TEXT memset(SB),$0
+
+/*
+ * performance:
+ * (tba)
+ */
+
+MOVW R7, 0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW p+0(FP), R10 /* R10 is pointer */
+ MOVW c+4(FP), R11 /* R11 is char */
+ ADD R9,R10, R12 /* R12 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+ SUBCC $4,R9, R0
+ BL out
+
+/*
+ * turn R11 into a word of characters
+ */
+ AND $0xff, R11
+ SLL $8,R11, R7
+ OR R7, R11
+ SLL $16,R11, R7
+ OR R7, R11
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+ ANDCC $3,R10, R0
+ BE l2
+ MOVB R11, 0(R10)
+ ADD $1, R10
+ JMP l1
+
+/*
+ * turn R9 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+ ADD $-15,R12, R9
+ SUBCC R10,R9, R0
+ BLEU l4
+l3:
+ MOVW R11, 0(R10)
+ MOVW R11, 4(R10)
+ ADD $16, R10
+ SUBCC R10,R9, R0
+ MOVW R11, -8(R10)
+ MOVW R11, -4(R10)
+ BGU l3
+
+/*
+ * turn R9 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+ ADD $-3,R12, R9
+l5:
+ SUBCC R10,R9, R0
+ BLEU out
+ MOVW R11, 0(R10)
+ ADD $4, R10
+ JMP l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+ SUBCC R10,R12, R0
+ BLEU ret
+ MOVB R11, 0(R10)
+ ADD $1, R10
+ JMP out
+
+ret:
+ MOVW s1+0(FP), R7
+ RETURN
diff --git a/libkern/memset-thumb.s b/libkern/memset-thumb.s
new file mode 100644
index 00000000..92355c11
--- /dev/null
+++ b/libkern/memset-thumb.s
@@ -0,0 +1,66 @@
+TO = 1
+TOE = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+
+TEXT memset(SB), $0
+ MOVW R0, R(TO)
+ MOVW data+4(FP), R(4)
+ MOVW n+8(FP), R(N)
+
+ ADD R(N), R(TO), R(TOE) /* to end pointer */
+
+ CMP $4, R(N) /* need at least 4 bytes to copy */
+ BLT _1tail
+
+ AND $0xFF, R(4) /* it's a byte */
+ SLL $8, R(4), R(TMP) /* replicate to a word */
+ ORR R(TMP), R(4)
+ SLL $16, R(4), R(TMP)
+ ORR R(TMP), R(4)
+
+_4align: /* align on 4 */
+ AND.S $3, R(TO), R(TMP)
+ BEQ _4aligned
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _4align
+
+_4aligned:
+ SUB $31, R(TOE), R(TMP) /* do 32-byte chunks if possible */
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVW R4, R5 /* replicate */
+ MOVW R4, R6
+ MOVW R4, R7
+ MOVW R4, R8
+ MOVW R4, R9
+ MOVW R4, R10
+ MOVW R4, R11
+
+_f32loop:
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVM.IA.W [R4-R11], (R(TO))
+ B _f32loop
+
+_4tail:
+ SUB $3, R(TOE), R(TMP) /* do remaining words if possible */
+_4loop:
+ CMP R(TMP), R(TO)
+ BHS _1tail
+
+ MOVW.P R(4), 4(R(TO)) /* implicit write back */
+ B _4loop
+
+_1tail:
+ CMP R(TO), R(TOE)
+ BEQ _return
+
+ MOVBU.P R(4), 1(R(TO)) /* implicit write back */
+ B _1tail
+
+_return:
+ RET
diff --git a/libkern/memset.c b/libkern/memset.c
new file mode 100644
index 00000000..270fca25
--- /dev/null
+++ b/libkern/memset.c
@@ -0,0 +1,15 @@
+#include <lib9.h>
+
+void*
+memset(void *ap, int c, ulong n)
+{
+ char *p;
+ int m = (int)n;
+
+ p = ap;
+ while(m > 0) {
+ *p++ = c;
+ m--;
+ }
+ return ap;
+}
diff --git a/libkern/mkfile b/libkern/mkfile
new file mode 100644
index 00000000..9bb9d65e
--- /dev/null
+++ b/libkern/mkfile
@@ -0,0 +1,81 @@
+<../mkconfig
+
+LIB=libkern.a
+
+COMMONFILES=\
+ abort.$O\
+ abs.$O\
+ atol.$O\
+ charstod.$O\
+ cistrcmp.$O\
+ cistrncmp.$O\
+ cistrstr.$O\
+ cleanname.$O\
+ convD2M.$O\
+ convM2D.$O\
+ convM2S.$O\
+ convS2M.$O\
+ dofmt.$O\
+ exp.$O\
+ fcallfmt.$O\
+ floor.$O\
+ fmt.$O\
+ fmtprint.$O\
+ fmtquote.$O\
+ fmtstr.$O\
+ fmtvprint.$O\
+ getfields.$O\
+ log.$O\
+ memccpy.$O\
+ memchr.$O\
+ memcmp.$O\
+# netmkaddr.$O\
+ pow.$O\
+ pow10.$O\
+ qsort.$O\
+ rune.$O\
+ runestrlen.$O\
+ sin.$O\
+ seprint.$O\
+ smprint.$O\
+ snprint.$O\
+ sqrt.$O\
+ strcat.$O\
+ strcmp.$O\
+ strcpy.$O\
+ strdup.$O\
+ strecpy.$O\
+ strlen.$O\
+ strncmp.$O\
+ strncpy.$O\
+ strrchr.$O\
+ strstr.$O\
+ strtod.$O\
+ strtol.$O\
+ strtoll.$O\
+ strtoul.$O\
+ tokenize.$O\
+ toupper.$O\
+ u16.$O\
+ u32.$O\
+ u64.$O\
+ utfecpy.$O\
+ utflen.$O\
+ utfnlen.$O\
+ utfrrune.$O\
+ utfrune.$O\
+ vseprint.$O\
+ vsmprint.$O\
+ vsnprint.$O\
+
+<mkfile-$OBJTYPE #sets $TARGFILES
+
+OFILES= $COMMONFILES $TARGFILES
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+convD2M.$O: $ROOT/include/fcall.h
+convM2D.$O: $ROOT/include/fcall.h
+convM2S.$O: $ROOT/include/fcall.h
+convS2M.$O: $ROOT/include/fcall.h
+fcallfmt.$O: $ROOT/include/fcall.h
diff --git a/libkern/mkfile-386 b/libkern/mkfile-386
new file mode 100644
index 00000000..00c0fcd5
--- /dev/null
+++ b/libkern/mkfile-386
@@ -0,0 +1,12 @@
+#
+# 386-specific files
+#
+TARGFILES=\
+ frexp-386.$O\
+ getfcr-386.$O\
+ memmove-386.$O\
+ memset-386.$O\
+ nan-386.$O\
+ strchr-386.$O\
+ vlop-386.$O\
+ vlrt-386.$O\
diff --git a/libkern/mkfile-68000 b/libkern/mkfile-68000
new file mode 100644
index 00000000..dd5da424
--- /dev/null
+++ b/libkern/mkfile-68000
@@ -0,0 +1,12 @@
+#
+# 68000-specific files
+#
+TARGFILES=\
+ frexp-68000.$O\
+ getfcr-68000.$O\
+ memmove-68000.$O\
+ memset-68000.$O\
+ nan-68000.$O\
+ strchr-68000.$O\
+ muldiv-68000.$O\
+ vlrt-68000.$O\
diff --git a/libkern/mkfile-arm b/libkern/mkfile-arm
new file mode 100644
index 00000000..01af1112
--- /dev/null
+++ b/libkern/mkfile-arm
@@ -0,0 +1,13 @@
+#
+# arm-specific files
+#
+TARGFILES=\
+ frexp-arm.$O\
+ getfcr-arm.$O\
+ memmove-arm.$O\
+ memset-arm.$O\
+ nan-arm.$O\
+ strchr-arm.$O\
+ vlop-arm.$O\
+ vlrt-arm.$O\
+ div-arm.$O\
diff --git a/libkern/mkfile-mips b/libkern/mkfile-mips
new file mode 100644
index 00000000..088f915e
--- /dev/null
+++ b/libkern/mkfile-mips
@@ -0,0 +1,13 @@
+#
+# mips-specific files
+#
+TARGFILES=\
+ frexp-mips.$O\
+ getfcr-mips.$O\
+ memmove-mips.$O\
+ memset-mips.$O\
+ nan-mips.$O\
+ strchr-mips.$O\
+ vlop-mips.$O\
+ vlrt-mips.$O\
+
diff --git a/libkern/mkfile-power b/libkern/mkfile-power
new file mode 100644
index 00000000..aa616ca7
--- /dev/null
+++ b/libkern/mkfile-power
@@ -0,0 +1,13 @@
+#
+# power-specific files
+#
+TARGFILES=\
+ frexp-power.$O\
+ getfcr-power.$O\
+ memmove-power.$O\
+ memset-power.$O\
+ nan-power.$O\
+ strchr-power.$O\
+ vlop-power.$O\
+ vlrt-power.$O\
+
diff --git a/libkern/mkfile-sparc b/libkern/mkfile-sparc
new file mode 100644
index 00000000..465f88e7
--- /dev/null
+++ b/libkern/mkfile-sparc
@@ -0,0 +1,13 @@
+#
+# sparc-specific files
+#
+TARGFILES=\
+ frexp-sparc.$O\
+ getfcr-sparc.$O\
+ memmove-sparc.$O\
+ memset-sparc.$O\
+ nan-sparc.$O\
+ strchr-sparc.$O\
+ vlop-sparc.$O\
+ vlrt-sparc.$O\
+
diff --git a/libkern/mkfile-spim b/libkern/mkfile-spim
new file mode 100644
index 00000000..fe9a79f5
--- /dev/null
+++ b/libkern/mkfile-spim
@@ -0,0 +1,8 @@
+#
+# spim-specific files
+#
+TARGFILES=\
+ getfcr-spim.$O\
+ memmove-spim.$O\
+ memset-spim.$O\
+ strchr-spim.$O\
diff --git a/libkern/mkfile-thumb b/libkern/mkfile-thumb
new file mode 100644
index 00000000..4ccd1653
--- /dev/null
+++ b/libkern/mkfile-thumb
@@ -0,0 +1,12 @@
+#
+# thumb-specific files
+#
+TARGFILES=\
+ frexp-thumb.$O\
+ getfcr-thumb.$O\
+ memmove-thumb.$O\
+ memset-thumb.$O\
+ nan-thumb.$O\
+ strchr-thumb.$O\
+ vlop-thumb.$O\
+ vlrt-thumb.$O\
diff --git a/libkern/muldiv-68000.s b/libkern/muldiv-68000.s
new file mode 100644
index 00000000..10ef6f46
--- /dev/null
+++ b/libkern/muldiv-68000.s
@@ -0,0 +1,172 @@
+/*
+ * calls _divul with
+ * absolute value arguments
+ */
+TEXT _divsl(SB), $0
+ MOVL R0, TOS
+
+ MOVL b+4(FP), R0
+ BPL y1
+ NEGL R0
+ MOVL R0, TOS
+
+ MOVL a+0(FP), R0
+ BPL y3
+ NEGL R0
+ MOVL R0, TOS
+
+ /* neg/neg */
+ JSR _divul(SB)
+ MOVL TOS, R0
+ MOVL R0, a+0(FP)
+ MOVL TOS, R0
+ NEGL R0
+ MOVL R0, b+4(FP)
+ MOVL TOS, R0
+ RTS
+
+y1: MOVL R0, TOS
+
+ MOVL a+0(FP), R0
+ BPL y2
+ NEGL R0
+ MOVL R0, TOS
+
+ /* neg/pos */
+ JSR _divul(SB)
+ MOVL TOS, R0
+ NEGL R0
+ MOVL R0, a+0(FP)
+ MOVL TOS, R0
+ NEGL R0
+ MOVL R0, b+4(FP)
+ MOVL TOS, R0
+ RTS
+
+y2: MOVL R0, TOS
+
+ /* pos/pos */
+ JSR _divul(SB)
+ MOVL TOS, R0
+ MOVL R0, a+0(FP)
+ MOVL TOS, R0
+ MOVL R0, b+4(FP)
+ MOVL TOS, R0
+ RTS
+
+y3: MOVL R0, TOS
+
+ /* pos/neg */
+ JSR _divul(SB)
+ MOVL TOS, R0
+ NEGL R0
+ MOVL R0, a+0(FP)
+ MOVL TOS, R0
+ MOVL R0, b+4(FP)
+ MOVL TOS, R0
+ RTS
+
+/*
+ * for(i=1;; i++) {
+ * if(den & (1<<31))
+ * break;
+ * den <<= 1;
+ * }
+ *
+ * for(; i; i--) {
+ * quo <<= 1;
+ * if(num >= den) {
+ * num -= den;
+ * quo |= 1;
+ * }
+ * den >>= 1;
+ * }
+ */
+TEXT _divul(SB), $0
+ MOVL R0, TOS /* i */
+ MOVL R1, TOS /* num */
+ MOVL R2, TOS /* den */
+ MOVL R3, TOS /* quo */
+
+ MOVL $0, R0
+ MOVL $0, R3
+ MOVL a+0(FP), R1
+ MOVL b+4(FP), R2
+ BEQ xout
+ BMI x1
+
+ ADDL $1, R0
+ LSLL $1, R2
+ BPL -2(PC)
+
+x1: LSLL $1, R3
+ CMPL R1, R2
+ BCS 3(PC)
+ SUBL R2, R1
+ ORL $1, R3
+ LSRL $1, R2
+ DBMI R0, x1
+
+ MOVL R3, a+0(FP)
+ MOVL R1, b+4(FP)
+
+xout:
+ MOVL TOS, R3
+ MOVL TOS, R2
+ MOVL TOS, R1
+ MOVL TOS, R0
+ RTS
+
+/*
+ * x = 0;
+ * for(i=0; i<32; i++) {
+ * if(a & 1)
+ * x += b;
+ * a >>= 1;
+ * b <<= 1;
+ * }
+ * a = x;
+ */
+TEXT _mull(SB), $0
+ MOVL R0, TOS /* i */
+ MOVL R1, TOS /* a */
+ MOVL R2, TOS /* b */
+ MOVL R3, TOS /* x */
+
+ MOVL a+0(FP), R1
+ MOVL b+4(FP), R2
+ MOVL $32, R0
+ CLRL R3
+
+z1: ROTRL $1, R1
+ BCC 2(PC)
+ ADDL R2, R3
+ LSLL $1, R2
+ DBEQ R0, z1
+
+ MOVL R3, b+4(FP)
+ MOVL TOS, R3
+ MOVL TOS, R2
+ MOVL TOS, R1
+ MOVL TOS, R0
+ RTS
+
+TEXT _ccr(SB), $0
+ PEA (A0)
+ SUBL A0, A0
+
+ BCC 2(PC)
+ LEA 1(A0), A0
+
+ BVC 2(PC)
+ LEA 2(A0), A0
+
+ BNE 2(PC)
+ LEA 4(A0), A0
+
+ BPL 2(PC)
+ LEA 8(A0), A0
+
+ MOVW A0, a+0(FP)
+ MOVL TOS, A0
+ RTS
diff --git a/libkern/nan-386.c b/libkern/nan-386.c
new file mode 100644
index 00000000..2152925a
--- /dev/null
+++ b/libkern/nan-386.c
@@ -0,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[1] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[1] = NANEXP;
+ a.x[0] = 0;
+ if(sign < 0)
+ a.x[1] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[0] != 0)
+ return 0;
+ if(a.x[1] == NANEXP)
+ return sign >= 0;
+ if(a.x[1] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/libkern/nan-68000.c b/libkern/nan-68000.c
new file mode 100644
index 00000000..e1b3db36
--- /dev/null
+++ b/libkern/nan-68000.c
@@ -0,0 +1,70 @@
+#include <u.h>
+#include <libc.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/libkern/nan-arm.c b/libkern/nan-arm.c
new file mode 100644
index 00000000..f1cfa0b0
--- /dev/null
+++ b/libkern/nan-arm.c
@@ -0,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/libkern/nan-mips.c b/libkern/nan-mips.c
new file mode 100644
index 00000000..e1b3db36
--- /dev/null
+++ b/libkern/nan-mips.c
@@ -0,0 +1,70 @@
+#include <u.h>
+#include <libc.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/libkern/nan-power.c b/libkern/nan-power.c
new file mode 100644
index 00000000..f1cfa0b0
--- /dev/null
+++ b/libkern/nan-power.c
@@ -0,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/libkern/nan-sparc.c b/libkern/nan-sparc.c
new file mode 100644
index 00000000..f1cfa0b0
--- /dev/null
+++ b/libkern/nan-sparc.c
@@ -0,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/libkern/nan-thumb.c b/libkern/nan-thumb.c
new file mode 100644
index 00000000..f1cfa0b0
--- /dev/null
+++ b/libkern/nan-thumb.c
@@ -0,0 +1,69 @@
+#include <lib9.h>
+
+#define NANEXP (2047<<20)
+#define NANMASK (2047<<20)
+#define NANSIGN (1<<31)
+
+double
+NaN(void)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 1;
+ return a.d;
+}
+
+int
+isNaN(double d)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if((a.x[0] & NANMASK) != NANEXP)
+ return 0;
+ return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.x[0] = NANEXP;
+ a.x[1] = 0;
+ if(sign < 0)
+ a.x[0] |= NANSIGN;
+ return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+ union
+ {
+ double d;
+ long x[2];
+ } a;
+
+ a.d = d;
+ if(a.x[1] != 0)
+ return 0;
+ if(a.x[0] == NANEXP)
+ return sign >= 0;
+ if(a.x[0] == (NANEXP|NANSIGN))
+ return sign <= 0;
+ return 0;
+}
diff --git a/libkern/netmkaddr.c b/libkern/netmkaddr.c
new file mode 100644
index 00000000..1e3b6294
--- /dev/null
+++ b/libkern/netmkaddr.c
@@ -0,0 +1,50 @@
+#include <lib9.h>
+
+/*
+ * make an address, add the defaults
+ */
+char *
+netmkaddr(char *linear, char *defnet, char *defsrv)
+{
+ static char addr[4*(NAMELEN+1)];
+ char *cp;
+
+ /*
+ * dump network name
+ */
+ cp = strchr(linear, '!');
+ if(cp == 0){
+ if(defnet==0){
+ if(defsrv)
+ sprint(addr, "net!%.*s!%.*s", 2*NAMELEN, linear,
+ NAMELEN, defsrv);
+ else
+ sprint(addr, "net!%.*s", 2*NAMELEN, linear);
+ } else {
+ if(defsrv)
+ sprint(addr, "%.*s!%.*s!%.*s", NAMELEN, defnet,
+ 2*NAMELEN, linear, NAMELEN, defsrv);
+ else
+ sprint(addr, "%.*s!%.*s", NAMELEN, defnet,
+ 2*NAMELEN, linear);
+ }
+ return addr;
+ }
+
+ /*
+ * if there is already a service, use it
+ */
+ cp = strchr(cp+1, '!');
+ if(cp)
+ return linear;
+
+ /*
+ * add default service
+ */
+ if(defsrv == 0)
+ return linear;
+ sprint(addr, "%.*s!%.*s", 3*NAMELEN, linear,
+ NAMELEN, defsrv);
+
+ return addr;
+}
diff --git a/libkern/pow.c b/libkern/pow.c
new file mode 100644
index 00000000..2dd39143
--- /dev/null
+++ b/libkern/pow.c
@@ -0,0 +1,68 @@
+#include <lib9.h>
+
+double
+pow(double x, double y) /* return x ^ y (exponentiation) */
+{
+ double xy, y1, ye;
+ long i;
+ int ex, ey, flip;
+
+ if(y == 0.0)
+ return 1.0;
+
+ flip = 0;
+ if(y < 0.){
+ y = -y;
+ flip = 1;
+ }
+ y1 = modf(y, &ye);
+ if(y1 != 0.0){
+ if(x <= 0.)
+ goto zreturn;
+ if(y1 > 0.5) {
+ y1 -= 1.;
+ ye += 1.;
+ }
+ xy = exp(y1 * log(x));
+ }else
+ xy = 1.0;
+ if(ye > 0x7FFFFFFF){ /* should be ~0UL but compiler can't convert double to ulong */
+ if(x <= 0.){
+ zreturn:
+ if(x==0. && !flip)
+ return 0.;
+ return NaN();
+ }
+ if(flip){
+ if(y == .5)
+ return 1./sqrt(x);
+ y = -y;
+ }else if(y == .5)
+ return sqrt(x);
+ return exp(y * log(x));
+ }
+ x = frexp(x, &ex);
+ ey = 0;
+ i = ye;
+ if(i)
+ for(;;){
+ if(i & 1){
+ xy *= x;
+ ey += ex;
+ }
+ i >>= 1;
+ if(i == 0)
+ break;
+ x *= x;
+ ex <<= 1;
+ if(x < .5){
+ x += x;
+ ex -= 1;
+ }
+ }
+ if(flip){
+ xy = 1. / xy;
+ ey = -ey;
+ }
+ return ldexp(xy, ey);
+}
diff --git a/libkern/pow10.c b/libkern/pow10.c
new file mode 100644
index 00000000..933f5d13
--- /dev/null
+++ b/libkern/pow10.c
@@ -0,0 +1,40 @@
+#include <lib9.h>
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+
+static
+double tab[] =
+{
+ 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
+ 1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
+ 1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
+ 1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
+ 1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
+ 1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
+ 1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
+};
+
+double
+pow10(int n)
+{
+ int m;
+
+ if(n < 0) {
+ n = -n;
+ if(n < sizeof(tab)/sizeof(tab[0]))
+ return 1/tab[n];
+ m = n/2;
+ return pow10(-m) * pow10(m-n);
+ }
+ if(n < sizeof(tab)/sizeof(tab[0]))
+ return tab[n];
+ m = n/2;
+ return pow10(m) * pow10(n-m);
+}
diff --git a/libkern/qsort.c b/libkern/qsort.c
new file mode 100644
index 00000000..3388891c
--- /dev/null
+++ b/libkern/qsort.c
@@ -0,0 +1,122 @@
+/*
+ * qsort -- simple quicksort
+ */
+
+typedef
+struct
+{
+ int (*cmp)(void*, void*);
+ void (*swap)(char*, char*, long);
+ long es;
+} Sort;
+
+static void
+swapb(char *i, char *j, long es)
+{
+ char c;
+
+ do {
+ c = *i;
+ *i++ = *j;
+ *j++ = c;
+ es--;
+ } while(es != 0);
+
+}
+
+static void
+swapi(char *ii, char *ij, long es)
+{
+ long *i, *j, c;
+
+ i = (long*)ii;
+ j = (long*)ij;
+ do {
+ c = *i;
+ *i++ = *j;
+ *j++ = c;
+ es -= sizeof(long);
+ } while(es != 0);
+}
+
+static char*
+pivot(char *a, long n, Sort *p)
+{
+ long j;
+ char *pi, *pj, *pk;
+
+ j = n/6 * p->es;
+ pi = a + j; /* 1/6 */
+ j += j;
+ pj = pi + j; /* 1/2 */
+ pk = pj + j; /* 5/6 */
+ if(p->cmp(pi, pj) < 0) {
+ if(p->cmp(pi, pk) < 0) {
+ if(p->cmp(pj, pk) < 0)
+ return pj;
+ return pk;
+ }
+ return pi;
+ }
+ if(p->cmp(pj, pk) < 0) {
+ if(p->cmp(pi, pk) < 0)
+ return pi;
+ return pk;
+ }
+ return pj;
+}
+
+static void
+qsorts(char *a, long n, Sort *p)
+{
+ long j, es;
+ char *pi, *pj, *pn;
+
+ es = p->es;
+ while(n > 1) {
+ if(n > 10) {
+ pi = pivot(a, n, p);
+ } else
+ pi = a + (n>>1)*es;
+
+ p->swap(a, pi, es);
+ pi = a;
+ pn = a + n*es;
+ pj = pn;
+ for(;;) {
+ do
+ pi += es;
+ while(pi < pn && p->cmp(pi, a) < 0);
+ do
+ pj -= es;
+ while(pj > a && p->cmp(pj, a) > 0);
+ if(pj < pi)
+ break;
+ p->swap(pi, pj, es);
+ }
+ p->swap(a, pj, es);
+ j = (pj - a) / es;
+
+ n = n-j-1;
+ if(j >= n) {
+ qsorts(a, j, p);
+ a += (j+1)*es;
+ } else {
+ qsorts(a + (j+1)*es, n, p);
+ n = j;
+ }
+ }
+}
+
+void
+qsort(void *va, long n, long es, int (*cmp)(void*, void*))
+{
+ Sort s;
+
+ s.cmp = cmp;
+ s.es = es;
+ s.swap = swapi;
+ if(((long)va | es) % sizeof(long))
+ s.swap = swapb;
+ qsorts((char*)va, n, &s);
+}
diff --git a/libkern/rune.c b/libkern/rune.c
new file mode 100644
index 00000000..d3cb28e0
--- /dev/null
+++ b/libkern/rune.c
@@ -0,0 +1,162 @@
+#include "lib9.h"
+
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+
+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
+
+ Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
+ Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
+ Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Bad = Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+ int c, c1, c2;
+ long l;
+
+ /*
+ * one character sequence
+ * 00000-0007F => T1
+ */
+ c = *(uchar*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uchar*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uchar*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+ long c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = *rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ str[1] = Tx | (c & Maskx);
+ return 2;
+ }
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ str[0] = T3 | (c >> 2*Bitx);
+ str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[2] = Tx | (c & Maskx);
+ return 3;
+}
+
+int
+runelen(long c)
+{
+ if(c <= Rune1)
+ return 1;
+ if(c <= Rune2)
+ return 2;
+ return 3;
+}
+
+int
+runenlen(Rune *r, int l)
+{
+ int n;
+ long c;
+
+ n = 0;
+ while(l--) {
+ c = *r++;
+ if(c <= Rune1)
+ n += 1;
+ else
+ if(c <= Rune2)
+ n += 2;
+ else
+ n += 3;
+ }
+ return n;
+}
+
+int
+fullrune(char *str, int n)
+{
+ int c;
+
+ if(n > 0) {
+ c = *(uchar*)str;
+ if(c < Tx)
+ return 1;
+ if(n > 1)
+ if(c < T3 || n > 2)
+ return 1;
+ }
+ return 0;
+}
diff --git a/libkern/runestrlen.c b/libkern/runestrlen.c
new file mode 100644
index 00000000..e1cd84ac
--- /dev/null
+++ b/libkern/runestrlen.c
@@ -0,0 +1,13 @@
+#include "lib9.h"
+
+
+long
+runestrlen(Rune *s)
+{
+ int i;
+
+ i = 0;
+ while(*s++)
+ i++;
+ return i;
+}
diff --git a/libkern/seprint.c b/libkern/seprint.c
new file mode 100644
index 00000000..7dadad62
--- /dev/null
+++ b/libkern/seprint.c
@@ -0,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+ char *p;
+ va_list args;
+
+ va_start(args, fmt);
+ p = vseprint(buf, e, fmt, args);
+ va_end(args);
+ return p;
+}
diff --git a/libkern/sin.c b/libkern/sin.c
new file mode 100644
index 00000000..70f90a9d
--- /dev/null
+++ b/libkern/sin.c
@@ -0,0 +1,67 @@
+/*
+ C program for floating point sin/cos.
+ Calls modf.
+ There are no error exits.
+ Coefficients are #3370 from Hart & Cheney (18.80D).
+*/
+
+#include <lib9.h>
+
+#define p0 .1357884097877375669092680e8
+#define p1 -.4942908100902844161158627e7
+#define p2 .4401030535375266501944918e6
+#define p3 -.1384727249982452873054457e5
+#define p4 .1459688406665768722226959e3
+#define q0 .8644558652922534429915149e7
+#define q1 .4081792252343299749395779e6
+#define q2 .9463096101538208180571257e4
+#define q3 .1326534908786136358911494e3
+
+static
+double
+sinus(double arg, int quad)
+{
+ double e, f, ysq, x, y, temp1, temp2;
+ int k;
+
+ x = arg;
+ if(x < 0) {
+ x = -x;
+ quad += 2;
+ }
+ x *= 1/PIO2; /* underflow? */
+ if(x > 32764) {
+ y = modf(x, &e);
+ e += quad;
+ modf(0.25*e, &f);
+ quad = e - 4*f;
+ } else {
+ k = x;
+ y = x - k;
+ quad += k;
+ quad &= 3;
+ }
+ if(quad & 1)
+ y = 1-y;
+ if(quad > 1)
+ y = -y;
+
+ ysq = y*y;
+ temp1 = ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y;
+ temp2 = ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0);
+ return temp1/temp2;
+}
+
+double
+cos(double arg)
+{
+ if(arg < 0)
+ arg = -arg;
+ return sinus(arg, 1);
+}
+
+double
+sin(double arg)
+{
+ return sinus(arg, 0);
+}
diff --git a/libkern/smprint.c b/libkern/smprint.c
new file mode 100644
index 00000000..ecb55492
--- /dev/null
+++ b/libkern/smprint.c
@@ -0,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+smprint(char *fmt, ...)
+{
+ va_list args;
+ char *p;
+
+ va_start(args, fmt);
+ p = vsmprint(fmt, args);
+ va_end(args);
+ return p;
+}
diff --git a/libkern/snprint.c b/libkern/snprint.c
new file mode 100644
index 00000000..6e65c70c
--- /dev/null
+++ b/libkern/snprint.c
@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprint(buf, len, fmt, args);
+ va_end(args);
+ return n;
+}
+
diff --git a/libkern/sqrt.c b/libkern/sqrt.c
new file mode 100644
index 00000000..0d235126
--- /dev/null
+++ b/libkern/sqrt.c
@@ -0,0 +1,53 @@
+/*
+ sqrt returns the square root of its floating
+ point argument. Newton's method.
+
+ calls frexp
+*/
+
+#include <lib9.h>
+
+double
+sqrt(double arg)
+{
+ double x, temp;
+ int exp, i;
+
+ if(arg <= 0) {
+ if(arg < 0)
+ return NaN();
+ return 0;
+ }
+ if(isInf(arg, 1))
+ return arg;
+ x = frexp(arg, &exp);
+ while(x < 0.5) {
+ x *= 2;
+ exp--;
+ }
+ /*
+ * NOTE
+ * this wont work on 1's comp
+ */
+ if(exp & 1) {
+ x *= 2;
+ exp--;
+ }
+ temp = 0.5 * (1.0+x);
+
+ while(exp > 60) {
+ temp *= (1L<<30);
+ exp -= 60;
+ }
+ while(exp < -60) {
+ temp /= (1L<<30);
+ exp += 60;
+ }
+ if(exp >= 0)
+ temp *= 1L << (exp/2);
+ else
+ temp /= 1L << (-exp/2);
+ for(i=0; i<=4; i++)
+ temp = 0.5*(temp + arg/temp);
+ return temp;
+}
diff --git a/libkern/strcat.c b/libkern/strcat.c
new file mode 100644
index 00000000..9b1b3046
--- /dev/null
+++ b/libkern/strcat.c
@@ -0,0 +1,9 @@
+#include <lib9.h>
+
+char*
+strcat(char *s1, char *s2)
+{
+
+ strcpy(strchr(s1, 0), s2);
+ return s1;
+}
diff --git a/libkern/strchr-386.s b/libkern/strchr-386.s
new file mode 100644
index 00000000..e437caf2
--- /dev/null
+++ b/libkern/strchr-386.s
@@ -0,0 +1,29 @@
+ TEXT strchr(SB),$0
+/*
+ * look for null
+ */
+ MOVL p+0(FP), DI
+ MOVL $-1, CX
+ MOVL $0, AX
+ CLD
+
+ REPN; SCASB
+
+/*
+ * look for real char
+ */
+ MOVL DI, CX
+ MOVL p+0(FP), DI
+ SUBL DI, CX
+ MOVBLZX c+4(FP), AX
+
+ REPN; SCASB
+
+ JEQ found
+ MOVL $0, AX
+ RET
+
+found:
+ MOVL DI, AX
+ SUBL $1, AX
+ RET
diff --git a/libkern/strchr-68000.s b/libkern/strchr-68000.s
new file mode 100644
index 00000000..a5d4be2c
--- /dev/null
+++ b/libkern/strchr-68000.s
@@ -0,0 +1,27 @@
+ TEXT strchr(SB), $0
+
+ MOVL s+0(FP), A0
+ MOVB c+7(FP), R2
+ BEQ null
+
+l:
+ MOVB (A0)+, R1
+ BEQ out
+ CMPB R1, R2
+ BNE l
+
+ MOVL A0, R0
+ ADDL $-1, R0
+ RTS
+
+out:
+ CLRL R0
+ RTS
+
+null:
+ TSTB (A0)+
+ BNE null
+
+ MOVL A0, R0
+ ADDL $-1, R0
+ RTS
diff --git a/libkern/strchr-arm.s b/libkern/strchr-arm.s
new file mode 100644
index 00000000..9c04273c
--- /dev/null
+++ b/libkern/strchr-arm.s
@@ -0,0 +1,52 @@
+TEXT strchr(SB), $-4
+ MOVBU c+4(FP), R1
+ CMP $0, R1
+ BEQ _null
+
+_strchr: /* not looking for a null, byte at a time */
+ MOVBU.P 1(R0), R2
+ CMP R1, R2
+ BEQ _sub1
+
+ CMP $0, R2
+ BNE _strchr
+
+_return0: /* character not found in string, return 0 */
+ MOVW $0, R0
+ RET
+
+_null: /* looking for null, align */
+ AND.S $3, R0, R2
+ BEQ _aligned
+
+ MOVBU.P 1(R0), R4
+ CMP $0, R4
+ BEQ _sub1
+ B _null
+
+_aligned:
+ MOVW $0xFF, R3 /* mask */
+
+_loop:
+ MOVW.P 4(R0), R4 /* 4 at a time */
+ TST R4, R3 /* AND.S R2, R3, Rx */
+ BEQ _sub4
+ TST R4>>8, R3
+ BEQ _sub3
+ TST R4>>16, R3
+ BEQ _sub2
+ TST R4>>24, R3
+ BNE _loop
+
+_sub1: /* compensate for pointer increment */
+ SUB $1, R0
+ RET
+_sub2:
+ SUB $2, R0
+ RET
+_sub3:
+ SUB $3, R0
+ RET
+_sub4:
+ SUB $4, R0
+ RET
diff --git a/libkern/strchr-mips.c b/libkern/strchr-mips.c
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/libkern/strchr-mips.c
diff --git a/libkern/strchr-mips.s b/libkern/strchr-mips.s
new file mode 100644
index 00000000..e009ffad
--- /dev/null
+++ b/libkern/strchr-mips.s
@@ -0,0 +1,63 @@
+ TEXT strchr(SB), $0
+MOVW R1, 0(FP)
+ MOVB c+7(FP), R4
+ MOVW s+0(FP), R3
+
+ BEQ R4, l2
+
+/*
+ * char is not null
+ */
+l1:
+ MOVB (R3), R1
+ ADDU $1, R3
+ BEQ R1, ret
+ BNE R1,R4, l1
+ JMP rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+ AND $3,R3, R1
+ BEQ R1, l3
+ MOVB (R3), R1
+ ADDU $1, R3
+ BNE R1, l2
+ JMP rm1
+
+l3:
+ MOVW $0xff000000, R6
+ MOVW $0x00ff0000, R7
+
+l4:
+ MOVW (R3), R5
+ ADDU $4, R3
+ AND R6,R5, R1
+ AND R7,R5, R2
+ BEQ R1, b0
+ AND $0xff00,R5, R1
+ BEQ R2, b1
+ AND $0xff,R5, R2
+ BEQ R1, b2
+ BNE R2, l4
+
+rm1:
+ ADDU $-1,R3, R1
+ JMP ret
+
+b2:
+ ADDU $-2,R3, R1
+ JMP ret
+
+b1:
+ ADDU $-3,R3, R1
+ JMP ret
+
+b0:
+ ADDU $-4,R3, R1
+ JMP ret
+
+ret:
+ RET
diff --git a/libkern/strchr-power.s b/libkern/strchr-power.s
new file mode 100644
index 00000000..1cfc0bbe
--- /dev/null
+++ b/libkern/strchr-power.s
@@ -0,0 +1,16 @@
+/*
+ * BUG: it's slow
+ */
+ TEXT strchr(SB), $0
+ MOVBZ c+7(FP), R4
+ SUB $1, R3
+l1:
+ MOVBZU 1(R3), R6
+ CMP R6, R4
+ BEQ eq
+ CMP R6, $0
+ BNE l1
+nf:
+ MOVW $0, R3
+eq:
+ RETURN
diff --git a/libkern/strchr-sparc.s b/libkern/strchr-sparc.s
new file mode 100644
index 00000000..192beab1
--- /dev/null
+++ b/libkern/strchr-sparc.s
@@ -0,0 +1,73 @@
+ TEXT strchr(SB), $0
+
+MOVW R7, 0(FP)
+ MOVB c+7(FP), R10
+ MOVW s+0(FP), R9
+
+ SUBCC R0,R10, R0
+ BE l2
+
+/*
+ * char is not null
+ */
+l1:
+ MOVB (R9), R7
+ ADD $1, R9
+ SUBCC R0,R7, R0
+ BE ret
+ SUBCC R7,R10, R0
+ BNE l1
+ JMP rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+ ANDCC $3,R9, R0
+ BE l3
+ MOVB (R9), R7
+ ADD $1, R9
+ SUBCC R0,R7, R0
+ BNE l2
+ JMP rm1
+
+/*
+ * develop byte masks
+ */
+l3:
+ MOVW $0xff, R17
+ SLL $8,R17, R16
+ SLL $16,R17, R13
+ SLL $24,R17, R12
+
+l4:
+ MOVW (R9), R11
+ ADD $4, R9
+ ANDCC R12,R11, R0
+ BE b0
+ ANDCC R13,R11, R0
+ BE b1
+ ANDCC R16,R11, R0
+ BE b2
+ ANDCC R17,R11, R0
+ BNE l4
+
+rm1:
+ SUB $1,R9, R7
+ JMP ret
+
+b2:
+ SUB $2,R9, R7
+ JMP ret
+
+b1:
+ SUB $3,R9, R7
+ JMP ret
+
+b0:
+ SUB $4,R9, R7
+ JMP ret
+
+ret:
+ RETURN
diff --git a/libkern/strchr-thumb.s b/libkern/strchr-thumb.s
new file mode 100644
index 00000000..9c04273c
--- /dev/null
+++ b/libkern/strchr-thumb.s
@@ -0,0 +1,52 @@
+TEXT strchr(SB), $-4
+ MOVBU c+4(FP), R1
+ CMP $0, R1
+ BEQ _null
+
+_strchr: /* not looking for a null, byte at a time */
+ MOVBU.P 1(R0), R2
+ CMP R1, R2
+ BEQ _sub1
+
+ CMP $0, R2
+ BNE _strchr
+
+_return0: /* character not found in string, return 0 */
+ MOVW $0, R0
+ RET
+
+_null: /* looking for null, align */
+ AND.S $3, R0, R2
+ BEQ _aligned
+
+ MOVBU.P 1(R0), R4
+ CMP $0, R4
+ BEQ _sub1
+ B _null
+
+_aligned:
+ MOVW $0xFF, R3 /* mask */
+
+_loop:
+ MOVW.P 4(R0), R4 /* 4 at a time */
+ TST R4, R3 /* AND.S R2, R3, Rx */
+ BEQ _sub4
+ TST R4>>8, R3
+ BEQ _sub3
+ TST R4>>16, R3
+ BEQ _sub2
+ TST R4>>24, R3
+ BNE _loop
+
+_sub1: /* compensate for pointer increment */
+ SUB $1, R0
+ RET
+_sub2:
+ SUB $2, R0
+ RET
+_sub3:
+ SUB $3, R0
+ RET
+_sub4:
+ SUB $4, R0
+ RET
diff --git a/libkern/strchr.c b/libkern/strchr.c
new file mode 100644
index 00000000..1d4d425c
--- /dev/null
+++ b/libkern/strchr.c
@@ -0,0 +1,18 @@
+#include <lib9.h>
+
+char*
+strchr(char *s, int c)
+{
+ char c1;
+
+ if(c == 0) {
+ while(*s++)
+ ;
+ return s-1;
+ }
+
+ while(c1 = *s++)
+ if(c1 == c)
+ return s-1;
+ return 0;
+}
diff --git a/libkern/strcmp-power.s b/libkern/strcmp-power.s
new file mode 100644
index 00000000..0aef5b29
--- /dev/null
+++ b/libkern/strcmp-power.s
@@ -0,0 +1,21 @@
+TEXT strcmp(SB), $0
+
+ MOVW s2+4(FP), R4
+
+ SUB $1, R3
+ SUB $1, R4
+l1:
+ MOVBZU 1(R3), R5
+ MOVBZU 1(R4), R6
+ CMP R5, R6
+ BNE ne
+ CMP R5, $0
+ BNE l1
+ MOVW $0, R3
+ RETURN
+ne:
+ MOVW $1, R3
+ BGT ret
+ MOVW $-1, R3
+ret:
+ RETURN
diff --git a/libkern/strcmp.c b/libkern/strcmp.c
new file mode 100644
index 00000000..f2a7e581
--- /dev/null
+++ b/libkern/strcmp.c
@@ -0,0 +1,19 @@
+#include <lib9.h>
+
+int
+strcmp(char *s1, char *s2)
+{
+ unsigned c1, c2;
+
+ for(;;) {
+ c1 = *s1++;
+ c2 = *s2++;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ return 0;
+ }
+}
diff --git a/libkern/strcpy.c b/libkern/strcpy.c
new file mode 100644
index 00000000..473a5eac
--- /dev/null
+++ b/libkern/strcpy.c
@@ -0,0 +1,15 @@
+#include <lib9.h>
+#define N 10000
+
+char*
+strcpy(char *s1, char *s2)
+{
+ char *os1;
+
+ os1 = s1;
+ while(!memccpy(s1, s2, 0, N)) {
+ s1 += N;
+ s2 += N;
+ }
+ return os1;
+}
diff --git a/libkern/strdup.c b/libkern/strdup.c
new file mode 100644
index 00000000..2d6eaef5
--- /dev/null
+++ b/libkern/strdup.c
@@ -0,0 +1,12 @@
+#include <lib9.h>
+
+char*
+strdup(char *s)
+{
+ char *os;
+
+ os = malloc(strlen(s) + 1);
+ if(os == 0)
+ return 0;
+ return strcpy(os, s);
+}
diff --git a/libkern/strecpy.c b/libkern/strecpy.c
new file mode 100644
index 00000000..7d2f2277
--- /dev/null
+++ b/libkern/strecpy.c
@@ -0,0 +1,16 @@
+#include <lib9.h>
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+ if(to >= e)
+ return to;
+ to = memccpy(to, from, '\0', e - to);
+ if(to == nil){
+ to = e - 1;
+ *to = '\0';
+ }else{
+ to--;
+ }
+ return to;
+}
diff --git a/libkern/strlen.c b/libkern/strlen.c
new file mode 100644
index 00000000..5cac06f2
--- /dev/null
+++ b/libkern/strlen.c
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+long
+strlen(char *s)
+{
+
+ return strchr(s, 0) - s;
+}
diff --git a/libkern/strncmp-power.s b/libkern/strncmp-power.s
new file mode 100644
index 00000000..c55962fa
--- /dev/null
+++ b/libkern/strncmp-power.s
@@ -0,0 +1,29 @@
+TEXT strncmp(SB), $0
+#define BDNZ BC 16,0,
+
+ MOVW s2+4(FP), R4
+ MOVW n+8(FP), R7
+
+ CMP R7, $0
+ MOVW R7, CTR
+ BLE eq
+
+ SUB $1, R3
+ SUB $1, R4
+l1:
+ MOVBZU 1(R3), R5
+ MOVBZU 1(R4), R6
+ CMP R5, R6
+ BNE ne
+ CMP R5, $0
+ BEQ eq
+ BDNZ l1
+eq:
+ MOVW $0, R3
+ RETURN
+ne:
+ MOVW $1, R3
+ BGT ret
+ MOVW $-1, R3
+ret:
+ RETURN
diff --git a/libkern/strncmp.c b/libkern/strncmp.c
new file mode 100644
index 00000000..ef926489
--- /dev/null
+++ b/libkern/strncmp.c
@@ -0,0 +1,21 @@
+#include <lib9.h>
+
+int
+strncmp(char *s1, char *s2, long n)
+{
+ unsigned c1, c2;
+
+ while(n > 0) {
+ c1 = *s1++;
+ c2 = *s2++;
+ n--;
+ if(c1 != c2) {
+ if(c1 > c2)
+ return 1;
+ return -1;
+ }
+ if(c1 == 0)
+ break;
+ }
+ return 0;
+}
diff --git a/libkern/strncpy.c b/libkern/strncpy.c
new file mode 100644
index 00000000..44f85d6f
--- /dev/null
+++ b/libkern/strncpy.c
@@ -0,0 +1,17 @@
+#include <lib9.h>
+
+char*
+strncpy(char *s1, char *s2, long n)
+{
+ int i;
+ char *os1;
+
+ os1 = s1;
+ for(i = 0; i < n; i++)
+ if((*s1++ = *s2++) == 0) {
+ while(++i < n)
+ *s1++ = 0;
+ return os1;
+ }
+ return os1;
+}
diff --git a/libkern/strrchr.c b/libkern/strrchr.c
new file mode 100644
index 00000000..fc28ede4
--- /dev/null
+++ b/libkern/strrchr.c
@@ -0,0 +1,14 @@
+#include <lib9.h>
+
+char*
+strrchr(char *s, int c)
+{
+ char *r;
+
+ if(c == 0)
+ return strchr(s, 0);
+ r = 0;
+ while(s = strchr(s, c))
+ r = s++;
+ return r;
+}
diff --git a/libkern/strstr.c b/libkern/strstr.c
new file mode 100644
index 00000000..b9d8a35e
--- /dev/null
+++ b/libkern/strstr.c
@@ -0,0 +1,21 @@
+#include <lib9.h>
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+strstr(char *s1, char *s2)
+{
+ char *p;
+ int f, n;
+
+ f = s2[0];
+ if(f == 0)
+ return s1;
+ n = strlen(s2);
+ for(p=strchr(s1, f); p; p=strchr(p+1, f))
+ if(strncmp(p, s2, n) == 0)
+ return p;
+ return 0;
+}
diff --git a/libkern/strtod.c b/libkern/strtod.c
new file mode 100644
index 00000000..c591e44c
--- /dev/null
+++ b/libkern/strtod.c
@@ -0,0 +1,31 @@
+#include <lib9.h>
+
+static int
+strtodf(void *vp)
+{
+ return *(*((char**)vp))++;
+}
+
+double
+strtod(char *s, char **end)
+{
+ double d;
+ char *ss;
+ int c;
+
+ ss = s;
+ d = charstod(strtodf, &s);
+ /*
+ * Fix cases like 2.3e+ , which charstod will consume
+ */
+ if(end){
+ *end = --s;
+ while(s > ss){
+ c = *--s;
+ if(c!='-' && c!='+' && c!='e' && c!='E')
+ break;
+ (*end)--;
+ }
+ }
+ return d;
+}
diff --git a/libkern/strtol.c b/libkern/strtol.c
new file mode 100644
index 00000000..a519f02d
--- /dev/null
+++ b/libkern/strtol.c
@@ -0,0 +1,94 @@
+#include <lib9.h>
+
+#define LONG_MAX 2147483647L
+#define LONG_MIN -2147483648L
+
+long
+strtol(char *nptr, char **endptr, int base)
+{
+ char *p;
+ long n, nn;
+ int c, ovfl, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ }else if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ }else if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = p;
+ if(ovfl){
+ if(neg)
+ return LONG_MIN;
+ return LONG_MAX;
+ }
+ if(neg)
+ return -n;
+ return n;
+}
diff --git a/libkern/strtoll.c b/libkern/strtoll.c
new file mode 100644
index 00000000..ff98e1c4
--- /dev/null
+++ b/libkern/strtoll.c
@@ -0,0 +1,81 @@
+#include "lib9.h"
+
+vlong
+strtoll(const char *nptr, char **endptr, int base)
+{
+ const char *p;
+ vlong n;
+ int c, v, neg, ndig;
+
+ p = nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X'){
+ p += 2;
+ base = 16;
+ }
+ }
+ }else if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ p += 2;
+ }else if(base<0 || 36<base)
+ goto Return;
+
+ /*
+ * Non-empty sequence of digits
+ */
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ n = n*base + v;
+ }
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = (char*) p;
+ if(neg)
+ return -n;
+ return n;
+}
diff --git a/libkern/strtoul.c b/libkern/strtoul.c
new file mode 100644
index 00000000..bdf2fc08
--- /dev/null
+++ b/libkern/strtoul.c
@@ -0,0 +1,96 @@
+#include <lib9.h>
+
+#define ULONG_MAX 4294967295UL
+
+ulong
+strtoul(char *nptr, char **endptr, int base)
+{
+ char *p;
+ ulong n, nn, m;
+ int c, ovfl, neg, v, ndig;
+
+ p = (char*)nptr;
+ neg = 0;
+ n = 0;
+ ndig = 0;
+ ovfl = 0;
+
+ /*
+ * White space
+ */
+ for(;;p++){
+ switch(*p){
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case '\v':
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Sign
+ */
+ if(*p=='-' || *p=='+')
+ if(*p++ == '-')
+ neg = 1;
+
+ /*
+ * Base
+ */
+ if(base==0){
+ if(*p != '0')
+ base = 10;
+ else{
+ base = 8;
+ if(p[1]=='x' || p[1]=='X')
+ base = 16;
+ }
+ }
+ if(base<2 || 36<base)
+ goto Return;
+ if(base==16 && *p=='0'){
+ if(p[1]=='x' || p[1]=='X')
+ if(('0' <= p[2] && p[2] <= '9')
+ ||('a' <= p[2] && p[2] <= 'f')
+ ||('A' <= p[2] && p[2] <= 'F'))
+ p += 2;
+ }
+ /*
+ * Non-empty sequence of digits
+ */
+ n = 0;
+ m = ULONG_MAX/base;
+ for(;; p++,ndig++){
+ c = *p;
+ v = base;
+ if('0'<=c && c<='9')
+ v = c - '0';
+ else if('a'<=c && c<='z')
+ v = c - 'a' + 10;
+ else if('A'<=c && c<='Z')
+ v = c - 'A' + 10;
+ if(v >= base)
+ break;
+ if(n > m)
+ ovfl = 1;
+ nn = n*base + v;
+ if(nn < n)
+ ovfl = 1;
+ n = nn;
+ }
+
+ Return:
+ if(ndig == 0)
+ p = nptr;
+ if(endptr)
+ *endptr = p;
+ if(ovfl)
+ return ULONG_MAX;
+ if(neg)
+ return -n;
+ return n;
+}
diff --git a/libkern/tokenize.c b/libkern/tokenize.c
new file mode 100644
index 00000000..1b222c52
--- /dev/null
+++ b/libkern/tokenize.c
@@ -0,0 +1,58 @@
+#include "lib9.h"
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s)
+{
+ int quoting;
+ char *t;
+
+ quoting = 0;
+ t = s; /* s is output string, t is input string */
+ while(*t!='\0' && (quoting || utfrune(qsep, *t)==nil)){
+ if(*t != '\''){
+ *s++ = *t++;
+ continue;
+ }
+ /* *t is a quote */
+ if(!quoting){
+ quoting = 1;
+ t++;
+ continue;
+ }
+ /* quoting and we're on a quote */
+ if(t[1] != '\''){
+ /* end of quoted section; absorb closing quote */
+ t++;
+ quoting = 0;
+ continue;
+ }
+ /* doubled quote; fold one quote into two */
+ t++;
+ *s++ = *t++;
+ }
+ if(*s != '\0'){
+ *s = '\0';
+ if(t == s)
+ t++;
+ }
+ return t;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+ int nargs;
+
+ for(nargs=0; nargs<maxargs; nargs++){
+ while(*s!='\0' && utfrune(qsep, *s)!=nil)
+ s++;
+ if(*s == '\0')
+ break;
+ args[nargs] = s;
+ s = qtoken(s);
+ }
+
+ return nargs;
+}
diff --git a/libkern/toupper.c b/libkern/toupper.c
new file mode 100644
index 00000000..4c0b02ac
--- /dev/null
+++ b/libkern/toupper.c
@@ -0,0 +1,16 @@
+toupper(int c)
+{
+
+ if(c < 'a' || c > 'z')
+ return c;
+ return (c-'a'+'A');
+}
+
+tolower(int c)
+{
+
+ if(c < 'A' || c > 'Z')
+ return c;
+ return (c-'A'+'a');
+}
+
diff --git a/libkern/u16.c b/libkern/u16.c
new file mode 100644
index 00000000..d9f41e46
--- /dev/null
+++ b/libkern/u16.c
@@ -0,0 +1,52 @@
+#include <lib9.h>
+static char t16e[] = "0123456789ABCDEF";
+
+int
+dec16(uchar *out, int lim, char *in, int n)
+{
+ int c, w = 0, i = 0;
+ uchar *start = out;
+ uchar *eout = out + lim;
+
+ while(n-- > 0){
+ c = *in++;
+ if('0' <= c && c <= '9')
+ c = c - '0';
+ else if('a' <= c && c <= 'z')
+ c = c - 'a' + 10;
+ else if('A' <= c && c <= 'Z')
+ c = c - 'A' + 10;
+ else
+ continue;
+ w = (w<<4) + c;
+ i++;
+ if(i == 2){
+ if(out + 1 > eout)
+ goto exhausted;
+ *out++ = w;
+ w = 0;
+ i = 0;
+ }
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc16(char *out, int lim, uchar *in, int n)
+{
+ uint c;
+ char *eout = out + lim;
+ char *start = out;
+
+ while(n-- > 0){
+ c = *in++;
+ if(out + 2 >= eout)
+ goto exhausted;
+ *out++ = t16e[c>>4];
+ *out++ = t16e[c&0xf];
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
diff --git a/libkern/u32.c b/libkern/u32.c
new file mode 100644
index 00000000..1eb0c6e0
--- /dev/null
+++ b/libkern/u32.c
@@ -0,0 +1,109 @@
+#include <lib9.h>
+
+int
+dec32(uchar *dest, int ndest, char *src, int nsrc)
+{
+ char *s, *tab;
+ uchar *start;
+ int i, u[8];
+
+ if(ndest+1 < (5*nsrc+7)/8)
+ return -1;
+ start = dest;
+ tab = "23456789abcdefghijkmnpqrstuvwxyz";
+ while(nsrc>=8){
+ for(i=0; i<8; i++){
+ s = strchr(tab,(int)src[i]);
+ u[i] = s ? s-tab : 0;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ *dest++ = ((0x7 & u[6])<<5) | u[7];
+ src += 8;
+ nsrc -= 8;
+ }
+ if(nsrc > 0){
+ if(nsrc == 1 || nsrc == 3 || nsrc == 6)
+ return -1;
+ for(i=0; i<nsrc; i++){
+ s = strchr(tab,(int)src[i]);
+ u[i] = s ? s-tab : 0;
+ }
+ *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+ if(nsrc == 2)
+ goto out;
+ *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+ if(nsrc == 4)
+ goto out;
+ *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+ if(nsrc == 5)
+ goto out;
+ *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+ }
+out:
+ return dest-start;
+}
+
+int
+enc32(char *dest, int ndest, uchar *src, int nsrc)
+{
+ char *tab, *start;
+ int j;
+
+ if(ndest <= (8*nsrc+4)/5 )
+ return -1;
+ start = dest;
+ tab = "23456789abcdefghijkmnpqrstuvwxyz";
+ while(nsrc>=5){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = tab[j];
+ j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
+ *dest++ = tab[j];
+ j = (0x1f & (src[1]>>1));
+ *dest++ = tab[j];
+ j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
+ *dest++ = tab[j];
+ j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
+ *dest++ = tab[j];
+ j = (0x1f & (src[3]>>2));
+ *dest++ = tab[j];
+ j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
+ *dest++ = tab[j];
+ j = (0x1f & (src[4]));
+ *dest++ = tab[j];
+ src += 5;
+ nsrc -= 5;
+ }
+ if(nsrc){
+ j = (0x1f & (src[0]>>3));
+ *dest++ = tab[j];
+ j = (0x1c & (src[0]<<2));
+ if(nsrc == 1)
+ goto out;
+ j |= (0x03 & (src[1]>>6));
+ *dest++ = tab[j];
+ j = (0x1f & (src[1]>>1));
+ if(nsrc == 2)
+ goto out;
+ *dest++ = tab[j];
+ j = (0x10 & (src[1]<<4));
+ if(nsrc == 3)
+ goto out;
+ j |= (0x0f & (src[2]>>4));
+ *dest++ = tab[j];
+ j = (0x1e & (src[2]<<1));
+ if(nsrc == 4)
+ goto out;
+ j |= (0x01 & (src[3]>>7));
+ *dest++ = tab[j];
+ j = (0x1f & (src[3]>>2));
+ *dest++ = tab[j];
+ j = (0x18 & (src[3]<<3));
+out:
+ *dest++ = tab[j];
+ }
+ *dest = 0;
+ return dest-start;
+}
diff --git a/libkern/u64.c b/libkern/u64.c
new file mode 100644
index 00000000..a17bdf1d
--- /dev/null
+++ b/libkern/u64.c
@@ -0,0 +1,126 @@
+#include <lib9.h>
+
+enum {
+ INVAL= 255
+};
+
+static uchar t64d[256] = {
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+ INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL
+};
+static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int
+dec64(uchar *out, int lim, char *in, int n)
+{
+ ulong b24;
+ uchar *start = out;
+ uchar *e = out + lim;
+ int i, c;
+
+ b24 = 0;
+ i = 0;
+ while(n-- > 0){
+
+ c = t64d[*(uchar*)in++];
+ if(c == INVAL)
+ continue;
+ switch(i){
+ case 0:
+ b24 = c<<18;
+ break;
+ case 1:
+ b24 |= c<<12;
+ break;
+ case 2:
+ b24 |= c<<6;
+ break;
+ case 3:
+ if(out + 3 > e)
+ goto exhausted;
+
+ b24 |= c;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ *out++ = b24;
+ i = -1;
+ break;
+ }
+ i++;
+ }
+ switch(i){
+ case 2:
+ if(out + 1 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ break;
+ case 3:
+ if(out + 2 > e)
+ goto exhausted;
+ *out++ = b24>>16;
+ *out++ = b24>>8;
+ break;
+ }
+exhausted:
+ return out - start;
+}
+
+int
+enc64(char *out, int lim, uchar *in, int n)
+{
+ int i;
+ ulong b24;
+ char *start = out;
+ char *e = out + lim;
+
+ for(i = n/3; i > 0; i--){
+ b24 = (*in++)<<16;
+ b24 |= (*in++)<<8;
+ b24 |= *in++;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = t64e[(b24>>6)&0x3f];
+ *out++ = t64e[(b24)&0x3f];
+ }
+
+ switch(n%3){
+ case 2:
+ b24 = (*in++)<<16;
+ b24 |= (*in)<<8;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = t64e[(b24>>6)&0x3f];
+ *out++ = '=';
+ break;
+ case 1:
+ b24 = (*in)<<16;
+ if(out + 4 >= e)
+ goto exhausted;
+ *out++ = t64e[(b24>>18)];
+ *out++ = t64e[(b24>>12)&0x3f];
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+exhausted:
+ *out = 0;
+ return out - start;
+}
diff --git a/libkern/utfecpy.c b/libkern/utfecpy.c
new file mode 100644
index 00000000..8ccb841c
--- /dev/null
+++ b/libkern/utfecpy.c
@@ -0,0 +1,20 @@
+#include "lib9.h"
+
+char*
+utfecpy(char *to, char *e, char *from)
+{
+ char *end;
+
+ if(to >= e)
+ return to;
+ end = memccpy(to, from, '\0', e - to);
+ if(end == nil){
+ end = e-1;
+ while(end>to && (*--end&0xC0)==0x80)
+ ;
+ *end = '\0';
+ }else{
+ end--;
+ }
+ return end;
+}
diff --git a/libkern/utflen.c b/libkern/utflen.c
new file mode 100644
index 00000000..a588bbd1
--- /dev/null
+++ b/libkern/utflen.c
@@ -0,0 +1,22 @@
+#include <lib9.h>
+
+int
+utflen(char *s)
+{
+ int c;
+ long n;
+ Rune rune;
+
+ n = 0;
+ for(;;) {
+ c = *(uchar*)s;
+ if(c < Runeself) {
+ if(c == 0)
+ return n;
+ s++;
+ } else
+ s += chartorune(&rune, s);
+ n++;
+ }
+ return 0;
+}
diff --git a/libkern/utfnlen.c b/libkern/utfnlen.c
new file mode 100644
index 00000000..02623f51
--- /dev/null
+++ b/libkern/utfnlen.c
@@ -0,0 +1,25 @@
+#include "lib9.h"
+
+int
+utfnlen(char *s, long m)
+{
+ int c;
+ long n;
+ Rune rune;
+ char *es;
+
+ es = s + m;
+ for(n = 0; s < es; n++) {
+ c = *(uchar*)s;
+ if(c < Runeself){
+ if(c == '\0')
+ break;
+ s++;
+ continue;
+ }
+ if(!fullrune(s, es-s))
+ break;
+ s += chartorune(&rune, s);
+ }
+ return n;
+}
diff --git a/libkern/utfrrune.c b/libkern/utfrrune.c
new file mode 100644
index 00000000..b4594321
--- /dev/null
+++ b/libkern/utfrrune.c
@@ -0,0 +1,30 @@
+#include <lib9.h>
+
+char*
+utfrrune(char *s, long c)
+{
+ long c1;
+ Rune r;
+ char *s1;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strrchr(s, c);
+
+ s1 = 0;
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return s1;
+ if(c1 == c)
+ s1 = s;
+ s++;
+ continue;
+ }
+ c1 = chartorune(&r, s);
+ if(r == c)
+ s1 = s;
+ s += c1;
+ }
+ return 0;
+}
diff --git a/libkern/utfrune.c b/libkern/utfrune.c
new file mode 100644
index 00000000..9925af81
--- /dev/null
+++ b/libkern/utfrune.c
@@ -0,0 +1,29 @@
+#include <lib9.h>
+
+char*
+utfrune(char *s, long c)
+{
+ long c1;
+ Rune r;
+ int n;
+
+ if(c < Runesync) /* not part of utf sequence */
+ return strchr(s, c);
+
+ for(;;) {
+ c1 = *(uchar*)s;
+ if(c1 < Runeself) { /* one byte rune */
+ if(c1 == 0)
+ return 0;
+ if(c1 == c)
+ return s;
+ s++;
+ continue;
+ }
+ n = chartorune(&r, s);
+ if(r == c)
+ return s;
+ s += n;
+ }
+ return 0;
+}
diff --git a/libkern/vlop-386.s b/libkern/vlop-386.s
new file mode 100644
index 00000000..42e8a70d
--- /dev/null
+++ b/libkern/vlop-386.s
@@ -0,0 +1,44 @@
+TEXT _mulv(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+4(FP), AX
+ MULL b+16(FP)
+ ADDL AX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _mul64by32(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _div64by32(SB), $0
+ MOVL r+12(FP), CX
+ MOVL a+0(FP), AX
+ MOVL a+4(FP), DX
+ DIVL b+8(FP)
+ MOVL DX, 0(CX)
+ RET
+
+TEXT _addv(SB), $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MOVL a+8(FP), BX
+ ADDL b+12(FP), AX
+ ADCL b+16(FP), BX
+ MOVL AX, 0(CX)
+ MOVL BX, 4(CX)
+ RET
diff --git a/libkern/vlop-arm.s b/libkern/vlop-arm.s
new file mode 100644
index 00000000..d972ac1b
--- /dev/null
+++ b/libkern/vlop-arm.s
@@ -0,0 +1,34 @@
+#define UMULL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(4<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define UMLAL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(5<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define MUL(Rs,Rm,Rd,S) WORD $((14<<28)|(0<<21)|(S<<20)|(Rd<<16)|(Rs<<8)|(9<<4)|Rm)
+arg=0
+
+/* replaced use of R10 by R11 because the former can be the data segment base register */
+
+TEXT _mulv(SB), $0
+ MOVW 8(FP), R9 /* l0 */
+ MOVW 4(FP), R11 /* h0 */
+ MOVW 16(FP), R4 /* l1 */
+ MOVW 12(FP), R5 /* h1 */
+ UMULL(4, 9, 7, 6, 0)
+ MUL(11, 4, 8, 0)
+ ADD R8, R7
+ MUL(9, 5, 8, 0)
+ ADD R8, R7
+ MOVW R6, 4(R(arg))
+ MOVW R7, 0(R(arg))
+ RET
+
+/* multiply, add, and right-shift, yielding a 32-bit result, while
+ using 64-bit accuracy for the multiply -- for fast fixed-point math */
+TEXT _mularsv(SB), $0
+ MOVW 4(FP), R11 /* m1 */
+ MOVW 8(FP), R8 /* a */
+ MOVW 12(FP), R4 /* rs */
+ MOVW $0, R9
+ UMLAL(0, 11, 9, 8, 0)
+ MOVW R8>>R4, R8
+ RSB $32, R4, R4
+ ORR R9<<R4, R8, R0
+ RET
+
diff --git a/libkern/vlop-mips.s b/libkern/vlop-mips.s
new file mode 100644
index 00000000..17f487ad
--- /dev/null
+++ b/libkern/vlop-mips.s
@@ -0,0 +1,17 @@
+TEXT _mulv(SB), $0
+ MOVW 8(FP), R2
+ MOVW 4(FP), R3
+ MOVW 16(FP), R4
+ MOVW 12(FP), R5
+ MULU R4, R2
+ MOVW LO, R6
+ MOVW HI, R7
+ MULU R3, R4
+ MOVW LO, R8
+ ADDU R8, R7
+ MULU R2, R5
+ MOVW LO, R8
+ ADDU R8, R7
+ MOVW R6, 4(R1)
+ MOVW R7, 0(R1)
+ RET
diff --git a/libkern/vlop-power.s b/libkern/vlop-power.s
new file mode 100644
index 00000000..715ef14d
--- /dev/null
+++ b/libkern/vlop-power.s
@@ -0,0 +1,14 @@
+TEXT _mulv(SB), $0
+ MOVW 8(FP), R9
+ MOVW 4(FP), R10
+ MOVW 16(FP), R4
+ MOVW 12(FP), R5
+ MULLW R4, R9, R6
+ MULHWU R4, R9, R7
+ MULLW R10, R4, R8
+ ADD R8, R7
+ MULLW R9, R5, R8
+ ADD R8, R7
+ MOVW R6, 4(R3)
+ MOVW R7, 0(R3)
+ RETURN
diff --git a/libkern/vlop-sparc.s b/libkern/vlop-sparc.s
new file mode 100644
index 00000000..ac36b414
--- /dev/null
+++ b/libkern/vlop-sparc.s
@@ -0,0 +1,112 @@
+TEXT _mulv(SB), $0
+ MOVW u1+8(FP), R8
+ MOVW u2+16(FP), R13
+
+ MOVW R13, R16 /* save low parts for later */
+ MOVW R8, R12
+
+ /*
+ * unsigned 32x32 => 64 multiply
+ */
+ CMP R13, R8
+ BLE mul1
+ MOVW R12, R13
+ MOVW R16, R8
+mul1:
+ MOVW R13, Y
+ ANDNCC $0xFFF, R13, R0
+ BE mul_shortway
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+
+ /* long multiply */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R8, R9, R9 /* 12 */
+ MULSCC R8, R9, R9 /* 13 */
+ MULSCC R8, R9, R9 /* 14 */
+ MULSCC R8, R9, R9 /* 15 */
+ MULSCC R8, R9, R9 /* 16 */
+ MULSCC R8, R9, R9 /* 17 */
+ MULSCC R8, R9, R9 /* 18 */
+ MULSCC R8, R9, R9 /* 19 */
+ MULSCC R8, R9, R9 /* 20 */
+ MULSCC R8, R9, R9 /* 21 */
+ MULSCC R8, R9, R9 /* 22 */
+ MULSCC R8, R9, R9 /* 23 */
+ MULSCC R8, R9, R9 /* 24 */
+ MULSCC R8, R9, R9 /* 25 */
+ MULSCC R8, R9, R9 /* 26 */
+ MULSCC R8, R9, R9 /* 27 */
+ MULSCC R8, R9, R9 /* 28 */
+ MULSCC R8, R9, R9 /* 29 */
+ MULSCC R8, R9, R9 /* 30 */
+ MULSCC R8, R9, R9 /* 31 */
+ MULSCC R0, R9, R9 /* 32; shift only; r9 is high part */
+
+ /*
+ * need to correct top word if top bit set
+ */
+ CMP R8, R0
+ BGE mul_tstlow
+ ADD R13, R9 /* adjust the high parts */
+
+mul_tstlow:
+ MOVW Y, R13 /* get low part */
+ BA mul_done
+
+mul_shortway:
+ ANDCC R0, R0, R9 /* zero partial product and clear N and V cond's */
+ MULSCC R8, R9, R9 /* 0 */
+ MULSCC R8, R9, R9 /* 1 */
+ MULSCC R8, R9, R9 /* 2 */
+ MULSCC R8, R9, R9 /* 3 */
+ MULSCC R8, R9, R9 /* 4 */
+ MULSCC R8, R9, R9 /* 5 */
+ MULSCC R8, R9, R9 /* 6 */
+ MULSCC R8, R9, R9 /* 7 */
+ MULSCC R8, R9, R9 /* 8 */
+ MULSCC R8, R9, R9 /* 9 */
+ MULSCC R8, R9, R9 /* 10 */
+ MULSCC R8, R9, R9 /* 11 */
+ MULSCC R0, R9, R9 /* 12; shift only; r9 is high part */
+
+ MOVW Y, R8 /* make low part of partial low part & high part */
+ SLL $12, R9, R13
+ SRL $20, R8
+ OR R8, R13
+
+ SRA $20, R9 /* high part */
+
+mul_done:
+
+ /*
+ * mul by high halves if needed
+ */
+ MOVW R13, 4(R7)
+ MOVW u2+12(FP), R11
+ CMP R11, R0
+ BE nomul1
+ MUL R11, R12
+ ADD R12, R9
+
+nomul1:
+ MOVW u1+4(FP), R11
+ CMP R11, R0
+ BE nomul2
+ MUL R11, R16
+ ADD R16, R9
+
+nomul2:
+
+ MOVW R9, 0(R7)
+ RETURN
diff --git a/libkern/vlop-thumb.s b/libkern/vlop-thumb.s
new file mode 100644
index 00000000..d972ac1b
--- /dev/null
+++ b/libkern/vlop-thumb.s
@@ -0,0 +1,34 @@
+#define UMULL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(4<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define UMLAL(Rs,Rm,Rhi,Rlo,S) WORD $((14<<28)|(5<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define MUL(Rs,Rm,Rd,S) WORD $((14<<28)|(0<<21)|(S<<20)|(Rd<<16)|(Rs<<8)|(9<<4)|Rm)
+arg=0
+
+/* replaced use of R10 by R11 because the former can be the data segment base register */
+
+TEXT _mulv(SB), $0
+ MOVW 8(FP), R9 /* l0 */
+ MOVW 4(FP), R11 /* h0 */
+ MOVW 16(FP), R4 /* l1 */
+ MOVW 12(FP), R5 /* h1 */
+ UMULL(4, 9, 7, 6, 0)
+ MUL(11, 4, 8, 0)
+ ADD R8, R7
+ MUL(9, 5, 8, 0)
+ ADD R8, R7
+ MOVW R6, 4(R(arg))
+ MOVW R7, 0(R(arg))
+ RET
+
+/* multiply, add, and right-shift, yielding a 32-bit result, while
+ using 64-bit accuracy for the multiply -- for fast fixed-point math */
+TEXT _mularsv(SB), $0
+ MOVW 4(FP), R11 /* m1 */
+ MOVW 8(FP), R8 /* a */
+ MOVW 12(FP), R4 /* rs */
+ MOVW $0, R9
+ UMLAL(0, 11, 9, 8, 0)
+ MOVW R8>>R4, R8
+ RSB $32, R4, R4
+ ORR R9<<R4, R8, R0
+ RET
+
diff --git a/libkern/vlrt-386.c b/libkern/vlrt-386.c
new file mode 100644
index 00000000..f0b100ef
--- /dev/null
+++ b/libkern/vlrt-386.c
@@ -0,0 +1,695 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ struct
+ {
+ ushort lols;
+ ushort loms;
+ ushort hils;
+ ushort hims;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+ulong _div64by32(Vlong, ulong, ulong*);
+void _mul64by32(Vlong*, Vlong, ulong);
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong n;
+ Vlong x, q, r;
+
+ if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+ if(qp) {
+ qp->hi = 0;
+ qp->lo = 0;
+ }
+ if(rp) {
+ rp->hi = num.hi;
+ rp->lo = num.lo;
+ }
+ return;
+ }
+
+ if(den.hi != 0){
+ q.hi = 0;
+ n = num.hi/den.hi;
+ _mul64by32(&x, den, n);
+ if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)){
+ n--;
+ _mul64by32(&x, den, n);
+ }
+ q.lo = n;
+ _subv(&r, num, x);
+ } else {
+ if(num.hi >= den.lo){
+ q.hi = n = num.hi/den.lo;
+ num.hi -= den.lo*n;
+ } else {
+ q.hi = 0;
+ }
+ q.lo = _div64by32(num, den.lo, &r.lo);
+ r.hi = 0;
+ }
+ if(qp) {
+ qp->lo = q.lo;
+ qp->hi = q.hi;
+ }
+ if(rp) {
+ rp->lo = r.lo;
+ rp->hi = r.hi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/libkern/vlrt-68000.c b/libkern/vlrt-68000.c
new file mode 100644
index 00000000..071aa180
--- /dev/null
+++ b/libkern/vlrt-68000.c
@@ -0,0 +1,771 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_negv(Vlong *r, Vlong a)
+{
+ if(a.lo == 0) {
+ r->hi = -a.hi;
+ r->lo = 0;
+ return;
+ }
+ r->hi = ~a.hi;
+ r->lo = -a.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+void
+_mulv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong ahi, alo, chi, clo, x;
+ int i;
+
+ ahi = a.hi;
+ alo = a.lo;
+ chi = 0;
+ clo = 0;
+
+ x = b.lo;
+ for(i=0; i<32; i++) {
+ if(x & 1) {
+ chi += ahi;
+ clo += alo;
+ if(clo < alo)
+ chi++;
+ }
+ ahi <<= 1;
+ if(alo & SIGN(32))
+ ahi += 1;
+ alo <<= 1;
+ x >>= 1;
+ }
+
+ /*
+ * same, but
+ * alo is known to be 0
+ * can stop when x == 0
+ */
+ for(x=b.hi; x; x>>=1) {
+ if(x & 1)
+ chi += ahi;
+ ahi <<= 1;
+ }
+
+ r->hi = chi;
+ r->lo = clo;
+}
diff --git a/libkern/vlrt-arm.c b/libkern/vlrt-arm.c
new file mode 100644
index 00000000..58cf5591
--- /dev/null
+++ b/libkern/vlrt-arm.c
@@ -0,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/libkern/vlrt-mips.c b/libkern/vlrt-mips.c
new file mode 100644
index 00000000..96456277
--- /dev/null
+++ b/libkern/vlrt-mips.c
@@ -0,0 +1,719 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(qp) {
+ qp->lo = quolo;
+ qp->hi = quohi;
+ }
+ if(rp) {
+ rp->lo = numlo;
+ rp->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/libkern/vlrt-power.c b/libkern/vlrt-power.c
new file mode 100644
index 00000000..6fbd83ca
--- /dev/null
+++ b/libkern/vlrt-power.c
@@ -0,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/libkern/vlrt-sparc.c b/libkern/vlrt-sparc.c
new file mode 100644
index 00000000..6fbd83ca
--- /dev/null
+++ b/libkern/vlrt-sparc.c
@@ -0,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/libkern/vlrt-thumb.c b/libkern/vlrt-thumb.c
new file mode 100644
index 00000000..58cf5591
--- /dev/null
+++ b/libkern/vlrt-thumb.c
@@ -0,0 +1,718 @@
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ struct
+ {
+ ulong hi;
+ ulong lo;
+ };
+ struct
+ {
+ ushort hims;
+ ushort hils;
+ ushort loms;
+ ushort lols;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+ ulong lo, hi;
+
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/libkern/vseprint.c b/libkern/vseprint.c
new file mode 100644
index 00000000..7b23d55b
--- /dev/null
+++ b/libkern/vseprint.c
@@ -0,0 +1,34 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+ Fmt f;
+
+ if(e <= buf)
+ return nil;
+ f.runes = 0;
+ f.start = buf;
+ f.to = buf;
+ f.stop = e - 1;
+ f.flush = nil;
+ f.farg = nil;
+ f.nfmt = 0;
+ f.args = args;
+ dofmt(&f, fmt);
+ *(char*)f.to = '\0';
+ return f.to;
+}
diff --git a/libkern/vsmprint.c b/libkern/vsmprint.c
new file mode 100644
index 00000000..44789be5
--- /dev/null
+++ b/libkern/vsmprint.c
@@ -0,0 +1,74 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+ char *s;
+ int n;
+
+ n = (int)f->farg;
+ n += 256;
+ f->farg = (void*)n;
+ s = f->start;
+ f->start = realloc(s, n);
+ if(f->start == nil){
+ free(s);
+ f->to = nil;
+ f->stop = nil;
+ return 0;
+ }
+ f->to = (char*)f->start + ((char*)f->to - s);
+ f->stop = (char*)f->start + n - 1;
+ return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+ int n;
+
+ f->runes = 0;
+ n = 32;
+ f->start = malloc(n);
+ if(f->start == nil)
+ return -1;
+ f->to = f->start;
+ f->stop = (char*)f->start + n - 1;
+ f->flush = fmtStrFlush;
+ f->farg = (void*)n;
+ f->nfmt = 0;
+ return 0;
+}
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+ Fmt f;
+ int n;
+
+ if(fmtstrinit(&f) < 0)
+ return nil;
+ f.args = args;
+ n = dofmt(&f, fmt);
+ if(n < 0)
+ return nil;
+ *(char*)f.to = '\0';
+ return f.start;
+}
diff --git a/libkern/vsnprint.c b/libkern/vsnprint.c
new file mode 100644
index 00000000..841d142c
--- /dev/null
+++ b/libkern/vsnprint.c
@@ -0,0 +1,34 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+int
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+ Fmt f;
+
+ if(len <= 0)
+ return -1;
+ f.runes = 0;
+ f.start = buf;
+ f.to = buf;
+ f.stop = buf + len - 1;
+ f.flush = nil;
+ f.farg = nil;
+ f.nfmt = 0;
+ f.args = args;
+ dofmt(&f, fmt);
+ *(char*)f.to = '\0';
+ return (char*)f.to - buf;
+}