summaryrefslogtreecommitdiff
path: root/sys/src/libc/arm
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libc/arm
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libc/arm')
-rwxr-xr-xsys/src/libc/arm/argv0.s4
-rwxr-xr-xsys/src/libc/arm/atom.s55
-rwxr-xr-xsys/src/libc/arm/cas.s28
-rwxr-xr-xsys/src/libc/arm/cycles.c7
-rwxr-xr-xsys/src/libc/arm/div.s118
-rwxr-xr-xsys/src/libc/arm/doprint.xc617
-rwxr-xr-xsys/src/libc/arm/getcallerpc.s3
-rwxr-xr-xsys/src/libc/arm/getfcr.s12
-rwxr-xr-xsys/src/libc/arm/main9.s29
-rwxr-xr-xsys/src/libc/arm/main9p.s42
-rwxr-xr-xsys/src/libc/arm/memmove.s212
-rwxr-xr-xsys/src/libc/arm/memset.s60
-rwxr-xr-xsys/src/libc/arm/mkfile36
-rwxr-xr-xsys/src/libc/arm/notejmp.c16
-rwxr-xr-xsys/src/libc/arm/setjmp.s19
-rwxr-xr-xsys/src/libc/arm/strchr.s56
-rwxr-xr-xsys/src/libc/arm/strcmp.s67
-rwxr-xr-xsys/src/libc/arm/strcpy.s46
-rwxr-xr-xsys/src/libc/arm/tas.s5
-rwxr-xr-xsys/src/libc/arm/vlop.s13
-rwxr-xr-xsys/src/libc/arm/vlrt.c708
21 files changed, 2153 insertions, 0 deletions
diff --git a/sys/src/libc/arm/argv0.s b/sys/src/libc/arm/argv0.s
new file mode 100755
index 000000000..8d9f9b29b
--- /dev/null
+++ b/sys/src/libc/arm/argv0.s
@@ -0,0 +1,4 @@
+GLOBL argv0(SB), $4
+GLOBL _tos(SB), $4
+GLOBL _privates(SB), $4
+GLOBL _nprivates(SB), $4
diff --git a/sys/src/libc/arm/atom.s b/sys/src/libc/arm/atom.s
new file mode 100755
index 000000000..674021391
--- /dev/null
+++ b/sys/src/libc/arm/atom.s
@@ -0,0 +1,55 @@
+
+/*
+ * int cas(ulong *p, ulong ov, ulong nv);
+ */
+
+#define LDREX(a,r) WORD $(0xe<<28|0x01900f9f | (a)<<16 | (r)<<12)
+#define STREX(a,v,r) WORD $(0xe<<28|0x01800f90 | (a)<<16 | (r)<<12 | (v)<<0)
+
+TEXT cas+0(SB),0,$12 /* r0 holds p */
+TEXT casp+0(SB),0,$12 /* r0 holds p */
+TEXT casl+0(SB),0,$12 /* r0 holds p */
+ MOVW ov+4(FP), R1
+ MOVW nv+8(FP), R2
+spincas:
+ LDREX(0,3) /* LDREX 0(R0),R3 */
+ CMP.S R3, R1
+ BNE fail
+ STREX(0,2,4) /* STREX 0(R0),R2,R4 */
+ CMP.S $0, R4
+ BNE spincas
+ MOVW $1, R0
+ RET
+fail:
+ MOVW $0, R0
+ RET
+
+TEXT ainc(SB), $0 /* long ainc(long *); */
+spinainc:
+ LDREX(0,3) /* LDREX 0(R0),R3 */
+ ADD $1,R3
+ STREX(0,3,4) /* STREX 0(R0),R2,R4 */
+ CMP.S $0, R4
+ BNE spinainc
+ MOVW R3, R0
+ RET
+
+TEXT adec(SB), $0 /* long ainc(long *); */
+spinadec:
+ LDREX(0,3) /* LDREX 0(R0),R3 */
+ SUB $1,R3
+ STREX(0,3,4) /* STREX 0(R0),R3,R4 */
+ CMP.S $0, R4
+ BNE spinadec
+ MOVW R3, R0
+ RET
+
+TEXT loadlinked(SB), $0 /* long loadlinked(long *); */
+ LDREX(0,0) /* LDREX 0(R0),R0 */
+ RET
+
+TEXT storecond(SB), $0 /* int storecond(long *, long); */
+ MOVW ov+4(FP), R3
+ STREX(0,3,4) /* STREX 0(R0),R3,R0 */
+ RSB $1, R0
+ RET
diff --git a/sys/src/libc/arm/cas.s b/sys/src/libc/arm/cas.s
new file mode 100755
index 000000000..7bb3a05f7
--- /dev/null
+++ b/sys/src/libc/arm/cas.s
@@ -0,0 +1,28 @@
+
+/*
+ * int swp(int r, int *p);
+ * uchar swpb(uchar r, uchar *p);
+ *
+ * int cas(uintptr *p, uintptr ov, uintptr nv);
+ */
+
+#define LDREX(a,r) WORD $(0xe<<28|0x01900f9f | (a)<<16 | (r)<<12)
+#define STREX(a,v,r) WORD $(0xe<<28|0x01800f90 | (a)<<16 | (r)<<12 | (v)<<0)
+
+TEXT cas+0(SB),0,$12 /* r0 holds p */
+ MOVW ov+4(FP), R1
+ MOVW nv+8(FP), R2
+spin:
+/* LDREX 0(R0),R3 */
+ LDREX(0,3)
+ CMP.S R3, R1
+ BNE fail
+/* STREX 0(R0),R2,R4 */
+ STREX(0,2,4)
+ CMP.S $0, R4
+ BNE spin
+ MOVW $1, R0
+ RET
+fail:
+ MOVW $0, R0
+ RET
diff --git a/sys/src/libc/arm/cycles.c b/sys/src/libc/arm/cycles.c
new file mode 100755
index 000000000..9bad3a989
--- /dev/null
+++ b/sys/src/libc/arm/cycles.c
@@ -0,0 +1,7 @@
+#include <u.h>
+#include <libc.h>
+
+void cycles(uvlong*u)
+{
+ *u = 0LL;
+}
diff --git a/sys/src/libc/arm/div.s b/sys/src/libc/arm/div.s
new file mode 100755
index 000000000..2f7699c50
--- /dev/null
+++ b/sys/src/libc/arm/div.s
@@ -0,0 +1,118 @@
+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
+ 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/sys/src/libc/arm/doprint.xc b/sys/src/libc/arm/doprint.xc
new file mode 100755
index 000000000..e3846a8d8
--- /dev/null
+++ b/sys/src/libc/arm/doprint.xc
@@ -0,0 +1,617 @@
+#include <u.h>
+#include <libc.h>
+
+enum
+{
+ SIZE = 1024,
+ IDIGIT = 40,
+ MAXCONV = 40,
+ FDIGIT = 30,
+ FDEFLT = 6,
+ NONE = -1000,
+ MAXFMT = 512,
+
+ FPLUS = 1<<0,
+ FMINUS = 1<<1,
+ FSHARP = 1<<2,
+ FLONG = 1<<3,
+ FSHORT = 1<<4,
+ FUNSIGN = 1<<5,
+ FVLONG = 1<<6,
+};
+
+int printcol;
+
+static int convcount;
+static char fmtindex[MAXFMT];
+
+static int noconv(va_list*, Fconv*);
+static int flags(va_list*, Fconv*);
+
+static int cconv(va_list*, Fconv*);
+static int rconv(va_list*, Fconv*);
+static int sconv(va_list*, Fconv*);
+static int percent(va_list*, Fconv*);
+static int column(va_list*, Fconv*);
+
+int numbconv(va_list*, Fconv*);
+
+static
+int (*fmtconv[MAXCONV])(va_list*, Fconv*) =
+{
+ noconv
+};
+
+static
+void
+initfmt(void)
+{
+ int cc;
+
+ cc = 0;
+ fmtconv[cc] = noconv;
+ cc++;
+
+ fmtconv[cc] = flags;
+ fmtindex['+'] = cc;
+ fmtindex['-'] = cc;
+ fmtindex['#'] = cc;
+ fmtindex['h'] = cc;
+ fmtindex['l'] = cc;
+ fmtindex['u'] = cc;
+ cc++;
+
+ fmtconv[cc] = numbconv;
+ fmtindex['d'] = cc;
+ fmtindex['o'] = cc;
+ fmtindex['x'] = cc;
+ fmtindex['X'] = cc;
+ cc++;
+
+ fmtconv[cc] = cconv;
+ fmtindex['c'] = cc;
+ fmtindex['C'] = cc;
+ cc++;
+
+ fmtconv[cc] = rconv;
+ fmtindex['r'] = cc;
+ cc++;
+
+ fmtconv[cc] = sconv;
+ fmtindex['s'] = cc;
+ fmtindex['S'] = cc;
+ cc++;
+
+ fmtconv[cc] = percent;
+ fmtindex['%'] = cc;
+ cc++;
+
+ fmtconv[cc] = column;
+ fmtindex['|'] = cc;
+ cc++;
+
+ convcount = cc;
+}
+
+int
+fmtinstall(int c, int (*f)(va_list*, Fconv*))
+{
+
+ if(convcount == 0)
+ initfmt();
+ if(c < 0 || c >= MAXFMT)
+ return -1;
+ if(convcount >= MAXCONV)
+ return -1;
+ fmtconv[convcount] = f;
+ fmtindex[c] = convcount;
+ convcount++;
+ return 0;
+}
+
+char*
+doprint(char *s, char *es, char *fmt, va_list argp)
+{
+ int n, c;
+ Rune rune;
+ Fconv local;
+
+ if(s >= es)
+ return s;
+ local.out = s;
+ local.eout = es-UTFmax-1;
+
+loop:
+ c = *fmt & 0xff;
+ if(c >= Runeself) {
+ n = chartorune(&rune, fmt);
+ fmt += n;
+ c = rune;
+ } else
+ fmt++;
+ switch(c) {
+ case 0:
+ *local.out = 0;
+ return local.out;
+
+ default:
+ printcol++;
+ goto common;
+
+ case '\n':
+ printcol = 0;
+ goto common;
+
+ case '\t':
+ printcol = (printcol+8) & ~7;
+ goto common;
+
+ common:
+ if(local.out < local.eout)
+ if(c >= Runeself) {
+ rune = c;
+ n = runetochar(local.out, &rune);
+ local.out += n;
+ } else
+ *local.out++ = c;
+ goto loop;
+
+ case '%':
+ break;
+ }
+ local.f1 = NONE;
+ local.f2 = NONE;
+ local.f3 = 0;
+
+ /*
+ * read one of the following
+ * 1. number, => f1, f2 in order.
+ * 2. '*' same as number (from args)
+ * 3. '.' ignored (separates numbers)
+ * 4. flag => f3
+ * 5. verb and terminate
+ */
+l0:
+ c = *fmt & 0xff;
+ if(c >= Runeself) {
+ n = chartorune(&rune, fmt);
+ fmt += n;
+ c = rune;
+ } else
+ fmt++;
+
+l1:
+ if(c == 0) {
+ fmt--;
+ goto loop;
+ }
+ if(c == '.') {
+ if(local.f1 == NONE)
+ local.f1 = 0;
+ local.f2 = 0;
+ goto l0;
+ }
+ if((c >= '1' && c <= '9') ||
+ (c == '0' && local.f1 != NONE)) { /* '0' is a digit for f2 */
+ n = 0;
+ while(c >= '0' && c <= '9') {
+ n = n*10 + c-'0';
+ c = *fmt++;
+ }
+ if(local.f1 == NONE)
+ local.f1 = n;
+ else
+ local.f2 = n;
+ goto l1;
+ }
+ if(c == '*') {
+ n = va_arg(argp, int);
+ if(local.f1 == NONE)
+ local.f1 = n;
+ else
+ local.f2 = n;
+ goto l0;
+ }
+ n = 0;
+ if(c >= 0 && c < MAXFMT)
+ n = fmtindex[c];
+ local.chr = c;
+ n = (*fmtconv[n])(&argp, &local);
+ if(n < 0) {
+ local.f3 |= -n;
+ goto l0;
+ }
+ goto loop;
+}
+
+int
+numbconv(va_list *arg, Fconv *fp)
+{
+ char s[IDIGIT];
+ int i, f, n, b, ucase;
+ short h;
+ long v;
+ vlong vl;
+
+ SET(v);
+ SET(vl);
+
+ ucase = 0;
+ b = fp->chr;
+ switch(fp->chr) {
+ case 'u':
+ fp->f3 |= FUNSIGN;
+ case 'd':
+ b = 10;
+ break;
+
+ case 'o':
+ b = 8;
+ break;
+
+ case 'X':
+ ucase = 1;
+ case 'x':
+ b = 16;
+ break;
+ }
+
+ f = 0;
+ switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) {
+ case FVLONG|FLONG:
+ vl = va_arg(*arg, vlong);
+ break;
+
+ case FUNSIGN|FVLONG|FLONG:
+ vl = va_arg(*arg, uvlong);
+ break;
+
+ case FLONG:
+ v = va_arg(*arg, long);
+ break;
+
+ case FUNSIGN|FLONG:
+ v = va_arg(*arg, ulong);
+ break;
+
+ case FSHORT:
+ h = va_arg(*arg, int);
+ v = h;
+ break;
+
+ case FUNSIGN|FSHORT:
+ h = va_arg(*arg, int);
+ v = (ushort)h;
+ break;
+
+ default:
+ v = va_arg(*arg, int);
+ break;
+
+ case FUNSIGN:
+ v = va_arg(*arg, unsigned);
+ break;
+ }
+ if(fp->f3 & FVLONG) {
+ if(!(fp->f3 & FUNSIGN) && vl < 0) {
+ vl = -vl;
+ f = 1;
+ }
+ } else {
+ if(!(fp->f3 & FUNSIGN) && v < 0) {
+ v = -v;
+ f = 1;
+ }
+ }
+ s[IDIGIT-1] = 0;
+ for(i = IDIGIT-2;; i--) {
+ if(fp->f3 & FVLONG)
+ n = (uvlong)vl % b;
+ else
+ n = (ulong)v % b;
+ n += '0';
+ if(n > '9') {
+ n += 'a' - ('9'+1);
+ if(ucase)
+ n += 'A'-'a';
+ }
+ s[i] = n;
+ if(i < 2)
+ break;
+ if(fp->f3 & FVLONG)
+ vl = (uvlong)vl / b;
+ else
+ v = (ulong)v / b;
+ if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
+ continue;
+ if(fp->f3 & FVLONG) {
+ if(vl <= 0)
+ break;
+ continue;
+ }
+ if(v <= 0)
+ break;
+ }
+
+ if(fp->f3 & FSHARP) {
+ if(b == 8 && s[i] != '0')
+ s[--i] = '0';
+ if(b == 16) {
+ if(ucase)
+ s[--i] = 'X';
+ else
+ s[--i] = 'x';
+ s[--i] = '0';
+ }
+ }
+ if(f)
+ s[--i] = '-';
+ fp->f2 = NONE;
+ strconv(s+i, fp);
+ return 0;
+}
+
+void
+Strconv(Rune *s, Fconv *fp)
+{
+ int n, c, i;
+ Rune rune;
+
+ if(fp->f3 & FMINUS)
+ fp->f1 = -fp->f1;
+ n = 0;
+ if(fp->f1 != NONE && fp->f1 >= 0) {
+ for(; s[n]; n++)
+ ;
+ while(n < fp->f1) {
+ if(fp->out < fp->eout)
+ *fp->out++ = ' ';
+ printcol++;
+ n++;
+ }
+ }
+ for(;;) {
+ c = *s++;
+ if(c == 0)
+ break;
+ n++;
+ if(fp->f2 == NONE || fp->f2 > 0) {
+ if(fp->out < fp->eout)
+ if(c >= Runeself) {
+ rune = c;
+ i = runetochar(fp->out, &rune);
+ fp->out += i;
+ } else
+ *fp->out++ = c;
+ if(fp->f2 != NONE)
+ fp->f2--;
+ switch(c) {
+ default:
+ printcol++;
+ break;
+ case '\n':
+ printcol = 0;
+ break;
+ case '\t':
+ printcol = (printcol+8) & ~7;
+ break;
+ }
+ }
+ }
+ if(fp->f1 != NONE && fp->f1 < 0) {
+ fp->f1 = -fp->f1;
+ while(n < fp->f1) {
+ if(fp->out < fp->eout)
+ *fp->out++ = ' ';
+ printcol++;
+ n++;
+ }
+ }
+}
+
+void
+strconv(char *s, Fconv *fp)
+{
+ int n, c, i;
+ Rune rune;
+
+ if(fp->f3 & FMINUS)
+ fp->f1 = -fp->f1;
+ n = 0;
+ if(fp->f1 != NONE && fp->f1 >= 0) {
+ n = utflen(s);
+ while(n < fp->f1) {
+ if(fp->out < fp->eout)
+ *fp->out++ = ' ';
+ printcol++;
+ n++;
+ }
+ }
+ for(;;) {
+ c = *s & 0xff;
+ if(c >= Runeself) {
+ i = chartorune(&rune, s);
+ s += i;
+ c = rune;
+ } else
+ s++;
+ if(c == 0)
+ break;
+ n++;
+ if(fp->f2 == NONE || fp->f2 > 0) {
+ if(fp->out < fp->eout)
+ if(c >= Runeself) {
+ rune = c;
+ i = runetochar(fp->out, &rune);
+ fp->out += i;
+ } else
+ *fp->out++ = c;
+ if(fp->f2 != NONE)
+ fp->f2--;
+ switch(c) {
+ default:
+ printcol++;
+ break;
+ case '\n':
+ printcol = 0;
+ break;
+ case '\t':
+ printcol = (printcol+8) & ~7;
+ break;
+ }
+ }
+ }
+ if(fp->f1 != NONE && fp->f1 < 0) {
+ fp->f1 = -fp->f1;
+ while(n < fp->f1) {
+ if(fp->out < fp->eout)
+ *fp->out++ = ' ';
+ printcol++;
+ n++;
+ }
+ }
+}
+
+static
+int
+noconv(va_list *arg, Fconv *fp)
+{
+ int n;
+ char s[10];
+
+ if(convcount == 0) {
+ initfmt();
+ n = 0;
+ if(fp->chr >= 0 && fp->chr < MAXFMT)
+ n = fmtindex[fp->chr];
+ return (*fmtconv[n])(arg, fp);
+ }
+ s[0] = '*';
+ s[1] = fp->chr;
+ s[2] = '*';
+ s[3] = 0;
+ fp->f1 = 0;
+ fp->f2 = NONE;
+ fp->f3 = 0;
+ strconv(s, fp);
+ return 0;
+}
+
+static
+int
+rconv(va_list*, Fconv *fp)
+{
+ char s[ERRLEN];
+
+ s[0] = 0;
+ errstr(s);
+ fp->f2 = NONE;
+ strconv(s, fp);
+ return 0;
+}
+
+static
+int
+cconv(va_list *arg, Fconv *fp)
+{
+ char s[10];
+ Rune rune;
+
+ rune = va_arg(*arg, int);
+ if(fp->chr == 'c')
+ rune &= 0xff;
+ s[runetochar(s, &rune)] = 0;
+
+ fp->f2 = NONE;
+ strconv(s, fp);
+ return 0;
+}
+
+static
+int
+sconv(va_list *arg, Fconv *fp)
+{
+ char *s;
+ Rune *r;
+
+ if(fp->chr == 's') {
+ s = va_arg(*arg, char*);
+ if(s == 0)
+ s = "<null>";
+ strconv(s, fp);
+ } else {
+ r = va_arg(*arg, Rune*);
+ if(r == 0)
+ r = L"<null>";
+ Strconv(r, fp);
+ }
+ return 0;
+}
+
+static
+int
+percent(va_list*, Fconv *fp)
+{
+
+ if(fp->out < fp->eout)
+ *fp->out++ = '%';
+ printcol++;
+ return 0;
+}
+
+static
+int
+column(va_list *arg, Fconv *fp)
+{
+ int col, pc;
+
+ col = va_arg(*arg, int);
+ while(fp->out < fp->eout && printcol < col) {
+ pc = (printcol+8) & ~7;
+ if(pc <= col) {
+ *fp->out++ = '\t';
+ printcol = pc;
+ } else {
+ *fp->out++ = ' ';
+ printcol++;
+ }
+ }
+ return 0;
+}
+
+static
+int
+flags(va_list*, Fconv *fp)
+{
+ int f;
+
+ f = 0;
+ switch(fp->chr) {
+ case '+':
+ f = FPLUS;
+ break;
+
+ case '-':
+ f = FMINUS;
+ break;
+
+ case '#':
+ f = FSHARP;
+ break;
+
+ case 'h':
+ f = FSHORT;
+ break;
+
+ case 'l':
+ f = FLONG;
+ if(fp->f3 & FLONG)
+ f = FVLONG;
+ break;
+
+ case 'u':
+ f = FUNSIGN;
+ break;
+ }
+ return -f;
+}
diff --git a/sys/src/libc/arm/getcallerpc.s b/sys/src/libc/arm/getcallerpc.s
new file mode 100755
index 000000000..ac4575913
--- /dev/null
+++ b/sys/src/libc/arm/getcallerpc.s
@@ -0,0 +1,3 @@
+TEXT getcallerpc(SB), $-4
+ MOVW 0(R13), R0
+ RET
diff --git a/sys/src/libc/arm/getfcr.s b/sys/src/libc/arm/getfcr.s
new file mode 100755
index 000000000..dc9a207bc
--- /dev/null
+++ b/sys/src/libc/arm/getfcr.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/sys/src/libc/arm/main9.s b/sys/src/libc/arm/main9.s
new file mode 100755
index 000000000..14cd31f2d
--- /dev/null
+++ b/sys/src/libc/arm/main9.s
@@ -0,0 +1,29 @@
+#define NPRIVATES 16
+
+arg=0
+sp=13
+sb=12
+
+TEXT _main(SB), 1, $(16 + NPRIVATES*4)
+ MOVW $setR12(SB), R(sb)
+ MOVW R(arg), _tos(SB)
+
+ MOVW $p-64(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ MOVW $inargv+0(FP), R(arg)
+ MOVW R(arg), 8(R(sp))
+ MOVW inargc-4(FP), R(arg)
+ MOVW R(arg), 4(R(sp))
+ BL main(SB)
+loop:
+ MOVW $_exitstr<>(SB), R(arg)
+ MOVW R(arg), 4(R(sp))
+ BL exits(SB)
+ BL _div(SB)
+ B loop
+
+DATA _exitstr<>+0(SB)/4, $"main"
+GLOBL _exitstr<>+0(SB), $5
diff --git a/sys/src/libc/arm/main9p.s b/sys/src/libc/arm/main9p.s
new file mode 100755
index 000000000..e77df7162
--- /dev/null
+++ b/sys/src/libc/arm/main9p.s
@@ -0,0 +1,42 @@
+#define NPRIVATES 16
+
+arg=0
+sp=13
+sb=12
+
+TEXT _mainp(SB), 1, $(16 + NPRIVATES*4)
+ MOVW $setR12(SB), R(sb)
+ MOVW R(arg), _tos(SB)
+
+ MOVW $p-64(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ BL _profmain(SB)
+ MOVW _tos(SB), R1
+ MOVW 4(R1), R0
+ MOVW R0, 0(R1)
+
+ MOVW $inargv+0(FP), R(arg)
+ MOVW R(arg), 8(R(sp))
+ MOVW inargc-4(FP), R(arg)
+ MOVW R(arg), 4(R(sp))
+ BL main(SB)
+loop:
+ MOVW $_exitstr<>(SB), R(arg)
+ MOVW R(arg), 4(R(sp))
+ BL exits(SB)
+ MOVW $_div(SB), R(arg) /* force loading of div */
+ MOVW $_profin(SB), R(arg) /* force loading of profile */
+ B loop
+
+TEXT _savearg(SB), 1, $0
+ RET
+
+TEXT _callpc(SB), 1, $0
+ MOVW argp-4(FP), R(arg)
+ RET
+
+DATA _exitstr<>+0(SB)/4, $"main"
+GLOBL _exitstr<>+0(SB), $5
diff --git a/sys/src/libc/arm/memmove.s b/sys/src/libc/arm/memmove.s
new file mode 100755
index 000000000..346a23d72
--- /dev/null
+++ b/sys/src/libc/arm/memmove.s
@@ -0,0 +1,212 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3 /* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT memcpy(SB), $-4
+ B _memmove
+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-R7]
+ MOVM.DB.W [R4-R7], (R(TE))
+ MOVM.DB.W (R(FROM)), [R4-R7]
+ MOVM.DB.W [R4-R7], (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-R7]
+ MOVM.IA.W [R4-R7], (R(TS))
+ MOVM.IA.W (R(FROM)), [R4-R7]
+ MOVM.IA.W [R4-R7], (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 = 11
+
+BR0 = 6
+BW0 = 7
+BR1 = 7
+BW1 = 8
+
+_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 $8, R(TS), R(TMP) /* do 8-byte chunks if possible */
+ CMP R(TMP), R(TE)
+ BLS _b1tail
+
+ BIC $3, R(FROM) /* align source */
+ MOVW (R(FROM)), R(BR0) /* prime first block register */
+
+_bu8loop:
+ CMP R(TMP), R(TE)
+ BLS _bu1tail
+
+ MOVW R(BR0)<<R(LSHIFT), R(BW1)
+ MOVM.DB.W (R(FROM)), [R(BR0)-R(BR1)]
+ 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(BW1)], (R(TE))
+ B _bu8loop
+
+_bu1tail:
+ ADD R(OFFSET), R(FROM)
+ B _b1tail
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 11
+
+FW0 = 6
+FR0 = 7
+FW1 = 7
+FR1 = 8
+
+_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 $8, R(TE), R(TMP) /* do 8-byte chunks if possible */
+ CMP R(TMP), R(TS)
+ BHS _f1tail
+
+ BIC $3, R(FROM) /* align source */
+ MOVW.P 4(R(FROM)), R(FR1) /* prime last block register, implicit write back */
+
+_fu8loop:
+ CMP R(TMP), R(TS)
+ BHS _fu1tail
+
+ MOVW R(FR1)>>R(RSHIFT), R(FW0)
+ MOVM.IA.W (R(FROM)), [R(FR0)-R(FR1)]
+ ORR R(FR0)<<R(LSHIFT), R(FW0)
+
+ MOVW R(FR0)>>R(RSHIFT), R(FW1)
+ ORR R(FR1)<<R(LSHIFT), R(FW1)
+
+ MOVM.IA.W [R(FW0)-R(FW1)], (R(TS))
+ B _fu8loop
+
+_fu1tail:
+ SUB R(OFFSET), R(FROM)
+ B _f1tail
diff --git a/sys/src/libc/arm/memset.s b/sys/src/libc/arm/memset.s
new file mode 100755
index 000000000..7ebbb44c3
--- /dev/null
+++ b/sys/src/libc/arm/memset.s
@@ -0,0 +1,60 @@
+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)
+ ORR R(4)<<8, R(4)
+ ORR R(4)<<16, R(4) /* replicate to word */
+
+_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 $15, R(TOE), R(TMP) /* do 16-byte chunks if possible */
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVW R4, R5 /* replicate */
+ MOVW R4, R6
+ MOVW R4, R7
+
+_f16loop:
+ CMP R(TMP), R(TO)
+ BHS _4tail
+
+ MOVM.IA.W [R4-R7], (R(TO))
+ B _f16loop
+
+_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/sys/src/libc/arm/mkfile b/sys/src/libc/arm/mkfile
new file mode 100755
index 000000000..14f81e1b8
--- /dev/null
+++ b/sys/src/libc/arm/mkfile
@@ -0,0 +1,36 @@
+objtype=arm
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libc.a
+SFILES=\
+ argv0.s\
+ atom.s\
+ div.s\
+ getcallerpc.s\
+ getfcr.s\
+ main9.s\
+ main9p.s\
+ memmove.s\
+ memset.s\
+ setjmp.s\
+ strchr.s\
+ strcmp.s\
+ strcpy.s\
+ tas.s\
+ vlop.s\
+
+CFILES=\
+ cycles.c\
+ notejmp.c\
+ vlrt.c\
+
+HFILES=/sys/include/libc.h
+
+OFILES=${CFILES:%.c=%.$O} ${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+ $HFILES\
+ $CFILES\
+ $SFILES\
+
+</sys/src/cmd/mksyslib
diff --git a/sys/src/libc/arm/notejmp.c b/sys/src/libc/arm/notejmp.c
new file mode 100755
index 000000000..a8a555022
--- /dev/null
+++ b/sys/src/libc/arm/notejmp.c
@@ -0,0 +1,16 @@
+#include <u.h>
+#include <libc.h>
+#include <ureg.h>
+
+void
+notejmp(void *vr, jmp_buf j, int ret)
+{
+ struct Ureg *r = vr;
+
+ r->r0 = ret;
+ if(ret == 0)
+ r->r0 = 1;
+ r->pc = j[JMPBUFPC];
+ r->r13 = j[JMPBUFSP];
+ noted(NCONT);
+}
diff --git a/sys/src/libc/arm/setjmp.s b/sys/src/libc/arm/setjmp.s
new file mode 100755
index 000000000..64bdc2196
--- /dev/null
+++ b/sys/src/libc/arm/setjmp.s
@@ -0,0 +1,19 @@
+arg=0
+link=14
+sp=13
+
+TEXT setjmp(SB), 1, $-4
+ MOVW R(sp), (R(arg+0))
+ MOVW R(link), 4(R(arg+0))
+ MOVW $0, R0
+ RET
+
+TEXT longjmp(SB), 1, $-4
+ MOVW r+4(FP), R(arg+2)
+ CMP $0, R(arg+2)
+ BNE ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVW $1, R(arg+2) /* bless their pointed heads */
+ok: MOVW (R(arg+0)), R(sp)
+ MOVW 4(R(arg+0)), R(link)
+ MOVW R(arg+2), R(arg+0)
+ RET
diff --git a/sys/src/libc/arm/strchr.s b/sys/src/libc/arm/strchr.s
new file mode 100755
index 000000000..349b5a49f
--- /dev/null
+++ b/sys/src/libc/arm/strchr.s
@@ -0,0 +1,56 @@
+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 */
+ TST.NE R4>>8, R3
+ TST.NE R4>>16, R3
+ TST.NE R4>>24, R3
+ BNE _loop
+
+ TST R4, R3 /* its somewhere, find it and correct */
+ BEQ _sub4
+ TST R4>>8, R3
+ BEQ _sub3
+ TST R4>>16, R3
+ BEQ _sub2
+
+_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/sys/src/libc/arm/strcmp.s b/sys/src/libc/arm/strcmp.s
new file mode 100755
index 000000000..015e51596
--- /dev/null
+++ b/sys/src/libc/arm/strcmp.s
@@ -0,0 +1,67 @@
+TEXT strcmp(SB), $-4
+ MOVW R0, R1
+ MOVW s2+4(FP), R2
+
+ MOVW $0xFF, R3 /* mask */
+
+_align: /* align s1 on 4 */
+ TST $3, R1
+ BEQ _aligned
+
+ MOVBU.P 1(R1), R4 /* implicit write back */
+ MOVBU.P 1(R2), R8 /* implicit write back */
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+ B _align
+
+_aligned: /* is s2 now aligned? */
+ TST $3, R2
+ BNE _unaligned
+
+_aloop:
+ MOVW.P 4(R1), R5 /* 4 at a time */
+ MOVW.P 4(R2), R7
+
+ AND R5, R3, R4
+ AND R7, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ AND R5>>8, R3, R4
+ AND R7>>8, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ AND R5>>16, R3, R4
+ AND R7>>16, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ AND R5>>24, R3, R4
+ AND R7>>24, R3, R8
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+
+ B _aloop
+
+_return:
+ RET
+
+_unaligned:
+ MOVBU.P 1(R1), R4 /* implicit write back */
+ MOVBU.P 1(R2), R8 /* implicit write back */
+ SUB.S R8, R4, R0
+ BNE _return
+ CMP $0, R4
+ BEQ _return
+ B _unaligned
diff --git a/sys/src/libc/arm/strcpy.s b/sys/src/libc/arm/strcpy.s
new file mode 100755
index 000000000..3e69fdc7d
--- /dev/null
+++ b/sys/src/libc/arm/strcpy.s
@@ -0,0 +1,46 @@
+TEXT strcpy(SB), $-4
+ MOVW R0, to+0(FP) /* need to save for return value */
+ MOVW from+4(FP), R1
+ MOVW $0xFF, R2 /* mask */
+
+salign: /* align source on 4 */
+ AND.S $3, R1, R3
+ BEQ dalign
+ MOVBU.P 1(R1), R3 /* implicit write back */
+ TST R3, R2
+ MOVBU.P R3, 1(R0) /* implicit write back */
+ BNE salign
+ B return
+
+dalign: /* is destination now aligned? */
+ AND.S $3, R0, R3
+ BNE uloop
+
+aloop:
+ MOVW.P 4(R1), R4 /* read 4, write 4 */
+ TST R4, R2 /* AND.S R3, R2, Rx */
+ TST.NE R4>>8, R2
+ TST.NE R4>>16, R2
+ TST.NE R4>>24, R2
+ BEQ tail
+ MOVW.P R4, 4(R0)
+ B aloop
+
+uloop:
+ MOVW.P 4(R1), R4 /* read 4, write 1,1,1,1 */
+
+tail:
+ AND.S R4, R2, R3
+ MOVBU.NE.P R3, 1(R0)
+ AND.NE.S R4>>8, R2, R3
+ MOVBU.NE.P R3, 1(R0)
+ AND.NE.S R4>>16, R2, R3
+ MOVBU.NE.P R3, 1(R0)
+ AND.NE.S R4>>24, R2, R3
+ MOVBU.P R3, 1(R0)
+ BNE uloop
+ B return
+
+return:
+ MOVW to+0(FP), R0
+ RET
diff --git a/sys/src/libc/arm/tas.s b/sys/src/libc/arm/tas.s
new file mode 100755
index 000000000..15febbd2c
--- /dev/null
+++ b/sys/src/libc/arm/tas.s
@@ -0,0 +1,5 @@
+TEXT _tas(SB), $-4
+ MOVW R0,R1
+ MOVW $1,R0
+ SWPW R0,(R1) /* fix: deprecated in armv7 */
+ RET
diff --git a/sys/src/libc/arm/vlop.s b/sys/src/libc/arm/vlop.s
new file mode 100755
index 000000000..3a5375541
--- /dev/null
+++ b/sys/src/libc/arm/vlop.s
@@ -0,0 +1,13 @@
+TEXT _mulv(SB), $0
+ MOVW 4(FP),R8 /* l0 */
+ MOVW 8(FP),R11 /* h0 */
+ MOVW 12(FP),R4 /* l1 */
+ MOVW 16(FP),R5 /* h1 */
+ MULLU R8,R4,(R6, R7) /* l0*l1 */
+ MUL R8,R5,R5 /* l0*h1 */
+ MUL R11,R4,R4 /* h0*l1 */
+ ADD R4,R6
+ ADD R5,R6
+ MOVW R6,4(R0)
+ MOVW R7,0(R0)
+ RET
diff --git a/sys/src/libc/arm/vlrt.c b/sys/src/libc/arm/vlrt.c
new file mode 100755
index 000000000..5e9524d34
--- /dev/null
+++ b/sys/src/libc/arm/vlrt.c
@@ -0,0 +1,708 @@
+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
+{
+ ulong lo;
+ ulong hi;
+};
+
+void abort(void);
+
+/* needed by profiler; can't be profiled */
+#pragma profile off
+
+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;
+}
+
+#pragma profile on
+
+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);
+}