summaryrefslogtreecommitdiff
path: root/sys/src/libc/mips
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/mips
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libc/mips')
-rwxr-xr-xsys/src/libc/mips/argv0.s4
-rwxr-xr-xsys/src/libc/mips/atom.s57
-rwxr-xr-xsys/src/libc/mips/cycles.c7
-rwxr-xr-xsys/src/libc/mips/getcallerpc.s4
-rwxr-xr-xsys/src/libc/mips/getfcr.s15
-rwxr-xr-xsys/src/libc/mips/lock.c169
-rwxr-xr-xsys/src/libc/mips/main9.s25
-rwxr-xr-xsys/src/libc/mips/main9p.s36
-rwxr-xr-xsys/src/libc/mips/memccpy.s20
-rwxr-xr-xsys/src/libc/mips/memchr.s39
-rwxr-xr-xsys/src/libc/mips/memcmp.s114
-rwxr-xr-xsys/src/libc/mips/memmove.s237
-rwxr-xr-xsys/src/libc/mips/memset.s88
-rwxr-xr-xsys/src/libc/mips/mkfile40
-rwxr-xr-xsys/src/libc/mips/notejmp.c16
-rwxr-xr-xsys/src/libc/mips/setjmp.s14
-rwxr-xr-xsys/src/libc/mips/sqrt.c103
-rwxr-xr-xsys/src/libc/mips/strchr.s63
-rwxr-xr-xsys/src/libc/mips/strcmp.s21
-rwxr-xr-xsys/src/libc/mips/strcpy.s96
-rwxr-xr-xsys/src/libc/mips/tas.s33
-rwxr-xr-xsys/src/libc/mips/vlop.s17
-rwxr-xr-xsys/src/libc/mips/vlrt.c723
23 files changed, 1941 insertions, 0 deletions
diff --git a/sys/src/libc/mips/argv0.s b/sys/src/libc/mips/argv0.s
new file mode 100755
index 000000000..8d9f9b29b
--- /dev/null
+++ b/sys/src/libc/mips/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/mips/atom.s b/sys/src/libc/mips/atom.s
new file mode 100755
index 000000000..8975ac569
--- /dev/null
+++ b/sys/src/libc/mips/atom.s
@@ -0,0 +1,57 @@
+/*
+ * R4000 user-level atomic operations
+ */
+
+#define LL(base, rt) WORD $((060<<26)|((base)<<21)|((rt)<<16))
+#define SC(base, rt) WORD $((070<<26)|((base)<<21)|((rt)<<16))
+#define NOOP WORD $0x27
+
+TEXT ainc(SB), 1, $-4 /* long ainc(long *); */
+TEXT _xinc(SB), 1, $-4 /* void _xinc(long *); */
+ MOVW R1, R2 /* address of counter */
+loop: MOVW $1, R3
+ LL(2, 1)
+ NOOP
+ ADD R1,R3,R3
+ SC(2, 3)
+ NOOP
+ BEQ R3,loop
+ RET
+
+TEXT adec(SB), 1, $-4 /* long adec(long*); */
+TEXT _xdec(SB), 1, $-4 /* long _xdec(long *); */
+ MOVW R1, R2 /* address of counter */
+loop1: MOVW $-1, R3
+ LL(2, 1)
+ NOOP
+ ADD R1,R3,R3
+ MOVW R3, R1
+ SC(2, 3)
+ NOOP
+ BEQ R3,loop1
+ RET
+
+/*
+ * int cas(uint* p, int ov, int nv);
+ */
+TEXT cas(SB), 1, $-4
+ MOVW ov+4(FP), R2
+ MOVW nv+8(FP), R3
+spincas:
+ LL(1, 4) /* R4 = *R1 */
+ NOOP
+ BNE R2, R4, fail
+ SC(1, 3) /* *R1 = R3 */
+ NOOP
+ BEQ R3, spincas /* R3 == 0 means store failed */
+ MOVW $1, R1
+ RET
+fail:
+ MOVW $0, R1
+ RET
+
+/* general-purpose abort */
+_trap:
+ MOVD $0, R0
+ MOVD 0(R0), R0
+ RET
diff --git a/sys/src/libc/mips/cycles.c b/sys/src/libc/mips/cycles.c
new file mode 100755
index 000000000..9bad3a989
--- /dev/null
+++ b/sys/src/libc/mips/cycles.c
@@ -0,0 +1,7 @@
+#include <u.h>
+#include <libc.h>
+
+void cycles(uvlong*u)
+{
+ *u = 0LL;
+}
diff --git a/sys/src/libc/mips/getcallerpc.s b/sys/src/libc/mips/getcallerpc.s
new file mode 100755
index 000000000..7397526e7
--- /dev/null
+++ b/sys/src/libc/mips/getcallerpc.s
@@ -0,0 +1,4 @@
+TEXT getcallerpc(SB), $0
+ MOVW 0(SP), R1
+ RET
+
diff --git a/sys/src/libc/mips/getfcr.s b/sys/src/libc/mips/getfcr.s
new file mode 100755
index 000000000..9e84cbccd
--- /dev/null
+++ b/sys/src/libc/mips/getfcr.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/sys/src/libc/mips/lock.c b/sys/src/libc/mips/lock.c
new file mode 100755
index 000000000..c42208822
--- /dev/null
+++ b/sys/src/libc/mips/lock.c
@@ -0,0 +1,169 @@
+#include <u.h>
+#include <libc.h>
+
+enum
+{
+ Pagesize = 4096,
+ Semperpg = Pagesize/(16*sizeof(uint)),
+ Lockaddr = 0x60000000,
+
+ POWER = 0x320,
+ MAGNUM = 0x330,
+ MAGNUMII = 0x340,
+ R4K = 0x500,
+};
+
+static int arch;
+extern int C_3ktas(int*);
+extern int C_4ktas(int*);
+extern int C_fcr0(void);
+
+static void
+lockinit(void)
+{
+ void *v;
+
+ if(arch != 0)
+ return; /* allow multiple calls */
+ arch = C_fcr0();
+ switch(arch) {
+ case POWER:
+ v = (void*)Lockaddr;
+ if(segattach(SG_CEXEC, "lock", v, Pagesize) == (void*)-1) {
+ arch = MAGNUM;
+ break;
+ }
+ memset(v, 0, Pagesize);
+ break;
+ case MAGNUM:
+ case MAGNUMII:
+ case R4K:
+ break;
+ default:
+ arch = R4K;
+ break;
+ }
+}
+
+void
+lock(Lock *lk)
+{
+ int *hwsem;
+ int hash;
+
+retry:
+ switch(arch) {
+ case 0:
+ lockinit();
+ goto retry;
+ case MAGNUM:
+ case MAGNUMII:
+ while(C_3ktas(&lk->val))
+ sleep(0);
+ return;
+ case R4K:
+ for(;;){
+ while(lk->val)
+ ;
+ if(C_4ktas(&lk->val) == 0)
+ return;
+ }
+ break;
+ case POWER:
+ /* Use low order lock bits to generate hash */
+ hash = ((int)lk/sizeof(int)) & (Semperpg-1);
+ hwsem = (int*)Lockaddr+hash;
+
+ for(;;) {
+ if((*hwsem & 1) == 0) {
+ if(lk->val)
+ *hwsem = 0;
+ else {
+ lk->val = 1;
+ *hwsem = 0;
+ return;
+ }
+ }
+ while(lk->val)
+ ;
+ }
+ }
+}
+
+int
+canlock(Lock *lk)
+{
+ int *hwsem;
+ int hash;
+
+retry:
+ switch(arch) {
+ case 0:
+ lockinit();
+ goto retry;
+ case MAGNUM:
+ case MAGNUMII:
+ if(C_3ktas(&lk->val))
+ return 0;
+ return 1;
+ case R4K:
+ if(C_4ktas(&lk->val))
+ return 0;
+ return 1;
+ case POWER:
+ /* Use low order lock bits to generate hash */
+ hash = ((int)lk/sizeof(int)) & (Semperpg-1);
+ hwsem = (int*)Lockaddr+hash;
+
+ if((*hwsem & 1) == 0) {
+ if(lk->val)
+ *hwsem = 0;
+ else {
+ lk->val = 1;
+ *hwsem = 0;
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+
+void
+unlock(Lock *lk)
+{
+ lk->val = 0;
+}
+
+int
+_tas(int *p)
+{
+ int *hwsem;
+ int hash;
+
+retry:
+ switch(arch) {
+ case 0:
+ lockinit();
+ goto retry;
+ case MAGNUM:
+ case MAGNUMII:
+ return C_3ktas(p);
+ case R4K:
+ return C_4ktas(p);
+ case POWER:
+ /* Use low order lock bits to generate hash */
+ hash = ((int)p/sizeof(int)) & (Semperpg-1);
+ hwsem = (int*)Lockaddr+hash;
+
+ if((*hwsem & 1) == 0) {
+ if(*p)
+ *hwsem = 0;
+ else {
+ *p = 1;
+ *hwsem = 0;
+ return 0;
+ }
+ }
+ return 1;
+ }
+}
diff --git a/sys/src/libc/mips/main9.s b/sys/src/libc/mips/main9.s
new file mode 100755
index 000000000..60ed1c148
--- /dev/null
+++ b/sys/src/libc/mips/main9.s
@@ -0,0 +1,25 @@
+#define NPRIVATES 16
+
+TEXT _main(SB), 1, $(16 + NPRIVATES*4)
+
+ MOVW $setR30(SB), R30
+ MOVW R1, _tos(SB)
+
+ MOVW $p-64(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ MOVW inargc-4(FP), R1
+ MOVW $inargv+0(FP), R2
+ MOVW R1, 4(R29)
+ MOVW R2, 8(R29)
+ JAL main(SB)
+loop:
+ MOVW $_exitstr<>(SB), R1
+ MOVW R1, 4(R29)
+ JAL exits(SB)
+ JMP loop
+
+DATA _exitstr<>+0(SB)/4, $"main"
+GLOBL _exitstr<>+0(SB), $5
diff --git a/sys/src/libc/mips/main9p.s b/sys/src/libc/mips/main9p.s
new file mode 100755
index 000000000..135d07522
--- /dev/null
+++ b/sys/src/libc/mips/main9p.s
@@ -0,0 +1,36 @@
+#define NPRIVATES 16
+
+TEXT _mainp(SB), 1, $(16 + NPRIVATES*4)
+
+ MOVW $setR30(SB), R30
+ MOVW R1, _tos(SB)
+
+ MOVW $p-64(SP), R1
+ MOVW R1, _privates(SB)
+ MOVW $NPRIVATES, R1
+ MOVW R1, _nprivates(SB)
+
+ JAL _profmain(SB)
+ MOVW __prof+4(SB), R1
+ MOVW R1, __prof+0(SB)
+ MOVW inargc-4(FP), R1
+ MOVW $inargv+0(FP), R2
+ MOVW R1, 4(R29)
+ MOVW R2, 8(R29)
+ JAL main(SB)
+loop:
+ MOVW $exits<>(SB), R1
+ MOVW R1, 4(R29)
+ JAL exits(SB)
+ MOVW $_profin(SB), R0 /* force loading of profile */
+ JMP loop
+
+TEXT _savearg(SB), 1, $0
+ RET
+
+TEXT _callpc(SB), 1, $0
+ MOVW argp-4(FP), R1
+ RET
+
+DATA exits<>+0(SB)/4, $"main"
+GLOBL exits<>+0(SB), $5
diff --git a/sys/src/libc/mips/memccpy.s b/sys/src/libc/mips/memccpy.s
new file mode 100755
index 000000000..776dd2768
--- /dev/null
+++ b/sys/src/libc/mips/memccpy.s
@@ -0,0 +1,20 @@
+ TEXT memccpy(SB), $0
+MOVW R1, 0(FP)
+ MOVW n+12(FP), R1
+ BEQ R1, ret
+ MOVW s1+0(FP), R3
+ MOVW s2+4(FP), R2
+ MOVBU c+11(FP), R4
+ ADDU R1, R2, R5
+
+l1: MOVBU (R2), R6
+ ADDU $1, R2
+ MOVBU R6, (R3)
+ ADDU $1, R3
+ BEQ R4, R6, eq
+ BNE R2, R5, l1
+ MOVW $0, R1
+ RET
+
+eq: MOVW R3, R1
+ret: RET
diff --git a/sys/src/libc/mips/memchr.s b/sys/src/libc/mips/memchr.s
new file mode 100755
index 000000000..5d1c3cc85
--- /dev/null
+++ b/sys/src/libc/mips/memchr.s
@@ -0,0 +1,39 @@
+ TEXT memchr(SB), $0
+MOVW R1, 0(FP)
+
+ MOVW n+8(FP), R1
+ MOVW s1+0(FP), R2
+ MOVBU c+7(FP), R3
+ ADDU R1, R2, R6
+
+ AND $(~1), R1, R5
+ ADDU R2, R5
+ BEQ R2, R5, lt2
+
+l1:
+ MOVBU 0(R2), R4
+ MOVBU 1(R2), R7
+ BEQ R3, R4, eq0
+ ADDU $2, R2
+ BEQ R3, R7, eq
+ BNE R2, R5, l1
+
+lt2:
+ BEQ R2, R6, zret
+
+l2:
+ MOVBU (R2), R4
+ ADDU $1, R2
+ BEQ R3, R4, eq
+ BNE R2, R6, l2
+zret:
+ MOVW R0, R1
+ RET
+
+eq0:
+ MOVW R2, R1
+ RET
+
+eq:
+ SUBU $1,R2, R1
+ RET
diff --git a/sys/src/libc/mips/memcmp.s b/sys/src/libc/mips/memcmp.s
new file mode 100755
index 000000000..fb82500d6
--- /dev/null
+++ b/sys/src/libc/mips/memcmp.s
@@ -0,0 +1,114 @@
+ TEXT memcmp(SB), $0
+MOVW R1, 0(FP)
+
+/*
+ * performance:
+ * alligned about 1.0us/call and 17.4mb/sec
+ * unalligned is about 3.1mb/sec
+ */
+
+ MOVW n+8(FP), R3 /* R3 is count */
+ MOVW s1+0(FP), R4 /* R4 is pointer1 */
+ MOVW s2+4(FP), R5 /* R5 is pointer2 */
+ ADDU R3,R4, R6 /* R6 is end pointer1 */
+
+/*
+ * 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 cmp.
+ */
+ SGT $4,R3, R1
+ BNE R1, out
+
+/*
+ * test if both pointers
+ * are similarly word alligned
+ */
+ XOR R4,R5, R1
+ AND $3, R1
+ BNE R1, out
+
+/*
+ * byte at a time to word allign
+ */
+l1:
+ AND $3,R4, R1
+ BEQ R1, l2
+ MOVBU 0(R4), R8
+ MOVBU 0(R5), R9
+ ADDU $1, R4
+ BNE R8,R9, ne
+ ADDU $1, R5
+ JMP l1
+
+/*
+ * turn R3 into end pointer1-15
+ * cmp 16 at a time while theres room
+ */
+l2:
+ ADDU $-15,R6, R3
+l3:
+ SGTU R3,R4, R1
+ BEQ R1, l4
+ MOVW 0(R4), R8
+ MOVW 0(R5), R9
+ MOVW 4(R4), R10
+ BNE R8,R9, ne
+ MOVW 4(R5), R11
+ MOVW 8(R4), R8
+ BNE R10,R11, ne1
+ MOVW 8(R5), R9
+ MOVW 12(R4), R10
+ BNE R8,R9, ne
+ MOVW 12(R5), R11
+ ADDU $16, R4
+ BNE R10,R11, ne1
+ BNE R8,R9, ne
+ ADDU $16, R5
+ JMP l3
+
+/*
+ * turn R3 into end pointer1-3
+ * cmp 4 at a time while theres room
+ */
+l4:
+ ADDU $-3,R6, R3
+l5:
+ SGTU R3,R4, R1
+ BEQ R1, out
+ MOVW 0(R4), R8
+ MOVW 0(R5), R9
+ ADDU $4, R4
+ BNE R8,R9, ne /* only works because big endian */
+ ADDU $4, R5
+ JMP l5
+
+/*
+ * last loop, cmp byte at a time
+ */
+out:
+ SGTU R6,R4, R1
+ BEQ R1, ret
+ MOVBU 0(R4), R8
+ MOVBU 0(R5), R9
+ ADDU $1, R4
+ BNE R8,R9, ne
+ ADDU $1, R5
+ JMP out
+
+ne1:
+ SGTU R10,R11, R1
+ BNE R1, ret
+ MOVW $-1,R1
+ RET
+ne:
+ SGTU R8,R9, R1
+ BNE R1, ret
+ MOVW $-1,R1
+ret:
+ RET
+ END
diff --git a/sys/src/libc/mips/memmove.s b/sys/src/libc/mips/memmove.s
new file mode 100755
index 000000000..c14d2a823
--- /dev/null
+++ b/sys/src/libc/mips/memmove.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/sys/src/libc/mips/memset.s b/sys/src/libc/mips/memset.s
new file mode 100755
index 000000000..8c9467f45
--- /dev/null
+++ b/sys/src/libc/mips/memset.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/sys/src/libc/mips/mkfile b/sys/src/libc/mips/mkfile
new file mode 100755
index 000000000..3b902f6e3
--- /dev/null
+++ b/sys/src/libc/mips/mkfile
@@ -0,0 +1,40 @@
+objtype=mips
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libc.a
+SFILES=\
+ argv0.s\
+ atom.s\
+ getcallerpc.s\
+ getfcr.s\
+ main9.s\
+ main9p.s\
+ memccpy.s\
+ memchr.s\
+ memcmp.s\
+ memmove.s\
+ memset.s\
+ setjmp.s\
+ strchr.s\
+ strcmp.s\
+ strcpy.s\
+ tas.s\
+ vlop.s\
+
+CFILES=\
+ cycles.c\
+ lock.c\
+ notejmp.c\
+ sqrt.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/mips/notejmp.c b/sys/src/libc/mips/notejmp.c
new file mode 100755
index 000000000..9d3be9389
--- /dev/null
+++ b/sys/src/libc/mips/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->r1 = ret;
+ if(ret == 0)
+ r->r1 = 1;
+ r->pc = j[JMPBUFPC];
+ r->sp = j[JMPBUFSP];
+ noted(NCONT);
+}
diff --git a/sys/src/libc/mips/setjmp.s b/sys/src/libc/mips/setjmp.s
new file mode 100755
index 000000000..bb971b60f
--- /dev/null
+++ b/sys/src/libc/mips/setjmp.s
@@ -0,0 +1,14 @@
+TEXT setjmp(SB), 1, $-4
+ MOVW R29, (R1)
+ MOVW R31, 4(R1)
+ MOVW $0, R1
+ RET
+
+TEXT longjmp(SB), 1, $-4
+ MOVW r+4(FP), R3
+ BNE R3, ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVW $1, R3 /* bless their pointed heads */
+ok: MOVW (R1), R29
+ MOVW 4(R1), R31
+ MOVW R3, R1
+ RET
diff --git a/sys/src/libc/mips/sqrt.c b/sys/src/libc/mips/sqrt.c
new file mode 100755
index 000000000..fa27c35ef
--- /dev/null
+++ b/sys/src/libc/mips/sqrt.c
@@ -0,0 +1,103 @@
+#include <u.h>
+#include <libc.h>
+
+static long sqtab[64] =
+{
+ 0x6cdb2, 0x726d4, 0x77ea3, 0x7d52f, 0x82a85, 0x87eb1, 0x8d1c0, 0x923bd,
+ 0x974b2, 0x9c4a8, 0xa13a9, 0xa61be, 0xaaeee, 0xafb41, 0xb46bf, 0xb916e,
+ 0xbdb55, 0xc247a, 0xc6ce3, 0xcb495, 0xcfb95, 0xd41ea, 0xd8796, 0xdcca0,
+ 0xe110c, 0xe54dd, 0xe9818, 0xedac0, 0xf1cd9, 0xf5e67, 0xf9f6e, 0xfdfef,
+ 0x01fe0, 0x05ee6, 0x09cfd, 0x0da30, 0x11687, 0x1520c, 0x18cc8, 0x1c6c1,
+ 0x20000, 0x2388a, 0x27068, 0x2a79e, 0x2de32, 0x3142b, 0x3498c, 0x37e5b,
+ 0x3b29d, 0x3e655, 0x41989, 0x44c3b, 0x47e70, 0x4b02b, 0x4e16f, 0x51241,
+ 0x542a2, 0x57296, 0x5a220, 0x5d142, 0x60000, 0x62e5a, 0x65c55, 0x689f2,
+};
+
+double
+sqrt(double arg)
+{
+ int e, ms;
+ double a, t;
+ union
+ {
+ double d;
+ struct
+ {
+ long ms;
+ long ls;
+ };
+ } u;
+
+ u.d = arg;
+ ms = u.ms;
+
+ /*
+ * sign extend the mantissa with
+ * exponent. result should be > 0 for
+ * normal case.
+ */
+ e = ms >> 20;
+ if(e <= 0) {
+ if(e == 0)
+ return 0;
+ return NaN();
+ }
+
+ /*
+ * pick up arg/4 by adjusting exponent
+ */
+ u.ms = ms - (2 << 20);
+ a = u.d;
+
+ /*
+ * use 5 bits of mantissa and 1 bit
+ * of exponent to form table index.
+ * insert exponent/2 - 1.
+ */
+ e = (((e - 1023) >> 1) + 1022) << 20;
+ u.ms = *(long*)((char*)sqtab + ((ms >> 13) & 0xfc)) | e;
+ u.ls = 0;
+
+ /*
+ * three laps of newton
+ */
+ e = 1 << 20;
+ t = u.d;
+ u.d = t + a/t;
+ u.ms -= e; /* u.d /= 2; */
+ t = u.d;
+ u.d = t + a/t;
+ u.ms -= e; /* u.d /= 2; */
+ t = u.d;
+
+ return t + a/t;
+}
+
+/*
+ * this is the program that generated the table.
+ * it calls sqrt by some other means.
+ *
+ * void
+ * main(void)
+ * {
+ * int i;
+ * union U
+ * {
+ * double d;
+ * struct
+ * {
+ * long ms;
+ * long ls;
+ * };
+ * } u;
+ *
+ * for(i=0; i<64; i++) {
+ * u.ms = (i<<15) | 0x3fe04000;
+ * u.ls = 0;
+ * u.d = sqrt(u.d);
+ * print(" 0x%.5lux,", u.ms & 0xfffff);
+ * }
+ * print("\n");
+ * exits(0);
+ * }
+ */
diff --git a/sys/src/libc/mips/strchr.s b/sys/src/libc/mips/strchr.s
new file mode 100755
index 000000000..e009ffad2
--- /dev/null
+++ b/sys/src/libc/mips/strchr.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/sys/src/libc/mips/strcmp.s b/sys/src/libc/mips/strcmp.s
new file mode 100755
index 000000000..da986a2ed
--- /dev/null
+++ b/sys/src/libc/mips/strcmp.s
@@ -0,0 +1,21 @@
+TEXT strcmp(SB), $0
+
+ MOVW s2+4(FP), R2
+
+l1:
+ MOVB (R2), R3
+ MOVB (R1), R4
+ ADDU $1, R1
+ BEQ R3, end
+ ADDU $1, R2
+ BEQ R3, R4, l1
+
+ SGTU R4, R3, R1
+ BNE R1, ret
+ MOVW $-1, R1
+ RET
+
+end:
+ SGTU R4, R3, R1
+ret:
+ RET
diff --git a/sys/src/libc/mips/strcpy.s b/sys/src/libc/mips/strcpy.s
new file mode 100755
index 000000000..77be42669
--- /dev/null
+++ b/sys/src/libc/mips/strcpy.s
@@ -0,0 +1,96 @@
+TEXT strcpy(SB), $0
+
+ MOVW s2+4(FP),R2 /* R2 is from pointer */
+ MOVW R1, R3 /* R3 is to pointer */
+
+/*
+ * align 'from' pointer
+ */
+l1:
+ AND $3, R2, R5
+ ADDU $1, R2
+ BEQ R5, l2
+ MOVB -1(R2), R5
+ ADDU $1, R3
+ MOVB R5, -1(R3)
+ BNE R5, l1
+ RET
+
+/*
+ * test if 'to' is also alligned
+ */
+l2:
+ AND $3,R3, R5
+ BEQ R5, l4
+
+/*
+ * copy 4 at a time, 'to' not aligned
+ */
+l3:
+ MOVW -1(R2), R4
+ ADD $4, R2
+ ADD $4, R3
+ SRL $24,R4, R5
+ MOVB R5, -4(R3)
+ BEQ R5, out
+
+ SRL $16,R4, R5
+ AND $0xff, R5
+ MOVB R5, -3(R3)
+ BEQ R5, out
+
+ SRL $8,R4, R5
+ AND $0xff, R5
+ MOVB R5, -2(R3)
+ BEQ R5, out
+
+ AND $0xff,R4, R5
+ MOVB R5, -1(R3)
+ BNE R5, l3
+
+out:
+ RET
+
+/*
+ * word at a time both aligned
+ */
+l4:
+ MOVW $0xff000000, R7
+ MOVW $0x00ff0000, R8
+
+l5:
+ ADDU $4, R3
+ MOVW -1(R2), R4 /* fetch */
+
+ ADDU $4, R2
+ AND R7,R4, R5 /* is it byte 0 */
+ AND R8,R4, R6 /* is it byte 1 */
+ BEQ R5, b0
+
+ AND $0xff00,R4, R5 /* is it byte 2 */
+ BEQ R6, b1
+
+ AND $0xff,R4, R6 /* is it byte 3 */
+ BEQ R5, b2
+
+ MOVW R4, -4(R3) /* store */
+ BNE R6, l5
+ JMP out
+
+b0:
+ MOVB $0, -4(R3)
+ JMP out
+
+b1:
+ SRL $24, R4
+ MOVB R4, -4(R3)
+ MOVB $0, -3(R3)
+ JMP out
+
+b2:
+ SRL $24,R4, R5
+ MOVB R5, -4(R3)
+ SRL $16, R4
+ MOVB R4, -3(R3)
+ MOVB $0, -2(R3)
+ JMP out
diff --git a/sys/src/libc/mips/tas.s b/sys/src/libc/mips/tas.s
new file mode 100755
index 000000000..d754b21f6
--- /dev/null
+++ b/sys/src/libc/mips/tas.s
@@ -0,0 +1,33 @@
+/*
+ * magnum user level lock code
+ */
+
+#define LL(base, rt) WORD $((060<<26)|((base)<<21)|((rt)<<16))
+#define SC(base, rt) WORD $((070<<26)|((base)<<21)|((rt)<<16))
+#define NOOP WORD $0x27
+#define COP3 WORD $(023<<26)
+
+ TEXT C_3ktas(SB),$0
+ MOVW R1, R21
+btas:
+ MOVW R21, R1
+ MOVB R0, 1(R1)
+ NOOP
+ COP3
+ BLTZ R1, btas
+ RET
+
+ TEXT C_4ktas(SB), $0
+ MOVW R1, R2 /* address of key */
+tas1:
+ MOVW $1, R3
+ LL(2, 1)
+ NOOP
+ SC(2, 3)
+ NOOP
+ BEQ R3, tas1
+ RET
+
+ TEXT C_fcr0(SB), $0
+ MOVW FCR0, R1
+ RET
diff --git a/sys/src/libc/mips/vlop.s b/sys/src/libc/mips/vlop.s
new file mode 100755
index 000000000..17f487ad8
--- /dev/null
+++ b/sys/src/libc/mips/vlop.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/sys/src/libc/mips/vlrt.c b/sys/src/libc/mips/vlrt.c
new file mode 100755
index 000000000..099c2c55d
--- /dev/null
+++ b/sys/src/libc/mips/vlrt.c
@@ -0,0 +1,723 @@
+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);
+
+/* 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 *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);
+}