summaryrefslogtreecommitdiff
path: root/sys/src/libc/sparc
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/sparc
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libc/sparc')
-rwxr-xr-xsys/src/libc/sparc/argv0.s4
-rwxr-xr-xsys/src/libc/sparc/getcallerpc.s3
-rwxr-xr-xsys/src/libc/sparc/getfcr.s27
-rwxr-xr-xsys/src/libc/sparc/main9.s31
-rwxr-xr-xsys/src/libc/sparc/main9p.s44
-rwxr-xr-xsys/src/libc/sparc/memccpy.s27
-rwxr-xr-xsys/src/libc/sparc/memchr.s26
-rwxr-xr-xsys/src/libc/sparc/memcmp.s120
-rwxr-xr-xsys/src/libc/sparc/memmove.s162
-rwxr-xr-xsys/src/libc/sparc/memset.s88
-rwxr-xr-xsys/src/libc/sparc/mkfile39
-rwxr-xr-xsys/src/libc/sparc/muldivrt.s310
-rwxr-xr-xsys/src/libc/sparc/notejmp.c23
-rwxr-xr-xsys/src/libc/sparc/setjmp.s25
-rwxr-xr-xsys/src/libc/sparc/sqrt.c103
-rwxr-xr-xsys/src/libc/sparc/strchr.s73
-rwxr-xr-xsys/src/libc/sparc/strcmp.s27
-rwxr-xr-xsys/src/libc/sparc/strcpy.s84
-rwxr-xr-xsys/src/libc/sparc/tas.s7
-rwxr-xr-xsys/src/libc/sparc/vlop.s112
-rwxr-xr-xsys/src/libc/sparc/vlrt.c722
21 files changed, 2057 insertions, 0 deletions
diff --git a/sys/src/libc/sparc/argv0.s b/sys/src/libc/sparc/argv0.s
new file mode 100755
index 000000000..8d9f9b29b
--- /dev/null
+++ b/sys/src/libc/sparc/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/sparc/getcallerpc.s b/sys/src/libc/sparc/getcallerpc.s
new file mode 100755
index 000000000..05d70f118
--- /dev/null
+++ b/sys/src/libc/sparc/getcallerpc.s
@@ -0,0 +1,3 @@
+TEXT getcallerpc(SB), $0
+ MOVW 0(R1), R7
+ RETURN
diff --git a/sys/src/libc/sparc/getfcr.s b/sys/src/libc/sparc/getfcr.s
new file mode 100755
index 000000000..0059ada56
--- /dev/null
+++ b/sys/src/libc/sparc/getfcr.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/sys/src/libc/sparc/main9.s b/sys/src/libc/sparc/main9.s
new file mode 100755
index 000000000..e5f459638
--- /dev/null
+++ b/sys/src/libc/sparc/main9.s
@@ -0,0 +1,31 @@
+#define NPRIVATES 16
+
+TEXT _main(SB), 1, $(16 + NPRIVATES*4)
+
+ MOVW $setSB(SB), R2
+ MOVW R7, _tos(SB)
+
+ MOVW $p-64(SP),R7
+ MOVW R7,_privates+0(SB)
+ MOVW $16,R7
+ MOVW R7,_nprivates+0(SB)
+/*
+ MOVW _fpsr+0(SB), FSR
+ FMOVD $0.5, F26
+ FSUBD F26, F26, F24
+ FADDD F26, F26, F28
+ FADDD F28, F28, F30
+*/
+ MOVW inargc-4(FP), R7
+ MOVW $inargv+0(FP), R8
+ MOVW R8, 8(R1)
+ JMPL main(SB)
+
+loop:
+ MOVW $_exits<>(SB), R7
+ JMPL exits(SB)
+ MOVW $_mul(SB), R8 /* force loading of muldiv */
+ JMP loop
+
+DATA _exits<>+0(SB)/5, $"main"
+GLOBL _exits<>+0(SB), $5
diff --git a/sys/src/libc/sparc/main9p.s b/sys/src/libc/sparc/main9p.s
new file mode 100755
index 000000000..db464f485
--- /dev/null
+++ b/sys/src/libc/sparc/main9p.s
@@ -0,0 +1,44 @@
+#define NPRIVATES 16
+
+TEXT _mainp(SB), 1, $(16 + NPRIVATES*4)
+
+ MOVW $setSB(SB), R2
+ MOVW R7, _tos(SB)
+
+ MOVW $p-64(SP),R7
+ MOVW R7,_privates+0(SB)
+ MOVW $16,R7
+ MOVW R7,_nprivates+0(SB)
+/*
+ MOVW _fpsr+0(SB), FSR
+ FMOVD $0.5, F26
+ FSUBD F26, F26, F24
+ FADDD F26, F26, F28
+ FADDD F28, F28, F30
+*/
+
+ JMPL _profmain(SB)
+ MOVW __prof+4(SB), R7
+ MOVW R7, __prof+0(SB)
+
+ MOVW inargc-4(FP), R7
+ MOVW $inargv+0(FP), R8
+ MOVW R8, 8(R1)
+ JMPL main(SB)
+
+loop:
+ MOVW $_exits<>(SB), R7
+ JMPL exits(SB)
+ MOVW $_mul(SB), R8 /* force loading of muldiv */
+ MOVW $_profin(SB), R9 /* force loading of profile */
+ JMP loop
+
+TEXT _savearg(SB), 1, $0
+ RETURN
+
+TEXT _callpc(SB), 1, $0
+ MOVW argp-4(FP), R7
+ RETURN
+
+DATA _exits<>+0(SB)/4, $"main"
+GLOBL _exits<>+0(SB), $5
diff --git a/sys/src/libc/sparc/memccpy.s b/sys/src/libc/sparc/memccpy.s
new file mode 100755
index 000000000..a2ebd7d11
--- /dev/null
+++ b/sys/src/libc/sparc/memccpy.s
@@ -0,0 +1,27 @@
+ TEXT memccpy(SB), $0
+
+MOVW R7, 0(FP)
+ MOVW n+12(FP), R7
+ SUBCC R0,R7, R0
+ BE ret
+ MOVW s1+0(FP), R9
+ MOVW s2+4(FP), R8
+ MOVBU c+11(FP), R10
+ ADD R7,R8, R11
+
+l1: MOVBU (R8), R12
+ ADD $1, R8
+ MOVBU R12, (R9)
+ ADD $1, R9
+ SUBCC R10,R12, R0
+ BE eq
+ SUBCC R8,R11, R0
+ BNE l1
+ MOVW R0, R7
+ RETURN
+
+eq:
+ MOVW R9, R7
+
+ret:
+ RETURN
diff --git a/sys/src/libc/sparc/memchr.s b/sys/src/libc/sparc/memchr.s
new file mode 100755
index 000000000..81e67f6f2
--- /dev/null
+++ b/sys/src/libc/sparc/memchr.s
@@ -0,0 +1,26 @@
+ TEXT memchr(SB), $0
+
+MOVW R7, 0(FP)
+ MOVW n+8(FP), R7
+ SUBCC R0,R7, R0
+ BE ret
+ MOVW s1+0(FP), R8
+ MOVBU c+7(FP), R9
+ ADD R7,R8, R11
+
+l1:
+ MOVBU (R8), R10
+ SUBCC R9,R10, R0
+ ADD $1, R8
+ BE eq
+ SUBCC R8,R11, R0
+ BNE l1
+
+ MOVW R0, R7
+ RETURN
+
+eq:
+ SUB $1,R8, R7
+
+ret:
+ RETURN
diff --git a/sys/src/libc/sparc/memcmp.s b/sys/src/libc/sparc/memcmp.s
new file mode 100755
index 000000000..f5d680a40
--- /dev/null
+++ b/sys/src/libc/sparc/memcmp.s
@@ -0,0 +1,120 @@
+ TEXT memcmp(SB), $0
+
+/*
+ * performance:
+ * (tba)
+ */
+
+ MOVW R7, 0(FP)
+ MOVW n+8(FP), R9 /* R9 is count */
+ MOVW s1+0(FP), R10 /* R10 is pointer1 */
+ MOVW s2+4(FP), R11 /* R11 is pointer2 */
+ ADD R9,R10, R12 /* R12 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.
+ */
+ SUBCC $4,R9, R0
+ BL out
+
+/*
+ * test if both pointers
+ * are similarly word alligned
+ */
+ XOR R10,R11, R7
+ ANDCC $3,R7, R0
+ BNE out
+
+/*
+ * byte at a time to word allign
+ */
+l1:
+ ANDCC $3,R10, R0
+ BE l2
+ MOVBU 0(R10), R16
+ MOVBU 0(R11), R17
+ ADD $1, R10
+ SUBCC R16,R17, R0
+ BNE ne
+ ADD $1, R11
+ JMP l1
+
+/*
+ * turn R9 into end pointer1-15
+ * cmp 16 at a time while theres room
+ */
+l2:
+ SUB $15,R12, R9
+l3:
+ SUBCC R10,R9, R0
+ BLEU l4
+ MOVW 0(R10), R16
+ MOVW 0(R11), R17
+ MOVW 4(R10), R18
+ SUBCC R16,R17, R0
+ BNE ne
+ MOVW 4(R11), R19
+ MOVW 8(R10), R16
+ SUBCC R18,R19, R0
+ BNE ne
+ MOVW 8(R11), R17
+ MOVW 12(R10), R18
+ SUBCC R16,R17, R0
+ BNE ne
+ MOVW 12(R11), R19
+ ADD $16, R10
+ SUBCC R18,R19, R0
+ BNE ne
+ SUBCC R16,R17, R0
+ BNE ne
+ ADD $16, R11
+ JMP l3
+
+/*
+ * turn R9 into end pointer1-3
+ * cmp 4 at a time while theres room
+ */
+l4:
+ SUB $3,R12, R9
+l5:
+ SUBCC R10,R9, R0
+ BLEU out
+ MOVW 0(R10), R16
+ MOVW 0(R11), R17
+ ADD $4, R10
+ SUBCC R16,R17, R0 /* only works because big endian */
+ BNE ne
+ ADD $4, R11
+ JMP l5
+
+/*
+ * last loop, cmp byte at a time
+ */
+out:
+ SUBCC R10,R12, R0
+ BE zero
+ MOVBU 0(R10), R16
+ MOVBU 0(R11), R17
+ ADD $1, R10
+ SUBCC R16,R17, R0
+ BNE ne
+ ADD $1, R11
+ JMP out
+
+ne:
+ BGU plus
+ MOVW $1, R7
+ RETURN
+plus:
+ MOVW $-1, R7
+ RETURN
+
+zero:
+ MOVW R0, R7
+ RETURN
diff --git a/sys/src/libc/sparc/memmove.s b/sys/src/libc/sparc/memmove.s
new file mode 100755
index 000000000..1295209ac
--- /dev/null
+++ b/sys/src/libc/sparc/memmove.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/sys/src/libc/sparc/memset.s b/sys/src/libc/sparc/memset.s
new file mode 100755
index 000000000..8c7b26c86
--- /dev/null
+++ b/sys/src/libc/sparc/memset.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/sys/src/libc/sparc/mkfile b/sys/src/libc/sparc/mkfile
new file mode 100755
index 000000000..af2b18944
--- /dev/null
+++ b/sys/src/libc/sparc/mkfile
@@ -0,0 +1,39 @@
+objtype=sparc
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libc.a
+SFILES=\
+ argv0.s\
+ getcallerpc.$O\
+ getfcr.s\
+ main9.s\
+ main9p.s\
+ memccpy.s\
+ memchr.s\
+ memcmp.s\
+ memmove.s\
+ memset.s\
+ muldivrt.s\
+ setjmp.s\
+ strchr.s\
+ strcmp.s\
+ strcpy.s\
+ tas.s\
+ vlop.s
+
+CFILES=\
+ cycles.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/sparc/muldivrt.s b/sys/src/libc/sparc/muldivrt.s
new file mode 100755
index 000000000..ac811629f
--- /dev/null
+++ b/sys/src/libc/sparc/muldivrt.s
@@ -0,0 +1,310 @@
+/*
+ * ulong
+ * _udiv(ulong num, ulong den)
+ * {
+ * int i;
+ * ulong quo;
+ *
+ * if(den == 0)
+ * *(ulong*)-1 = 0;
+ * quo = num;
+ * if(quo > 1<<(32-1))
+ * quo = 1<<(32-1);
+ * for(i=0; den<quo; i++)
+ * den <<= 1;
+ * quo = 0;
+ * for(; i>=0; i--) {
+ * quo <<= 1;
+ * if(num >= den) {
+ * num -= den;
+ * quo |= 1;
+ * }
+ * den >>= 1;
+ * }
+ * return quo::num;
+ * }
+ */
+
+#define NOPROF 1
+
+/*
+ * calling sequence:
+ * num: 4(R1)
+ * den: 8(R1)
+ * returns
+ * quo: 4(R1)
+ * rem: 8(R1)
+ */
+TEXT _udivmod(SB), NOPROF, $-4
+
+ MOVW $(1<<31), R11
+ MOVW 4(R1), R13 /* numerator */
+ MOVW 8(R1), R10 /* denominator */
+ CMP R10, R0
+ BNE udm20
+ MOVW R0, -1(R0) /* fault -- divide by zero */
+udm20:
+ MOVW R13, R12
+ CMP R13, R11
+ BLEU udm34
+ MOVW R11, R12
+udm34:
+ MOVW R0, R11
+udm38:
+ CMP R10, R12
+ BCC udm54
+ SLL $1, R10
+ ADD $1, R11
+ BA udm38
+udm54:
+ MOVW R0, R12
+udm58:
+ CMP R11, R0
+ BL udm8c
+ SLL $1, R12
+ CMP R13, R10
+ BCS udm7c
+ SUB R10, R13
+ OR $1, R12
+udm7c:
+ SRL $1, R10
+ SUB $1, R11
+ BA udm58
+udm8c:
+ MOVW R12, 4(R1) /* quotent */
+ MOVW R13, 8(R1) /* remainder */
+ JMPL 8(R15)
+
+/*
+ * save working registers
+ * and bring in num/den parameters
+ */
+TEXT _unsarg(SB), NOPROF, $-4
+ MOVW R10, 12(R1)
+ MOVW R11, 16(R1)
+ MOVW R12, 20(R1)
+ MOVW R13, 24(R1)
+
+ MOVW R14, 4(R1)
+ MOVW 32(R1), R14
+ MOVW R14, 8(R1)
+
+ JMPL 8(R15)
+
+/*
+ * save working registers
+ * and bring in absolute value
+ * of num/den parameters
+ */
+TEXT _absarg(SB), NOPROF, $-4
+ MOVW R10, 12(R1)
+ MOVW R11, 16(R1)
+ MOVW R12, 20(R1)
+ MOVW R13, 24(R1)
+
+ MOVW R14, 28(R1)
+ CMP R14, R0
+ BGE ab1
+ SUB R14, R0, R14
+ab1:
+ MOVW R14, 4(R1) /* numerator */
+
+ MOVW 32(R1), R14
+ CMP R14, R0
+ BGE ab2
+ SUB R14, R0, R14
+ab2:
+ MOVW R14, 8(R1) /* denominator */
+ JMPL 8(R15)
+
+/*
+ * restore registers and
+ * return to original caller
+ * answer is in R14
+ */
+TEXT _retarg(SB), NOPROF, $-4
+ MOVW 12(R1), R10
+ MOVW 16(R1), R11
+ MOVW 20(R1), R12
+ MOVW 24(R1), R13
+ MOVW 0(R1), R15
+
+ ADD $28, R1
+ JMP 8(R15) /* back to main sequence */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * quo: R14
+ */
+TEXT _div(SB), NOPROF, $-4
+ SUB $28, R1 /* 4 reg save, 2 parameters, link */
+ MOVW R15, 0(R1)
+
+ JMPL _absarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 4(R1), R14
+
+ MOVW 28(R1), R10 /* clean up the sign */
+ MOVW 32(R1), R11
+ XORCC R11, R10, R0
+ BGE div1
+ SUB R14, R0, R14
+div1:
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * quo: R14
+ */
+TEXT _divl(SB), NOPROF, $-4
+ SUB $((4+2+1)*4), R1 /* 4 reg save, 2 parameters, link */
+ MOVW R15, 0(R1)
+
+ JMPL _unsarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 4(R1), R14
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * rem: R14
+ */
+TEXT _mod(SB), NOPROF, $-4
+ SUB $28, R1 /* 4 reg save, 2 parameters, link */
+
+ MOVW R15, 0(R1)
+ JMPL _absarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 8(R1), R14
+
+ MOVW 28(R1), R10 /* clean up the sign */
+ CMP R10, R0
+ BGE mod1
+ SUB R14, R0, R14
+mod1:
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * calling sequence
+ * num: R14
+ * den: 8(R1)
+ * returns
+ * rem: R14
+ */
+TEXT _modl(SB), NOPROF, $-4
+ SUB $28, R1 /* 4 reg save, 2 parameters, link */
+
+
+ MOVW R15, 0(R1)
+ JMPL _unsarg(SB)
+ JMPL _udivmod(SB)
+ MOVW 8(R1), R14
+
+ JMPL _retarg(SB)
+ JMP 8(R15) /* not executed */
+
+/*
+ * special calling sequence:
+ * arg1 in R14
+ * arg2 in 4(R1), will save R9
+ * nothing in 0(R1), will save R8
+ * result in R14
+ */
+TEXT _mul+0(SB), NOPROF, $-4
+
+ /*
+ * exchange stack and registers
+ */
+ MOVW R8, 0(R1)
+ MOVW 4(R1), R8
+ MOVW R9, 4(R1)
+
+ CMP R14, R8
+ BLE mul1
+ MOVW R14, R9
+ MOVW R8, R14
+ MOVW R9, R8
+mul1:
+ MOVW R14, Y
+ ANDNCC $0xFFF, R14, 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 */
+
+ MOVW Y, R14 /* get low part */
+ BA mul_return
+
+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 */
+
+ MOVW Y, R8
+ SLL $12, R9
+ SRL $20, R8
+ OR R8, R9, R14
+
+mul_return:
+ MOVW 0(R1), R8
+ MOVW 4(R1), R9
+ JMP 8(R15)
diff --git a/sys/src/libc/sparc/notejmp.c b/sys/src/libc/sparc/notejmp.c
new file mode 100755
index 000000000..56caf98e6
--- /dev/null
+++ b/sys/src/libc/sparc/notejmp.c
@@ -0,0 +1,23 @@
+#include <u.h>
+#include <libc.h>
+#include <ureg.h>
+
+int __noterestore(void);
+
+void
+notejmp(void *vr, jmp_buf j, int ret)
+{
+ struct Ureg *r = vr;
+
+ /*
+ * song and dance to get around the kernel smashing r7 in noted
+ */
+ r->r8 = ret;
+ if(ret == 0)
+ r->r8 = 1;
+ r->r9 = j[JMPBUFPC] - JMPBUFDPC;
+ r->pc = (ulong)__noterestore;
+ r->npc = (ulong)__noterestore + 4;
+ r->sp = j[JMPBUFSP];
+ noted(NCONT);
+}
diff --git a/sys/src/libc/sparc/setjmp.s b/sys/src/libc/sparc/setjmp.s
new file mode 100755
index 000000000..da8e7e63b
--- /dev/null
+++ b/sys/src/libc/sparc/setjmp.s
@@ -0,0 +1,25 @@
+TEXT setjmp(SB), 1, $0
+
+ MOVW R1, (R7)
+ MOVW R15, 4(R7)
+ MOVW $0, R7
+ RETURN
+
+TEXT longjmp(SB), 1, $0
+
+ MOVW R7, R8
+ MOVW r+4(FP), R7
+ CMP R7, R0
+ BNE ok /* ansi: "longjmp(0) => longjmp(1)" */
+ MOVW $1, R7 /* bless their pointed heads */
+ok: MOVW (R8), R1
+ MOVW 4(R8), R15
+ RETURN
+
+/*
+ * trampoline functions because the kernel smashes r7
+ * in the uregs given to notejmp
+ */
+TEXT __noterestore(SB), 1, $-4
+ MOVW R8, R7
+ JMP (R9)
diff --git a/sys/src/libc/sparc/sqrt.c b/sys/src/libc/sparc/sqrt.c
new file mode 100755
index 000000000..fa27c35ef
--- /dev/null
+++ b/sys/src/libc/sparc/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/sparc/strchr.s b/sys/src/libc/sparc/strchr.s
new file mode 100755
index 000000000..192beab13
--- /dev/null
+++ b/sys/src/libc/sparc/strchr.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/sys/src/libc/sparc/strcmp.s b/sys/src/libc/sparc/strcmp.s
new file mode 100755
index 000000000..e9539ebf8
--- /dev/null
+++ b/sys/src/libc/sparc/strcmp.s
@@ -0,0 +1,27 @@
+TEXT strcmp(SB), $0
+
+ MOVW s2+4(FP), R10
+
+l1:
+ MOVB 0(R7), R8
+ MOVB 0(R10), R9
+ ADD $1, R7
+ ADD $1, R10
+
+ CMP R8, R9
+ BNE l2
+
+ CMP R8, $0
+ BNE l1
+
+ MOVW R0, R7
+ RETURN
+
+l2:
+ BLEU l3
+ MOVW $1, R7
+ RETURN
+
+l3:
+ MOVW $-1, R7
+ RETURN
diff --git a/sys/src/libc/sparc/strcpy.s b/sys/src/libc/sparc/strcpy.s
new file mode 100755
index 000000000..6fd6aef05
--- /dev/null
+++ b/sys/src/libc/sparc/strcpy.s
@@ -0,0 +1,84 @@
+ TEXT strcpy(SB), $0
+
+MOVW R7, 0(FP)
+ MOVW s1+0(FP), R9 /* R9 is to pointer */
+ MOVW s2+4(FP), R10 /* R10 is from pointer */
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+ XOR R9,R10, R7
+ ANDCC $3,R7, R0
+ BNE una
+
+/*
+ * make byte masks
+ */
+ MOVW $0xff, R17
+ SLL $8,R17, R16
+ SLL $16,R17, R13
+ SLL $24,R17, R12
+
+/*
+ * byte at a time to word align
+ */
+al1:
+ ANDCC $3,R10, R0
+ BE al2
+ MOVB (R10), R11
+ ADD $1, R10
+ MOVB R11, (R9)
+ ADD $1, R9
+ SUBCC R0,R11, R0
+ BNE al1
+ JMP out
+
+/*
+ * word at a time
+ */
+al2:
+ ADD $4, R9
+ MOVW (R10), R11 /* fetch */
+ ADD $4, R10
+ ANDCC R12,R11, R0 /* is it byte 0 */
+ BE b0
+ ANDCC R13,R11, R0 /* is it byte 1 */
+ BE b1
+ ANDCC R16,R11, R0 /* is it byte 2 */
+ BE b2
+ MOVW R11, -4(R9) /* store */
+ ANDCC R17,R11, R0 /* is it byte 3 */
+ BNE al2
+
+ JMP out
+
+b0:
+ MOVB R0, -4(R9)
+ JMP out
+
+b1:
+ SRL $24, R11
+ MOVB R11, -4(R9)
+ MOVB R0, -3(R9)
+ JMP out
+
+b2:
+ SRL $24,R11, R7
+ MOVB R7, -4(R9)
+ SRL $16, R11
+ MOVB R11, -3(R9)
+ MOVB R0, -2(R9)
+ JMP out
+
+una:
+ MOVB (R10), R11
+ ADD $1, R10
+ MOVB R11, (R9)
+ ADD $1, R9
+ SUBCC R0,R11, R0
+ BNE una
+
+out:
+ MOVW s1+0(FP),R7
+ RETURN
diff --git a/sys/src/libc/sparc/tas.s b/sys/src/libc/sparc/tas.s
new file mode 100755
index 000000000..15fd0b648
--- /dev/null
+++ b/sys/src/libc/sparc/tas.s
@@ -0,0 +1,7 @@
+/*
+ * tas uses LDSTUB
+ */
+ TEXT _tas(SB),$-4
+
+ TAS (R7),R7
+ RETURN
diff --git a/sys/src/libc/sparc/vlop.s b/sys/src/libc/sparc/vlop.s
new file mode 100755
index 000000000..ac36b4143
--- /dev/null
+++ b/sys/src/libc/sparc/vlop.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/sys/src/libc/sparc/vlrt.c b/sys/src/libc/sparc/vlrt.c
new file mode 100755
index 000000000..b71c92f73
--- /dev/null
+++ b/sys/src/libc/sparc/vlrt.c
@@ -0,0 +1,722 @@
+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 *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);
+}