diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libc |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libc')
397 files changed, 28984 insertions, 0 deletions
diff --git a/sys/src/libc/386/387/asin.s b/sys/src/libc/386/387/asin.s new file mode 100755 index 000000000..6c91d1fe3 --- /dev/null +++ b/sys/src/libc/386/387/asin.s @@ -0,0 +1,40 @@ +TEXT asin(SB), $0 + FMOVD a+0(FP), F0 /* a */ + FMOVD F0, F0 /* a,a */ + FMULD F0, F0 /* a*a,a */ + FLD1 /* 1,a*a,a */ + FSUBRDP F0, F1 /* 1-a*a,a */ + + FTST + WAIT + FSTSW AX + SAHF + JLO bad + + FSQRT /* sqrt(1-a*a),a */ + FPATAN /* atan2(sqrt(1-a*a),a) */ + RET + +TEXT acos(SB), $0 + FMOVD a+0(FP), F0 + FMOVD F0, F0 + FMULD F0, F0 + FLD1 + FSUBRDP F0, F1 + + FTST + WAIT + FSTSW AX + SAHF + JLO bad + + FSQRT + FXCHD F0, F1 /* identical except this */ + FPATAN + RET + +bad: + FMOVDP F0, F0 + FMOVDP F0, F0 + CALL NaN(SB) + RET diff --git a/sys/src/libc/386/387/atan.s b/sys/src/libc/386/387/atan.s new file mode 100755 index 000000000..65496f2b6 --- /dev/null +++ b/sys/src/libc/386/387/atan.s @@ -0,0 +1,5 @@ +TEXT atan(SB), $0 + FMOVD a+0(FP), F0 + FLD1 + FPATAN + RET diff --git a/sys/src/libc/386/387/atan2.s b/sys/src/libc/386/387/atan2.s new file mode 100755 index 000000000..00ca36e01 --- /dev/null +++ b/sys/src/libc/386/387/atan2.s @@ -0,0 +1,5 @@ +TEXT atan2(SB), $0 + FMOVD a+0(FP), F0 + FMOVD b+8(FP), F0 + FPATAN + RET diff --git a/sys/src/libc/386/387/exp.s b/sys/src/libc/386/387/exp.s new file mode 100755 index 000000000..0c73465ab --- /dev/null +++ b/sys/src/libc/386/387/exp.s @@ -0,0 +1,13 @@ +TEXT exp(SB), $0 + FLDL2E + FMULD a+0(FP), F0 /* now we want 2^ this number */ + + FMOVD F0, F0 /* x, x */ + FRNDINT /* ix, x -- this is best in round mode */ + FSUBD F0, F1 /* ix, fx */ + FXCHD F0, F1 /* fx, ix */ + F2XM1 /* 2^fx-1, ix */ + FADDD $1.0, F0 /* 2^fx, ix */ + FSCALE /* 2^(fx+ix), ix */ + FMOVDP F0, F1 /* 2^(fx+ix) == 2^x */ + RET diff --git a/sys/src/libc/386/387/log.s b/sys/src/libc/386/387/log.s new file mode 100755 index 000000000..f53c05eb1 --- /dev/null +++ b/sys/src/libc/386/387/log.s @@ -0,0 +1,31 @@ +TEXT log(SB), $0 + FMOVD $0.69314718055994530941, F0 + FMOVD a+0(FP), F0 + + FTST + WAIT + FSTSW AX + SAHF + JLO bad + + FYL2X + RET + +TEXT log10(SB), $0 + FMOVD $0.30102999566398119521, F0 + FMOVD a+0(FP), F0 + + FTST + WAIT + FSTSW AX + SAHF + JLO bad + + FYL2X + RET + +bad: + FMOVDP F0, F0 + FMOVDP F0, F0 + CALL NaN(SB) + RET diff --git a/sys/src/libc/386/387/mkfile b/sys/src/libc/386/387/mkfile new file mode 100755 index 000000000..05343b63e --- /dev/null +++ b/sys/src/libc/386/387/mkfile @@ -0,0 +1,14 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/lib387.a + +OFILES=\ + atan.$O\ + tan.$O\ + atan2.$O\ + exp.$O\ + asin.$O\ + log.$O\ + sin.$O\ + +</sys/src/cmd/mksyslib diff --git a/sys/src/libc/386/387/sin.s b/sys/src/libc/386/387/sin.s new file mode 100755 index 000000000..998a63ff4 --- /dev/null +++ b/sys/src/libc/386/387/sin.s @@ -0,0 +1,9 @@ +TEXT sin(SB), $0 + FMOVD a+0(FP), F0 + FSIN + RET + +TEXT cos(SB), $0 + FMOVD a+0(FP), F0 + FCOS + RET diff --git a/sys/src/libc/386/387/sqrt.s b/sys/src/libc/386/387/sqrt.s new file mode 100755 index 000000000..219a8ac6b --- /dev/null +++ b/sys/src/libc/386/387/sqrt.s @@ -0,0 +1,16 @@ +TEXT sqrt(SB), $0 + FMOVD a+0(FP), F0 + + FTST + WAIT + FSTSW AX + SAHF + JLO bad + + FSQRT + RET + +bad: + FMOVDP F0, F0 + CALL NaN(SB) + RET diff --git a/sys/src/libc/386/387/tan.s b/sys/src/libc/386/387/tan.s new file mode 100755 index 000000000..01d9cdab1 --- /dev/null +++ b/sys/src/libc/386/387/tan.s @@ -0,0 +1,5 @@ +TEXT tan(SB), $0 + FMOVD a+0(FP), F0 + FPTAN + FMOVDP F0, F0 /* get rid of extra 1.0 */ + RET diff --git a/sys/src/libc/386/argv0.s b/sys/src/libc/386/argv0.s new file mode 100755 index 000000000..8d9f9b29b --- /dev/null +++ b/sys/src/libc/386/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/386/atom.s b/sys/src/libc/386/atom.s new file mode 100755 index 000000000..8fd8c75d0 --- /dev/null +++ b/sys/src/libc/386/atom.s @@ -0,0 +1,75 @@ +TEXT ainc(SB), $0 /* long ainc(long *); */ + MOVL addr+0(FP), BX +ainclp: + MOVL (BX), AX + MOVL AX, CX + INCL CX + LOCK + BYTE $0x0F; BYTE $0xB1; BYTE $0x0B /* CMPXCHGL CX, (BX) */ + JNZ ainclp + MOVL CX, AX + RET + +TEXT adec(SB), $0 /* long adec(long*); */ + MOVL addr+0(FP), BX +adeclp: + MOVL (BX), AX + MOVL AX, CX + DECL CX + LOCK + BYTE $0x0F; BYTE $0xB1; BYTE $0x0B /* CMPXCHGL CX, (BX) */ + JNZ adeclp + MOVL CX, AX + RET + +/* + * int cas32(u32int *p, u32int ov, u32int nv); + * int cas(uint *p, int ov, int nv); + * int casp(void **p, void *ov, void *nv); + * int casl(ulong *p, ulong ov, ulong nv); + */ + +/* + * CMPXCHG (CX), DX: 0000 1111 1011 000w oorr rmmm, + * mmm = CX = 001; rrr = DX = 010 + */ + +#define CMPXCHG BYTE $0x0F; BYTE $0xB1; BYTE $0x11 + +TEXT cas32+0(SB),0,$0 +TEXT cas+0(SB),0,$0 +TEXT casp+0(SB),0,$0 +TEXT casl+0(SB),0,$0 + MOVL p+0(FP), CX + MOVL ov+4(FP), AX + MOVL nv+8(FP), DX + LOCK + CMPXCHG + JNE fail + MOVL $1,AX + RET +fail: + MOVL $0,AX + RET + +/* + * int cas64(u64int *p, u64int ov, u64int nv); + */ + +/* + * CMPXCHG64 (DI): 0000 1111 1100 0111 0000 1110, + */ + +#define CMPXCHG64 BYTE $0x0F; BYTE $0xC7; BYTE $0x0F + +TEXT cas64+0(SB),0,$0 + MOVL p+0(FP), DI + MOVL ov+0x4(FP), AX + MOVL ov+0x8(FP), DX + MOVL nv+0xc(FP), BX + MOVL nv+0x10(FP), CX + LOCK + CMPXCHG64 + JNE fail + MOVL $1,AX + RET diff --git a/sys/src/libc/386/cycles.s b/sys/src/libc/386/cycles.s new file mode 100755 index 000000000..7f8810261 --- /dev/null +++ b/sys/src/libc/386/cycles.s @@ -0,0 +1,8 @@ +#define RDTSC BYTE $0x0F; BYTE $0x31 + +TEXT cycles(SB),1,$0 /* time stamp counter; cycles since power up */ + RDTSC + MOVL vlong+0(FP), CX /* &vlong */ + MOVL AX, 0(CX) /* lo */ + MOVL DX, 4(CX) /* hi */ + RET diff --git a/sys/src/libc/386/getcallerpc.s b/sys/src/libc/386/getcallerpc.s new file mode 100755 index 000000000..bc4a5f1ea --- /dev/null +++ b/sys/src/libc/386/getcallerpc.s @@ -0,0 +1,4 @@ +TEXT getcallerpc(SB), $0 + MOVL v+0(FP), AX + MOVL -4(AX), AX + RET diff --git a/sys/src/libc/386/getfcr.s b/sys/src/libc/386/getfcr.s new file mode 100755 index 000000000..f646c369c --- /dev/null +++ b/sys/src/libc/386/getfcr.s @@ -0,0 +1,27 @@ + +TEXT setfcr(SB), $4 + MOVL p+0(FP),AX + XORB $0x3f,AX + MOVW AX, 0(SP) + WAIT + FLDCW 0(SP) + MOVW 0(SP), AX + RET + +TEXT getfcr(SB), $4 + MOVW AX, 0(SP) + WAIT + FSTCW 0(SP) + MOVW 0(SP), AX + XORB $0x3f,AX + RET + +TEXT getfsr(SB), $0 + WAIT + FSTSW AX + RET + +TEXT setfsr(SB), $0 + WAIT + FCLEX + RET diff --git a/sys/src/libc/386/main9.s b/sys/src/libc/386/main9.s new file mode 100755 index 000000000..ced3efde6 --- /dev/null +++ b/sys/src/libc/386/main9.s @@ -0,0 +1,21 @@ +#define NPRIVATES 16 + +TEXT _main(SB), 1, $(8+NPRIVATES*4) + MOVL AX, _tos(SB) + LEAL 8(SP), AX + MOVL AX, _privates(SB) + MOVL $NPRIVATES, _nprivates(SB) + MOVL inargc-4(FP), AX + MOVL AX, 0(SP) + LEAL inargv+0(FP), AX + MOVL AX, 4(SP) + CALL main(SB) + +loop: + MOVL $_exits<>(SB), AX + MOVL AX, 0(SP) + CALL exits(SB) + JMP loop + +DATA _exits<>+0(SB)/4, $"main" +GLOBL _exits<>+0(SB), $5 diff --git a/sys/src/libc/386/main9p.s b/sys/src/libc/386/main9p.s new file mode 100755 index 000000000..a924d0aff --- /dev/null +++ b/sys/src/libc/386/main9p.s @@ -0,0 +1,38 @@ +#define NPRIVATES 16 + +TEXT _mainp(SB), 1, $(8+NPRIVATES*4) + /* _tos = arg */ + MOVL AX, _tos(SB) + LEAL 8(SP), AX + MOVL AX, _privates(SB) + MOVL $NPRIVATES, _nprivates(SB) + /* _profmain(); */ + CALL _profmain(SB) + /* _tos->prof.pp = _tos->prof.next; */ + MOVL _tos+0(SB),DX + MOVL 4(DX),CX + MOVL CX,(DX) + /* main(argc, argv); */ + MOVL inargc-4(FP), AX + MOVL AX, 0(SP) + LEAL inargv+0(FP), AX + MOVL AX, 4(SP) + CALL main(SB) + +loop: + MOVL $_exits<>(SB), AX + MOVL AX, 0(SP) + CALL exits(SB) + MOVL $_profin(SB), AX /* force loading of profile */ + JMP loop + +TEXT _savearg(SB), 1, $0 + RET + +TEXT _callpc(SB), 1, $0 + MOVL argp+0(FP), AX + MOVL 4(AX), AX + RET + +DATA _exits<>+0(SB)/4, $"main" +GLOBL _exits<>+0(SB), $5 diff --git a/sys/src/libc/386/memccpy.s b/sys/src/libc/386/memccpy.s new file mode 100755 index 000000000..52af6a9cf --- /dev/null +++ b/sys/src/libc/386/memccpy.s @@ -0,0 +1,53 @@ + TEXT memccpy(SB),$0 + + MOVL n+12(FP), CX + CMPL CX, $0 + JEQ none + MOVL p2+4(FP), DI + MOVBLZX c+8(FP), AX + CLD +/* + * find the character in the second string + */ + + REPN; SCASB + JEQ found + +/* + * if not found, set count to 'n' + */ +none: + MOVL $0, AX + MOVL n+12(FP), BX + JMP memcpy + +/* + * if found, set count to bytes thru character + */ +found: + MOVL DI, AX + SUBL p2+4(FP), AX + MOVL AX, BX + ADDL p1+0(FP), AX + +/* + * copy the memory + */ + +memcpy: + MOVL p1+0(FP), DI + MOVL p2+4(FP), SI +/* + * copy whole longs + */ + MOVL BX, CX + SHRL $2, CX + REP; MOVSL +/* + * copy the rest, by bytes + */ + ANDL $3, BX + MOVL BX, CX + REP; MOVSB + + RET diff --git a/sys/src/libc/386/memchr.s b/sys/src/libc/386/memchr.s new file mode 100755 index 000000000..23a1982a3 --- /dev/null +++ b/sys/src/libc/386/memchr.s @@ -0,0 +1,23 @@ + TEXT memchr(SB),$0 + + MOVL n+8(FP), CX + CMPL CX, $0 + JEQ none + MOVL p+0(FP), DI + MOVBLZX c+4(FP), AX + CLD +/* + * SCASB is memchr instruction + */ + + REPN; SCASB + JEQ found + +none: + MOVL $0, AX + RET + +found: + MOVL DI, AX + SUBL $1, AX + RET diff --git a/sys/src/libc/386/memcmp.s b/sys/src/libc/386/memcmp.s new file mode 100755 index 000000000..4e9d090cf --- /dev/null +++ b/sys/src/libc/386/memcmp.s @@ -0,0 +1,47 @@ + TEXT memcmp(SB),$0 + + MOVL n+8(FP), BX + CMPL BX, $0 + JEQ none + MOVL p1+0(FP), DI + MOVL p2+4(FP), SI + CLD +/* + * first by longs + */ + + MOVL BX, CX + SHRL $2, CX + + REP; CMPSL + JNE found + +/* + * then by bytes + */ + ANDL $3, BX + MOVL BX, CX + REP; CMPSB + JNE found1 + +none: + MOVL $0, AX + RET + +/* + * if long found, + * back up and look by bytes + */ +found: + MOVL $4, CX + SUBL CX, DI + SUBL CX, SI + REP; CMPSB + +found1: + JLS lt + MOVL $-1, AX + RET +lt: + MOVL $1, AX + RET diff --git a/sys/src/libc/386/memcpy.s b/sys/src/libc/386/memcpy.s new file mode 100755 index 000000000..bb9cfe40c --- /dev/null +++ b/sys/src/libc/386/memcpy.s @@ -0,0 +1,57 @@ + TEXT memcpy(SB), $0 + + MOVL p1+0(FP), DI + MOVL p2+4(FP), SI + MOVL n+8(FP), BX + CMPL BX, $0 + JGE ok + MOVL $0, SI +ok: + CLD +/* + * check and set for backwards + */ + CMPL SI, DI + JLS back +/* + * copy whole longs + */ + MOVL BX, CX + SHRL $2, CX + REP; MOVSL +/* + * copy the rest, by bytes + */ + ANDL $3, BX + MOVL BX, CX + REP; MOVSB + + MOVL p+0(FP),AX + RET +/* + * whole thing backwards has + * adjusted addresses + */ +back: + ADDL BX, DI + ADDL BX, SI + SUBL $4, DI + SUBL $4, SI + STD +/* + * copy whole longs + */ + MOVL BX, CX + SHRL $2, CX + ANDL $3, BX + REP; MOVSL +/* + * copy the rest, by bytes + */ + ADDL $3, DI + ADDL $3, SI + MOVL BX, CX + REP; MOVSB + + MOVL p+0(FP),AX + RET diff --git a/sys/src/libc/386/memmove.s b/sys/src/libc/386/memmove.s new file mode 100755 index 000000000..90eee75c1 --- /dev/null +++ b/sys/src/libc/386/memmove.s @@ -0,0 +1,71 @@ +TEXT memmove(SB), $0 + MOVL p1+0(FP), DI + MOVL DI, AX /* return value */ + MOVL p2+4(FP), SI + MOVL n+8(FP), BX + CMPL BX, $0 + JGT _ok + JEQ _return /* nothing to do if n == 0 */ + MOVL $0, SI /* fault if n < 0 */ + +/* + * check and set for backwards: + * (p2 < p1) && ((p2+n) > p1) + */ +_ok: + CMPL SI, DI + JGT _forward + JEQ _return /* nothing to do if p2 == p1 */ + MOVL SI, DX + ADDL BX, DX + CMPL DX, DI + JGT _back + +/* + * copy whole longs + */ +_forward: + MOVL BX, CX + CLD + SHRL $2, CX + ANDL $3, BX + REP; MOVSL + +/* + * copy the rest, by bytes + */ + JEQ _return /* flags set by above ANDL */ + MOVL BX, CX + REP; MOVSB + + RET + +/* + * whole thing backwards has + * adjusted addresses + */ +_back: + ADDL BX, DI + ADDL BX, SI + STD + SUBL $4, DI + SUBL $4, SI +/* + * copy whole longs + */ + MOVL BX, CX + SHRL $2, CX + ANDL $3, BX + REP; MOVSL +/* + * copy the rest, by bytes + */ + JEQ _return /* flags set by above ANDL */ + + ADDL $3, DI + ADDL $3, SI + MOVL BX, CX + REP; MOVSB + +_return: + RET diff --git a/sys/src/libc/386/memset.s b/sys/src/libc/386/memset.s new file mode 100755 index 000000000..6e482abee --- /dev/null +++ b/sys/src/libc/386/memset.s @@ -0,0 +1,35 @@ + TEXT memset(SB),$0 + + CLD + MOVL p+0(FP), DI + MOVBLZX c+4(FP), AX + MOVL n+8(FP), BX +/* + * if not enough bytes, just set bytes + */ + CMPL BX, $9 + JLS c3 +/* + * build word in AX + */ + MOVB AL, AH + MOVL AX, CX + SHLL $16, CX + ORL CX, AX +/* + * set whole longs + */ +c1: + MOVL BX, CX + SHRL $2, CX + ANDL $3, BX + REP; STOSL +/* + * set the rest, by bytes + */ +c3: + MOVL BX, CX + REP; STOSB +ret: + MOVL p+0(FP),AX + RET diff --git a/sys/src/libc/386/mkfile b/sys/src/libc/386/mkfile new file mode 100755 index 000000000..417ea5ffb --- /dev/null +++ b/sys/src/libc/386/mkfile @@ -0,0 +1,42 @@ +objtype=386 +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +SFILES=\ + argv0.s\ + atom.s\ + getfcr.s\ + main9.s\ + main9p.s\ + memccpy.s\ + memchr.s\ + memcmp.s\ + memcpy.s\ + memmove.s\ + memset.s\ + muldiv.s\ + cycles.s\ + setjmp.s\ + sqrt.s\ + strcat.s\ + strchr.s\ + strcpy.s\ + strlen.s\ + tas.s\ + vlop.s\ + +CFILES=\ + getcallerpc.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/386/muldiv.s b/sys/src/libc/386/muldiv.s new file mode 100755 index 000000000..5f11a97e6 --- /dev/null +++ b/sys/src/libc/386/muldiv.s @@ -0,0 +1,12 @@ +TEXT umuldiv(SB), $0 + MOVL a+0(FP), AX + MULL b+4(FP) + DIVL c+8(FP) + RET + +TEXT muldiv(SB), $0 + MOVL a+0(FP), AX + IMULL b+4(FP) + IDIVL c+8(FP) + RET + END diff --git a/sys/src/libc/386/notejmp.c b/sys/src/libc/386/notejmp.c new file mode 100755 index 000000000..5d912767d --- /dev/null +++ b/sys/src/libc/386/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->ax = ret; + if(ret == 0) + r->ax = 1; + r->pc = j[JMPBUFPC]; + r->sp = j[JMPBUFSP] + 4; + noted(NCONT); +} diff --git a/sys/src/libc/386/setjmp.s b/sys/src/libc/386/setjmp.s new file mode 100755 index 000000000..697fa7359 --- /dev/null +++ b/sys/src/libc/386/setjmp.s @@ -0,0 +1,18 @@ +TEXT longjmp(SB), $0 + MOVL r+4(FP), AX + CMPL AX, $0 + JNE ok /* ansi: "longjmp(0) => longjmp(1)" */ + MOVL $1, AX /* bless their pointed heads */ +ok: MOVL l+0(FP), BX + MOVL 0(BX), SP /* restore sp */ + MOVL 4(BX), BX /* put return pc on the stack */ + MOVL BX, 0(SP) + RET + +TEXT setjmp(SB), $0 + MOVL l+0(FP), AX + MOVL SP, 0(AX) /* store sp */ + MOVL 0(SP), BX /* store return pc */ + MOVL BX, 4(AX) + MOVL $0, AX /* return 0 */ + RET diff --git a/sys/src/libc/386/sqrt.s b/sys/src/libc/386/sqrt.s new file mode 100755 index 000000000..219a8ac6b --- /dev/null +++ b/sys/src/libc/386/sqrt.s @@ -0,0 +1,16 @@ +TEXT sqrt(SB), $0 + FMOVD a+0(FP), F0 + + FTST + WAIT + FSTSW AX + SAHF + JLO bad + + FSQRT + RET + +bad: + FMOVDP F0, F0 + CALL NaN(SB) + RET diff --git a/sys/src/libc/386/strcat.s b/sys/src/libc/386/strcat.s new file mode 100755 index 000000000..3f41fefa5 --- /dev/null +++ b/sys/src/libc/386/strcat.s @@ -0,0 +1,43 @@ + TEXT strcat(SB),$0 + + MOVL $0, AX + MOVL $-1, CX + CLD + +/* + * find length of second string + */ + + MOVL p2+4(FP), DI + REPN; SCASB + + MOVL DI, BX + SUBL p2+4(FP), BX + +/* + * find end of first string + */ + + MOVL p1+0(FP), DI + REPN; SCASB + +/* + * copy the memory + */ + SUBL $1, DI + MOVL p2+4(FP), SI +/* + * copy whole longs + */ + MOVL BX, CX + SHRL $2, CX + REP; MOVSL +/* + * copy the rest, by bytes + */ + ANDL $3, BX + MOVL BX, CX + REP; MOVSB + + MOVL p1+0(FP), AX + RET diff --git a/sys/src/libc/386/strchr.s b/sys/src/libc/386/strchr.s new file mode 100755 index 000000000..873bdcf12 --- /dev/null +++ b/sys/src/libc/386/strchr.s @@ -0,0 +1,38 @@ + TEXT strchr(SB), $0 + + MOVL s+0(FP), DI + MOVB c+4(FP), AX + CMPB AX, $0 + JEQ l2 /**/ + +/* + * char is not null + */ +l1: + MOVB (DI), BX + CMPB BX, $0 + JEQ ret0 + ADDL $1, DI + CMPB AX, BX + JNE l1 + + MOVL DI, AX + SUBL $1, AX + RET + +/* + * char is null + */ +l2: + MOVL $-1, CX + CLD + + REPN; SCASB + + MOVL DI, AX + SUBL $1, AX + RET + +ret0: + MOVL $0, AX + RET diff --git a/sys/src/libc/386/strcpy.s b/sys/src/libc/386/strcpy.s new file mode 100755 index 000000000..83482e8a2 --- /dev/null +++ b/sys/src/libc/386/strcpy.s @@ -0,0 +1,35 @@ + TEXT strcpy(SB),$0 + + MOVL $0, AX + MOVL $-1, CX + CLD +/* + * find end of second string + */ + + MOVL p2+4(FP), DI + REPN; SCASB + + MOVL DI, BX + SUBL p2+4(FP), BX + +/* + * copy the memory + */ + MOVL p1+0(FP), DI + MOVL p2+4(FP), SI +/* + * copy whole longs + */ + MOVL BX, CX + SHRL $2, CX + REP; MOVSL +/* + * copy the rest, by bytes + */ + ANDL $3, BX + MOVL BX, CX + REP; MOVSB + + MOVL p1+0(FP), AX + RET diff --git a/sys/src/libc/386/strlen.s b/sys/src/libc/386/strlen.s new file mode 100755 index 000000000..e0330ffcc --- /dev/null +++ b/sys/src/libc/386/strlen.s @@ -0,0 +1,16 @@ + TEXT strlen(SB),$0 + + MOVL $0, AX + MOVL $-1, CX + CLD +/* + * look for end of string + */ + + MOVL p+0(FP), DI + REPN; SCASB + + MOVL DI, AX + SUBL p+0(FP), AX + SUBL $1, AX + RET diff --git a/sys/src/libc/386/tas.s b/sys/src/libc/386/tas.s new file mode 100755 index 000000000..9649dcacf --- /dev/null +++ b/sys/src/libc/386/tas.s @@ -0,0 +1,6 @@ +TEXT _tas(SB),$0 + + MOVL $0xdeadead,AX + MOVL l+0(FP),BX + XCHGL AX,(BX) + RET diff --git a/sys/src/libc/386/vlop.s b/sys/src/libc/386/vlop.s new file mode 100755 index 000000000..1ad69f274 --- /dev/null +++ b/sys/src/libc/386/vlop.s @@ -0,0 +1,54 @@ +TEXT _mulv(SB), $0 + MOVL r+0(FP), CX + MOVL a+4(FP), AX + MULL b+12(FP) + MOVL AX, 0(CX) + MOVL DX, BX + MOVL a+4(FP), AX + MULL b+16(FP) + ADDL AX, BX + MOVL a+8(FP), AX + MULL b+12(FP) + ADDL AX, BX + MOVL BX, 4(CX) + RET + +TEXT _mul64by32(SB), $0 + MOVL r+0(FP), CX + MOVL a+4(FP), AX + MULL b+12(FP) + MOVL AX, 0(CX) + MOVL DX, BX + MOVL a+8(FP), AX + MULL b+12(FP) + ADDL AX, BX + MOVL BX, 4(CX) + RET + +TEXT _div64by32(SB), $0 + MOVL r+12(FP), CX + MOVL a+0(FP), AX + MOVL a+4(FP), DX + DIVL b+8(FP) + MOVL DX, 0(CX) + RET + +TEXT _addv(SB),1,$0 /* used in profiler, can't be profiled */ + MOVL r+0(FP), CX + MOVL a+4(FP), AX + MOVL a+8(FP), BX + ADDL b+12(FP), AX + ADCL b+16(FP), BX + MOVL AX, 0(CX) + MOVL BX, 4(CX) + RET + +TEXT _subv(SB),1,$0 /* used in profiler, can't be profiled */ + MOVL r+0(FP), CX + MOVL a+4(FP), AX + MOVL a+8(FP), BX + SUBL b+12(FP), AX + SBBL b+16(FP), BX + MOVL AX, 0(CX) + MOVL BX, 4(CX) + RET diff --git a/sys/src/libc/386/vlrt.c b/sys/src/libc/386/vlrt.c new file mode 100755 index 000000000..83fd09683 --- /dev/null +++ b/sys/src/libc/386/vlrt.c @@ -0,0 +1,746 @@ +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef signed char schar; + +#define SIGN(n) (1UL<<(n-1)) + +typedef struct Vlong Vlong; +struct Vlong +{ + union + { + struct + { + ulong lo; + ulong hi; + }; + struct + { + ushort lols; + ushort loms; + ushort hils; + ushort hims; + }; + }; +}; + +void abort(void); + +void _subv(Vlong*, Vlong, Vlong); + +void +_d2v(Vlong *y, double d) +{ + union { double d; struct Vlong; } x; + ulong xhi, xlo, ylo, yhi; + int sh; + + x.d = d; + + xhi = (x.hi & 0xfffff) | 0x100000; + xlo = x.lo; + sh = 1075 - ((x.hi >> 20) & 0x7ff); + + ylo = 0; + yhi = 0; + if(sh >= 0) { + /* v = (hi||lo) >> sh */ + if(sh < 32) { + if(sh == 0) { + ylo = xlo; + yhi = xhi; + } else { + ylo = (xlo >> sh) | (xhi << (32-sh)); + yhi = xhi >> sh; + } + } else { + if(sh == 32) { + ylo = xhi; + } else + if(sh < 64) { + ylo = xhi >> (sh-32); + } + } + } else { + /* v = (hi||lo) << -sh */ + sh = -sh; + if(sh <= 10) { + ylo = xlo << sh; + yhi = (xhi << sh) | (xlo >> (32-sh)); + } else { + /* overflow */ + yhi = d; /* causes something awful */ + } + } + if(x.hi & SIGN(32)) { + if(ylo != 0) { + ylo = -ylo; + yhi = ~yhi; + } else + yhi = -yhi; + } + + y->hi = yhi; + y->lo = ylo; +} + +void +_f2v(Vlong *y, float f) +{ + + _d2v(y, f); +} + +double +_v2d(Vlong x) +{ + if(x.hi & SIGN(32)) { + if(x.lo) { + x.lo = -x.lo; + x.hi = ~x.hi; + } else + x.hi = -x.hi; + return -((long)x.hi*4294967296. + x.lo); + } + return (long)x.hi*4294967296. + x.lo; +} + +float +_v2f(Vlong x) +{ + return _v2d(x); +} + +ulong _div64by32(Vlong, ulong, ulong*); +void _mul64by32(Vlong*, Vlong, ulong); + +static void +slowdodiv(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; + } +} + +static void +dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp) +{ + ulong n; + Vlong x, q, r; + + if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){ + if(qp) { + qp->hi = 0; + qp->lo = 0; + } + if(rp) { + rp->hi = num.hi; + rp->lo = num.lo; + } + return; + } + + if(den.hi != 0){ + q.hi = 0; + n = num.hi/den.hi; + _mul64by32(&x, den, n); + if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)) + slowdodiv(num, den, &q, &r); + else { + q.lo = n; + _subv(&r, num, x); + } + } else { + if(num.hi >= den.lo){ + q.hi = n = num.hi/den.lo; + num.hi -= den.lo*n; + } else { + q.hi = 0; + } + q.lo = _div64by32(num, den.lo, &r.lo); + r.hi = 0; + } + if(qp) { + qp->lo = q.lo; + qp->hi = q.hi; + } + if(rp) { + rp->lo = r.lo; + rp->hi = r.hi; + } +} + +void +_divvu(Vlong *q, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + q->hi = 0; + q->lo = n.lo / d.lo; + return; + } + dodiv(n, d, q, 0); +} + +void +_modvu(Vlong *r, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + r->hi = 0; + r->lo = n.lo % d.lo; + return; + } + dodiv(n, d, 0, r); +} + +static void +vneg(Vlong *v) +{ + + if(v->lo == 0) { + v->hi = -v->hi; + return; + } + v->lo = -v->lo; + v->hi = ~v->hi; +} + +void +_divv(Vlong *q, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + q->lo = (long)n.lo / (long)d.lo; + q->hi = ((long)q->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, q, 0); + if(nneg != dneg) + vneg(q); +} + +void +_modv(Vlong *r, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + r->lo = (long)n.lo % (long)d.lo; + r->hi = ((long)r->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, 0, r); + if(nneg) + vneg(r); +} + +void +_rshav(Vlong *r, Vlong a, int b) +{ + long t; + + t = a.hi; + if(b >= 32) { + r->hi = t>>31; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = t>>31; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_rshlv(Vlong *r, Vlong a, int b) +{ + ulong t; + + t = a.hi; + if(b >= 32) { + r->hi = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = 0; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_lshv(Vlong *r, Vlong a, int b) +{ + ulong t; + + t = a.lo; + if(b >= 32) { + r->lo = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->hi = 0; + return; + } + r->hi = t << (b-32); + return; + } + if(b <= 0) { + r->lo = t; + r->hi = a.hi; + return; + } + r->lo = t << b; + r->hi = (t >> (32-b)) | (a.hi << b); +} + +void +_andv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi & b.hi; + r->lo = a.lo & b.lo; +} + +void +_orv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi | b.hi; + r->lo = a.lo | b.lo; +} + +void +_xorv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi ^ b.hi; + r->lo = a.lo ^ b.lo; +} + +void +_vpp(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + r->lo++; + if(r->lo == 0) + r->hi++; +} + +void +_vmm(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + if(r->lo == 0) + r->hi--; + r->lo--; +} + +void +_ppv(Vlong *l, Vlong *r) +{ + + r->lo++; + if(r->lo == 0) + r->hi++; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_mmv(Vlong *l, Vlong *r) +{ + + if(r->lo == 0) + r->hi--; + r->lo--; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) +{ + Vlong t, u; + + u.lo = 0; + u.hi = 0; + switch(type) { + default: + abort(); + break; + + case 1: /* schar */ + t.lo = *(schar*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(schar*)lv = u.lo; + break; + + case 2: /* uchar */ + t.lo = *(uchar*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uchar*)lv = u.lo; + break; + + case 3: /* short */ + t.lo = *(short*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(short*)lv = u.lo; + break; + + case 4: /* ushort */ + t.lo = *(ushort*)lv; + t.hi = 0; + fn(&u, t, rv); + *(ushort*)lv = u.lo; + break; + + case 9: /* int */ + t.lo = *(int*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(int*)lv = u.lo; + break; + + case 10: /* uint */ + t.lo = *(uint*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uint*)lv = u.lo; + break; + + case 5: /* long */ + t.lo = *(long*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(long*)lv = u.lo; + break; + + case 6: /* ulong */ + t.lo = *(ulong*)lv; + t.hi = 0; + fn(&u, t, rv); + *(ulong*)lv = u.lo; + break; + + case 7: /* vlong */ + case 8: /* uvlong */ + fn(&u, *(Vlong*)lv, rv); + *(Vlong*)lv = u; + break; + } + *ret = u; +} + +void +_p2v(Vlong *ret, void *p) +{ + long t; + + t = (ulong)p; + ret->lo = t; + ret->hi = 0; +} + +void +_sl2v(Vlong *ret, long sl) +{ + long t; + + t = sl; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ul2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul; + ret->lo = t; + ret->hi = 0; +} + +void +_si2v(Vlong *ret, int si) +{ + long t; + + t = si; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ui2v(Vlong *ret, uint ui) +{ + long t; + + t = ui; + ret->lo = t; + ret->hi = 0; +} + +void +_sh2v(Vlong *ret, long sh) +{ + long t; + + t = (sh << 16) >> 16; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uh2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul & 0xffff; + ret->lo = t; + ret->hi = 0; +} + +void +_sc2v(Vlong *ret, long uc) +{ + long t; + + t = (uc << 24) >> 24; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uc2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul & 0xff; + ret->lo = t; + ret->hi = 0; +} + +long +_v2sc(Vlong rv) +{ + long t; + + t = rv.lo & 0xff; + return (t << 24) >> 24; +} + +long +_v2uc(Vlong rv) +{ + + return rv.lo & 0xff; +} + +long +_v2sh(Vlong rv) +{ + long t; + + t = rv.lo & 0xffff; + return (t << 16) >> 16; +} + +long +_v2uh(Vlong rv) +{ + + return rv.lo & 0xffff; +} + +long +_v2sl(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ul(Vlong rv) +{ + + return rv.lo; +} + +long +_v2si(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ui(Vlong rv) +{ + + return rv.lo; +} + +int +_testv(Vlong rv) +{ + return rv.lo || rv.hi; +} + +int +_eqv(Vlong lv, Vlong rv) +{ + return lv.lo == rv.lo && lv.hi == rv.hi; +} + +int +_nev(Vlong lv, Vlong rv) +{ + return lv.lo != rv.lo || lv.hi != rv.hi; +} + +int +_ltv(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lev(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_gtv(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_gev(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} + +int +_lov(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lsv(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_hiv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_hsv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} diff --git a/sys/src/libc/68000/argv0.s b/sys/src/libc/68000/argv0.s new file mode 100755 index 000000000..8d9f9b29b --- /dev/null +++ b/sys/src/libc/68000/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/68000/cycles.c b/sys/src/libc/68000/cycles.c new file mode 100755 index 000000000..9bad3a989 --- /dev/null +++ b/sys/src/libc/68000/cycles.c @@ -0,0 +1,7 @@ +#include <u.h> +#include <libc.h> + +void cycles(uvlong*u) +{ + *u = 0LL; +} diff --git a/sys/src/libc/68000/doprint.c b/sys/src/libc/68000/doprint.c new file mode 100755 index 000000000..e3846a8d8 --- /dev/null +++ b/sys/src/libc/68000/doprint.c @@ -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/68000/getfcr.s b/sys/src/libc/68000/getfcr.s new file mode 100755 index 000000000..7f67d038f --- /dev/null +++ b/sys/src/libc/68000/getfcr.s @@ -0,0 +1,19 @@ +TEXT getfsr(SB), $0 + MOVL $0, R0 + MOVL FPSR, R0 + RTS + +TEXT setfsr(SB), $0 + MOVL new+0(FP), R1 + MOVL R1, FPSR + RTS + +TEXT getfcr(SB), $0 + MOVL $0, R0 + MOVL FPCR, R0 + RTS + +TEXT setfcr(SB), $0 + MOVL new+0(FP), R1 + MOVL R1, FPCR + RTS diff --git a/sys/src/libc/68000/main9.s b/sys/src/libc/68000/main9.s new file mode 100755 index 000000000..86b23d257 --- /dev/null +++ b/sys/src/libc/68000/main9.s @@ -0,0 +1,18 @@ +#define NPRIVATES 16 + +TEXT _main(SB), 1, $(16 + NPRIVATES*4) + MOVL $a6base(SB), A6 + MOVL R0, _tos(SB) + LEA p-64(SP),A0 + MOVL A0,_privates+0(SB) + MOVL $16,R0 + MOVL R0,_nprivates+0(SB) + PEA inargv+0(FP) + MOVL inargc-4(FP), TOS + BSR main(SB) + PEA _exits<>+0(SB) + BSR exits(SB) + RTS + +DATA _exits<>+0(SB)/4, $"main" +GLOBL _exits<>+0(SB), $5 diff --git a/sys/src/libc/68000/main9p.s b/sys/src/libc/68000/main9p.s new file mode 100755 index 000000000..61e0294d5 --- /dev/null +++ b/sys/src/libc/68000/main9p.s @@ -0,0 +1,31 @@ +#define NPRIVATES 16 + +TEXT _mainp(SB), 1, $(16 + NPRIVATES*4) + MOVL $a6base(SB), A6 + MOVL R0, _tos(SB) /* return value of sys exec!! */ + LEA p-64(SP),A0 + MOVL A0,_privates+0(SB) + MOVL $16,R0 + MOVL R0,_nprivates+0(SB) + BSR _profmain(SB) + MOVL __prof+4(SB), __prof+0(SB) + PEA inargv+0(FP) + MOVL inargc-4(FP), TOS + BSR main(SB) + +loop: + PEA _exits<>+0(SB) + BSR exits(SB) + LEA _profin(SB), A0 /* force loading of profile */ + BRA loop + +TEXT _savearg(SB), 1, $0 + RTS + +TEXT _callpc(SB), 1, $0 + MOVL argp+0(FP), A0 + MOVL 4(A0), R0 + RTS + +DATA _exits<>+0(SB)/4, $"main" +GLOBL _exits<>+0(SB), $5 diff --git a/sys/src/libc/68000/memccpy.s b/sys/src/libc/68000/memccpy.s new file mode 100755 index 000000000..3e494e915 --- /dev/null +++ b/sys/src/libc/68000/memccpy.s @@ -0,0 +1,30 @@ + TEXT memccpy(SB),$0 + MOVL n+12(FP),R0 + BEQ ret + MOVL s1+0(FP),A2 + MOVL s2+4(FP),A1 + MOVL c+8(FP),R1 + BEQ l2 + +/* + * general case + */ +l1: MOVB (A1)+,R2 + MOVB R2,(A2)+ + CMPB R2,R1 + BEQ eq + SUBL $1,R0 + BNE l1 + RTS + +/* + * special case for null character + */ +l2: MOVB (A1)+,(A2)+ + BEQ eq + SUBL $1,R0 + BNE l2 + RTS + +eq: MOVL A2,R0 +ret: RTS diff --git a/sys/src/libc/68000/memchr.s b/sys/src/libc/68000/memchr.s new file mode 100755 index 000000000..ea2584df8 --- /dev/null +++ b/sys/src/libc/68000/memchr.s @@ -0,0 +1,15 @@ + TEXT memchr(SB),$0 + MOVL n+8(FP),R0 + BEQ ret + MOVL s1+0(FP),A1 + MOVL c+4(FP),R1 + +l1: CMPB R1,(A1)+ + BEQ eq + SUBL $1,R0 + BNE l1 + RTS + +eq: MOVL A1,R0 + SUBL $1,R0 +ret: RTS diff --git a/sys/src/libc/68000/memcmp.s b/sys/src/libc/68000/memcmp.s new file mode 100755 index 000000000..97d208e3b --- /dev/null +++ b/sys/src/libc/68000/memcmp.s @@ -0,0 +1,18 @@ + TEXT memcmp(SB),$0 + MOVL n+8(FP),R0 + BEQ ret + MOVL s1+0(FP),A2 + MOVL s2+4(FP),A1 + +l1: CMPB (A1)+,(A2)+ + BNE neq + SUBL $1,R0 + BNE l1 + RTS + +neq: BCS gtr + MOVL $-1,R0 + RTS + +gtr: MOVL $1,R0 +ret: RTS diff --git a/sys/src/libc/68000/memcpy.s b/sys/src/libc/68000/memcpy.s new file mode 100755 index 000000000..bf4b1d5df --- /dev/null +++ b/sys/src/libc/68000/memcpy.s @@ -0,0 +1,120 @@ + TEXT memcpy(SB), $0 + + MOVL n+8(FP), R0 /* count */ + BEQ return + BGT ok + MOVL 0, R0 +ok: + MOVL s1+0(FP), A2 /* dest pointer */ + MOVL s2+4(FP), A1 /* source pointer */ + + CMPL A2,A1 + BHI back + +/* + * byte-at-a-time foreward copy to + * get source (A1) alligned. + */ +f1: + MOVL A1, R1 + ANDL $3, R1 + BEQ f2 + SUBL $1, R0 + BLT return + MOVB (A1)+, (A2)+ + BRA f1 + +/* + * check that dest is alligned + * if not, just go byte-at-a-time + */ +f2: + MOVL A2, R1 + ANDL $3, R1 + BEQ f3 + SUBL $1, R0 + BLT return + BRA f5 +/* + * quad-long-at-a-time forward copy + */ +f3: + SUBL $16, R0 + BLT f4 + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + BRA f3 + +/* + * cleanup byte-at-a-time + */ +f4: + ADDL $15, R0 + BLT return +f5: + MOVB (A1)+, (A2)+ + SUBL $1, R0 + BGE f5 + BRA return + +return: + MOVL s1+0(FP),R0 + RTS + +/* + * everything the same, but + * copy backwards + */ +back: + ADDL R0, A1 + ADDL R0, A2 + +/* + * byte-at-a-time backward copy to + * get source (A1) alligned. + */ +b1: + MOVL A1, R1 + ANDL $3, R1 + BEQ b2 + SUBL $1, R0 + BLT return + MOVB -(A1), -(A2) + BRA b1 + +/* + * check that dest is alligned + * if not, just go byte-at-a-time + */ +b2: + MOVL A2, R1 + ANDL $3, R1 + BEQ b3 + SUBL $1, R0 + BLT return + BRA b5 +/* + * quad-long-at-a-time backward copy + */ +b3: + SUBL $16, R0 + BLT b4 + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + BRA b3 + +/* + * cleanup byte-at-a-time backward + */ +b4: + ADDL $15, R0 + BLT return +b5: + MOVB -(A1), -(A2) + SUBL $1, R0 + BGE b5 + BRA return diff --git a/sys/src/libc/68000/memmove.s b/sys/src/libc/68000/memmove.s new file mode 100755 index 000000000..618e368d3 --- /dev/null +++ b/sys/src/libc/68000/memmove.s @@ -0,0 +1,120 @@ + TEXT memmove(SB), $0 + + MOVL n+8(FP), R0 /* count */ + BEQ return + BGT ok + MOVL 0, R0 +ok: + MOVL s1+0(FP), A2 /* dest pointer */ + MOVL s2+4(FP), A1 /* source pointer */ + + CMPL A2,A1 + BHI back + +/* + * byte-at-a-time foreward copy to + * get source (A1) alligned. + */ +f1: + MOVL A1, R1 + ANDL $3, R1 + BEQ f2 + SUBL $1, R0 + BLT return + MOVB (A1)+, (A2)+ + BRA f1 + +/* + * check that dest is alligned + * if not, just go byte-at-a-time + */ +f2: + MOVL A2, R1 + ANDL $3, R1 + BEQ f3 + SUBL $1, R0 + BLT return + BRA f5 +/* + * quad-long-at-a-time forward copy + */ +f3: + SUBL $16, R0 + BLT f4 + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + BRA f3 + +/* + * cleanup byte-at-a-time + */ +f4: + ADDL $15, R0 + BLT return +f5: + MOVB (A1)+, (A2)+ + SUBL $1, R0 + BGE f5 + BRA return + +return: + MOVL s1+0(FP),R0 + RTS + +/* + * everything the same, but + * copy backwards + */ +back: + ADDL R0, A1 + ADDL R0, A2 + +/* + * byte-at-a-time backward copy to + * get source (A1) alligned. + */ +b1: + MOVL A1, R1 + ANDL $3, R1 + BEQ b2 + SUBL $1, R0 + BLT return + MOVB -(A1), -(A2) + BRA b1 + +/* + * check that dest is alligned + * if not, just go byte-at-a-time + */ +b2: + MOVL A2, R1 + ANDL $3, R1 + BEQ b3 + SUBL $1, R0 + BLT return + BRA b5 +/* + * quad-long-at-a-time backward copy + */ +b3: + SUBL $16, R0 + BLT b4 + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + BRA b3 + +/* + * cleanup byte-at-a-time backward + */ +b4: + ADDL $15, R0 + BLT return +b5: + MOVB -(A1), -(A2) + SUBL $1, R0 + BGE b5 + BRA return diff --git a/sys/src/libc/68000/memset.s b/sys/src/libc/68000/memset.s new file mode 100755 index 000000000..318f61a7c --- /dev/null +++ b/sys/src/libc/68000/memset.s @@ -0,0 +1,57 @@ + TEXT memset(SB), $0 + MOVL n+8(FP), R0 + BLE return + MOVL s1+0(FP), A1 + CLRL R1 + MOVB c+7(FP), R1 + BEQ l1 + +/* + * create 4 replicated copies + * of the byte in R1 + */ + MOVL R1, R2 + ASLL $8, R2 + ORL R2, R1 + MOVL R1, R2 + SWAP R2 + ORL R2, R1 + +/* + * byte-at-a-time until alligned + */ +l1: + MOVL A1, R1 + ANDL $3, R1 + BEQ l2 + SUBL $1, R0 + BLT return + MOVB R1, (A1)+ + BRA l1 + +/* + * quad-long-at-a-time set + */ +l2: + SUBL $16, R0 + BLT l3 + MOVL R1, (A1)+ + MOVL R1, (A1)+ + MOVL R1, (A1)+ + MOVL R1, (A1)+ + BRA l2 + +/* + * cleanup byte-at-a-time + */ +l3: + ADDL $15, R0 + BLT return +l4: + MOVB R1, (A1)+ + SUBL $1, R0 + BGE l4 + +return: + MOVL s1+0(FP),R0 + RTS diff --git a/sys/src/libc/68000/mkfile b/sys/src/libc/68000/mkfile new file mode 100755 index 000000000..573d49268 --- /dev/null +++ b/sys/src/libc/68000/mkfile @@ -0,0 +1,40 @@ +objtype=68000 +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +SFILES=\ + argv0.s\ + getfcr.s\ + main9.s\ + main9p.s\ + memccpy.s\ + memchr.s\ + memcmp.s\ + memcpy.s\ + memmove.s\ + memset.s\ + muldivrt.s\ + scale.s\ + setjmp.s\ + sqrt.s\ + strcat.s\ + strchr.s\ + strcmp.s\ + strcpy.s\ + strlen.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/68000/muldivrt.s b/sys/src/libc/68000/muldivrt.s new file mode 100755 index 000000000..10ef6f46b --- /dev/null +++ b/sys/src/libc/68000/muldivrt.s @@ -0,0 +1,172 @@ +/* + * calls _divul with + * absolute value arguments + */ +TEXT _divsl(SB), $0 + MOVL R0, TOS + + MOVL b+4(FP), R0 + BPL y1 + NEGL R0 + MOVL R0, TOS + + MOVL a+0(FP), R0 + BPL y3 + NEGL R0 + MOVL R0, TOS + + /* neg/neg */ + JSR _divul(SB) + MOVL TOS, R0 + MOVL R0, a+0(FP) + MOVL TOS, R0 + NEGL R0 + MOVL R0, b+4(FP) + MOVL TOS, R0 + RTS + +y1: MOVL R0, TOS + + MOVL a+0(FP), R0 + BPL y2 + NEGL R0 + MOVL R0, TOS + + /* neg/pos */ + JSR _divul(SB) + MOVL TOS, R0 + NEGL R0 + MOVL R0, a+0(FP) + MOVL TOS, R0 + NEGL R0 + MOVL R0, b+4(FP) + MOVL TOS, R0 + RTS + +y2: MOVL R0, TOS + + /* pos/pos */ + JSR _divul(SB) + MOVL TOS, R0 + MOVL R0, a+0(FP) + MOVL TOS, R0 + MOVL R0, b+4(FP) + MOVL TOS, R0 + RTS + +y3: MOVL R0, TOS + + /* pos/neg */ + JSR _divul(SB) + MOVL TOS, R0 + NEGL R0 + MOVL R0, a+0(FP) + MOVL TOS, R0 + MOVL R0, b+4(FP) + MOVL TOS, R0 + RTS + +/* + * for(i=1;; i++) { + * if(den & (1<<31)) + * break; + * den <<= 1; + * } + * + * for(; i; i--) { + * quo <<= 1; + * if(num >= den) { + * num -= den; + * quo |= 1; + * } + * den >>= 1; + * } + */ +TEXT _divul(SB), $0 + MOVL R0, TOS /* i */ + MOVL R1, TOS /* num */ + MOVL R2, TOS /* den */ + MOVL R3, TOS /* quo */ + + MOVL $0, R0 + MOVL $0, R3 + MOVL a+0(FP), R1 + MOVL b+4(FP), R2 + BEQ xout + BMI x1 + + ADDL $1, R0 + LSLL $1, R2 + BPL -2(PC) + +x1: LSLL $1, R3 + CMPL R1, R2 + BCS 3(PC) + SUBL R2, R1 + ORL $1, R3 + LSRL $1, R2 + DBMI R0, x1 + + MOVL R3, a+0(FP) + MOVL R1, b+4(FP) + +xout: + MOVL TOS, R3 + MOVL TOS, R2 + MOVL TOS, R1 + MOVL TOS, R0 + RTS + +/* + * x = 0; + * for(i=0; i<32; i++) { + * if(a & 1) + * x += b; + * a >>= 1; + * b <<= 1; + * } + * a = x; + */ +TEXT _mull(SB), $0 + MOVL R0, TOS /* i */ + MOVL R1, TOS /* a */ + MOVL R2, TOS /* b */ + MOVL R3, TOS /* x */ + + MOVL a+0(FP), R1 + MOVL b+4(FP), R2 + MOVL $32, R0 + CLRL R3 + +z1: ROTRL $1, R1 + BCC 2(PC) + ADDL R2, R3 + LSLL $1, R2 + DBEQ R0, z1 + + MOVL R3, b+4(FP) + MOVL TOS, R3 + MOVL TOS, R2 + MOVL TOS, R1 + MOVL TOS, R0 + RTS + +TEXT _ccr(SB), $0 + PEA (A0) + SUBL A0, A0 + + BCC 2(PC) + LEA 1(A0), A0 + + BVC 2(PC) + LEA 2(A0), A0 + + BNE 2(PC) + LEA 4(A0), A0 + + BPL 2(PC) + LEA 8(A0), A0 + + MOVW A0, a+0(FP) + MOVL TOS, A0 + RTS diff --git a/sys/src/libc/68000/notejmp.c b/sys/src/libc/68000/notejmp.c new file mode 100755 index 000000000..61562d441 --- /dev/null +++ b/sys/src/libc/68000/notejmp.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> +#define UREGVARSZ 4 /* not right but doesn't matter */ +#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->usp = j[JMPBUFSP] + 4; + noted(NCONT); +} diff --git a/sys/src/libc/68000/scale.s b/sys/src/libc/68000/scale.s new file mode 100755 index 000000000..0e0e50a86 --- /dev/null +++ b/sys/src/libc/68000/scale.s @@ -0,0 +1,4 @@ + TEXT fscale(SB), $0 + FMOVED a+0(FP), F0 + FSCALEL x+8(FP), F0 + RTS diff --git a/sys/src/libc/68000/setjmp.s b/sys/src/libc/68000/setjmp.s new file mode 100755 index 000000000..827b71fc1 --- /dev/null +++ b/sys/src/libc/68000/setjmp.s @@ -0,0 +1,15 @@ +TEXT setjmp(SB), 1, $0 + MOVL b+0(FP), A0 + MOVL A7, (A0)+ + MOVL (A7), (A0) + CLRL R0 + RTS + +TEXT longjmp(SB), 1, $0 + MOVL b+0(FP), A0 + MOVL r+4(FP), R0 + BNE ok /* ansi: "longjmp(0) => longjmp(1)" */ + MOVL $1, R0 /* bless their pointed heads */ +ok: MOVL (A0)+, A7 + MOVL (A0), (A7) + RTS diff --git a/sys/src/libc/68000/sqrt.s b/sys/src/libc/68000/sqrt.s new file mode 100755 index 000000000..5109bc255 --- /dev/null +++ b/sys/src/libc/68000/sqrt.s @@ -0,0 +1,3 @@ + TEXT sqrt(SB),$0 + FSQRTD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68000/strcat.s b/sys/src/libc/68000/strcat.s new file mode 100755 index 000000000..95821408b --- /dev/null +++ b/sys/src/libc/68000/strcat.s @@ -0,0 +1,15 @@ + TEXT strcat(SB), $0 + MOVL s1+0(FP), A2 + MOVL s2+4(FP), A1 + +l1: TSTB (A2)+ + BNE l1 + + MOVB (A1)+, -1(A2) + BEQ done + +l2: MOVB (A1)+, (A2)+ + BNE l2 + +done: MOVL s1+0(FP), R0 + RTS diff --git a/sys/src/libc/68000/strchr.s b/sys/src/libc/68000/strchr.s new file mode 100755 index 000000000..a5d4be2c6 --- /dev/null +++ b/sys/src/libc/68000/strchr.s @@ -0,0 +1,27 @@ + TEXT strchr(SB), $0 + + MOVL s+0(FP), A0 + MOVB c+7(FP), R2 + BEQ null + +l: + MOVB (A0)+, R1 + BEQ out + CMPB R1, R2 + BNE l + + MOVL A0, R0 + ADDL $-1, R0 + RTS + +out: + CLRL R0 + RTS + +null: + TSTB (A0)+ + BNE null + + MOVL A0, R0 + ADDL $-1, R0 + RTS diff --git a/sys/src/libc/68000/strcmp.s b/sys/src/libc/68000/strcmp.s new file mode 100755 index 000000000..c6072efd7 --- /dev/null +++ b/sys/src/libc/68000/strcmp.s @@ -0,0 +1,20 @@ + TEXT strcmp(SB), $0 + MOVL s1+0(FP), A2 + MOVL s2+4(FP), A1 + +l1: MOVB (A1)+, R0 + BEQ end + CMPB R0, (A2)+ + BEQ l1 + + BCS gtr + MOVL $-1, R0 + RTS + +gtr: MOVL $1, R0 + RTS + +end: TSTB (A2) + BNE gtr + CLRL R0 + RTS diff --git a/sys/src/libc/68000/strcpy.s b/sys/src/libc/68000/strcpy.s new file mode 100755 index 000000000..ce5c30bdb --- /dev/null +++ b/sys/src/libc/68000/strcpy.s @@ -0,0 +1,10 @@ + TEXT strcpy(SB), $0 + + MOVL s1+0(FP), A2 + MOVL s2+4(FP), A1 + +l1: MOVB (A1)+, (A2)+ + BNE l1 + + MOVL s1+0(FP), R0 + RTS diff --git a/sys/src/libc/68000/strlen.s b/sys/src/libc/68000/strlen.s new file mode 100755 index 000000000..4d787c704 --- /dev/null +++ b/sys/src/libc/68000/strlen.s @@ -0,0 +1,18 @@ + TEXT strlen(SB), $0 + MOVL s+0(FP), A1 + + TSTB (A1)+ + BEQ null + MOVL A1, A2 + +l1: + TSTB (A1)+ + BNE l1 + + SUBL A2, A1 + MOVL A1, R0 + RTS + +null: + MOVL $0, R0 + RTS diff --git a/sys/src/libc/68000/vlrt.c b/sys/src/libc/68000/vlrt.c new file mode 100755 index 000000000..071aa180d --- /dev/null +++ b/sys/src/libc/68000/vlrt.c @@ -0,0 +1,771 @@ +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef signed char schar; + +#define SIGN(n) (1UL<<(n-1)) + +typedef struct Vlong Vlong; +struct Vlong +{ + union + { + struct + { + ulong hi; + ulong lo; + }; + struct + { + ushort hims; + ushort hils; + ushort loms; + ushort lols; + }; + }; +}; + +void abort(void); + +void +_addv(Vlong *r, Vlong a, Vlong b) +{ + ulong lo, hi; + + lo = a.lo + b.lo; + hi = a.hi + b.hi; + if(lo < a.lo) + hi++; + r->lo = lo; + r->hi = hi; +} + +void +_subv(Vlong *r, Vlong a, Vlong b) +{ + ulong lo, hi; + + lo = a.lo - b.lo; + hi = a.hi - b.hi; + if(lo > a.lo) + hi--; + r->lo = lo; + r->hi = hi; +} + +void +_d2v(Vlong *y, double d) +{ + union { double d; struct Vlong; } x; + ulong xhi, xlo, ylo, yhi; + int sh; + + x.d = d; + + xhi = (x.hi & 0xfffff) | 0x100000; + xlo = x.lo; + sh = 1075 - ((x.hi >> 20) & 0x7ff); + + ylo = 0; + yhi = 0; + if(sh >= 0) { + /* v = (hi||lo) >> sh */ + if(sh < 32) { + if(sh == 0) { + ylo = xlo; + yhi = xhi; + } else { + ylo = (xlo >> sh) | (xhi << (32-sh)); + yhi = xhi >> sh; + } + } else { + if(sh == 32) { + ylo = xhi; + } else + if(sh < 64) { + ylo = xhi >> (sh-32); + } + } + } else { + /* v = (hi||lo) << -sh */ + sh = -sh; + if(sh <= 10) { + ylo = xlo << sh; + yhi = (xhi << sh) | (xlo >> (32-sh)); + } else { + /* overflow */ + yhi = d; /* causes something awful */ + } + } + if(x.hi & SIGN(32)) { + if(ylo != 0) { + ylo = -ylo; + yhi = ~yhi; + } else + yhi = -yhi; + } + + y->hi = yhi; + y->lo = ylo; +} + +void +_f2v(Vlong *y, float f) +{ + + _d2v(y, f); +} + +double +_v2d(Vlong x) +{ + if(x.hi & SIGN(32)) { + if(x.lo) { + x.lo = -x.lo; + x.hi = ~x.hi; + } else + x.hi = -x.hi; + return -((long)x.hi*4294967296. + x.lo); + } + return (long)x.hi*4294967296. + x.lo; +} + +float +_v2f(Vlong x) +{ + return _v2d(x); +} + +static void +dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) +{ + ulong numlo, numhi, denhi, denlo, quohi, quolo, t; + int i; + + numhi = num.hi; + numlo = num.lo; + denhi = den.hi; + denlo = den.lo; + + /* + * get a divide by zero + */ + if(denlo==0 && denhi==0) { + numlo = numlo / denlo; + } + + /* + * set up the divisor and find the number of iterations needed + */ + if(numhi >= SIGN(32)) { + quohi = SIGN(32); + quolo = 0; + } else { + quohi = numhi; + quolo = numlo; + } + i = 0; + while(denhi < quohi || (denhi == quohi && denlo < quolo)) { + denhi = (denhi<<1) | (denlo>>31); + denlo <<= 1; + i++; + } + + quohi = 0; + quolo = 0; + for(; i >= 0; i--) { + quohi = (quohi<<1) | (quolo>>31); + quolo <<= 1; + if(numhi > denhi || (numhi == denhi && numlo >= denlo)) { + t = numlo; + numlo -= denlo; + if(numlo > t) + numhi--; + numhi -= denhi; + quolo |= 1; + } + denlo = (denlo>>1) | (denhi<<31); + denhi >>= 1; + } + + if(q) { + q->lo = quolo; + q->hi = quohi; + } + if(r) { + r->lo = numlo; + r->hi = numhi; + } +} + +void +_divvu(Vlong *q, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + q->hi = 0; + q->lo = n.lo / d.lo; + return; + } + dodiv(n, d, q, 0); +} + +void +_modvu(Vlong *r, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + r->hi = 0; + r->lo = n.lo % d.lo; + return; + } + dodiv(n, d, 0, r); +} + +static void +vneg(Vlong *v) +{ + + if(v->lo == 0) { + v->hi = -v->hi; + return; + } + v->lo = -v->lo; + v->hi = ~v->hi; +} + +void +_divv(Vlong *q, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + q->lo = (long)n.lo / (long)d.lo; + q->hi = ((long)q->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, q, 0); + if(nneg != dneg) + vneg(q); +} + +void +_modv(Vlong *r, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + r->lo = (long)n.lo % (long)d.lo; + r->hi = ((long)r->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, 0, r); + if(nneg) + vneg(r); +} + +void +_rshav(Vlong *r, Vlong a, int b) +{ + long t; + + t = a.hi; + if(b >= 32) { + r->hi = t>>31; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = t>>31; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_rshlv(Vlong *r, Vlong a, int b) +{ + ulong t; + + t = a.hi; + if(b >= 32) { + r->hi = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = 0; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_lshv(Vlong *r, Vlong a, int b) +{ + ulong t; + + t = a.lo; + if(b >= 32) { + r->lo = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->hi = 0; + return; + } + r->hi = t << (b-32); + return; + } + if(b <= 0) { + r->lo = t; + r->hi = a.hi; + return; + } + r->lo = t << b; + r->hi = (t >> (32-b)) | (a.hi << b); +} + +void +_andv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi & b.hi; + r->lo = a.lo & b.lo; +} + +void +_orv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi | b.hi; + r->lo = a.lo | b.lo; +} + +void +_xorv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi ^ b.hi; + r->lo = a.lo ^ b.lo; +} + +void +_negv(Vlong *r, Vlong a) +{ + if(a.lo == 0) { + r->hi = -a.hi; + r->lo = 0; + return; + } + r->hi = ~a.hi; + r->lo = -a.lo; +} + +void +_vpp(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + r->lo++; + if(r->lo == 0) + r->hi++; +} + +void +_vmm(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + if(r->lo == 0) + r->hi--; + r->lo--; +} + +void +_ppv(Vlong *l, Vlong *r) +{ + + r->lo++; + if(r->lo == 0) + r->hi++; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_mmv(Vlong *l, Vlong *r) +{ + + if(r->lo == 0) + r->hi--; + r->lo--; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) +{ + Vlong t, u; + + u = *ret; + switch(type) { + default: + abort(); + break; + + case 1: /* schar */ + t.lo = *(schar*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(schar*)lv = u.lo; + break; + + case 2: /* uchar */ + t.lo = *(uchar*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uchar*)lv = u.lo; + break; + + case 3: /* short */ + t.lo = *(short*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(short*)lv = u.lo; + break; + + case 4: /* ushort */ + t.lo = *(ushort*)lv; + t.hi = 0; + fn(&u, t, rv); + *(ushort*)lv = u.lo; + break; + + case 9: /* int */ + t.lo = *(int*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(int*)lv = u.lo; + break; + + case 10: /* uint */ + t.lo = *(uint*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uint*)lv = u.lo; + break; + + case 5: /* long */ + t.lo = *(long*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(long*)lv = u.lo; + break; + + case 6: /* ulong */ + t.lo = *(ulong*)lv; + t.hi = 0; + fn(&u, t, rv); + *(ulong*)lv = u.lo; + break; + + case 7: /* vlong */ + case 8: /* uvlong */ + fn(&u, *(Vlong*)lv, rv); + *(Vlong*)lv = u; + break; + } + *ret = u; +} + +void +_p2v(Vlong *ret, void *p) +{ + long t; + + t = (ulong)p; + ret->lo = t; + ret->hi = 0; +} + +void +_sl2v(Vlong *ret, long sl) +{ + long t; + + t = sl; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ul2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul; + ret->lo = t; + ret->hi = 0; +} + +void +_si2v(Vlong *ret, int si) +{ + long t; + + t = si; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ui2v(Vlong *ret, uint ui) +{ + long t; + + t = ui; + ret->lo = t; + ret->hi = 0; +} + +void +_sh2v(Vlong *ret, long sh) +{ + long t; + + t = (sh << 16) >> 16; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uh2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul & 0xffff; + ret->lo = t; + ret->hi = 0; +} + +void +_sc2v(Vlong *ret, long uc) +{ + long t; + + t = (uc << 24) >> 24; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uc2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul & 0xff; + ret->lo = t; + ret->hi = 0; +} + +long +_v2sc(Vlong rv) +{ + long t; + + t = rv.lo & 0xff; + return (t << 24) >> 24; +} + +long +_v2uc(Vlong rv) +{ + + return rv.lo & 0xff; +} + +long +_v2sh(Vlong rv) +{ + long t; + + t = rv.lo & 0xffff; + return (t << 16) >> 16; +} + +long +_v2uh(Vlong rv) +{ + + return rv.lo & 0xffff; +} + +long +_v2sl(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ul(Vlong rv) +{ + + return rv.lo; +} + +long +_v2si(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ui(Vlong rv) +{ + + return rv.lo; +} + +int +_testv(Vlong rv) +{ + return rv.lo || rv.hi; +} + +int +_eqv(Vlong lv, Vlong rv) +{ + return lv.lo == rv.lo && lv.hi == rv.hi; +} + +int +_nev(Vlong lv, Vlong rv) +{ + return lv.lo != rv.lo || lv.hi != rv.hi; +} + +int +_ltv(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lev(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_gtv(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_gev(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} + +int +_lov(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lsv(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_hiv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_hsv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} + +void +_mulv(Vlong *r, Vlong a, Vlong b) +{ + ulong ahi, alo, chi, clo, x; + int i; + + ahi = a.hi; + alo = a.lo; + chi = 0; + clo = 0; + + x = b.lo; + for(i=0; i<32; i++) { + if(x & 1) { + chi += ahi; + clo += alo; + if(clo < alo) + chi++; + } + ahi <<= 1; + if(alo & SIGN(32)) + ahi += 1; + alo <<= 1; + x >>= 1; + } + + /* + * same, but + * alo is known to be 0 + * can stop when x == 0 + */ + for(x=b.hi; x; x>>=1) { + if(x & 1) + chi += ahi; + ahi <<= 1; + } + + r->hi = chi; + r->lo = clo; +} diff --git a/sys/src/libc/68020/68881/acos.s b/sys/src/libc/68020/68881/acos.s new file mode 100755 index 000000000..94c995c1f --- /dev/null +++ b/sys/src/libc/68020/68881/acos.s @@ -0,0 +1,3 @@ + TEXT acos(SB),$0 + FACOSD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/asin.s b/sys/src/libc/68020/68881/asin.s new file mode 100755 index 000000000..068c4ce2e --- /dev/null +++ b/sys/src/libc/68020/68881/asin.s @@ -0,0 +1,3 @@ + TEXT asin(SB),$0 + FASIND a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/atan.s b/sys/src/libc/68020/68881/atan.s new file mode 100755 index 000000000..33f7bd8a4 --- /dev/null +++ b/sys/src/libc/68020/68881/atan.s @@ -0,0 +1,3 @@ + TEXT atan(SB),$0 + FATAND a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/cos.s b/sys/src/libc/68020/68881/cos.s new file mode 100755 index 000000000..faacddf30 --- /dev/null +++ b/sys/src/libc/68020/68881/cos.s @@ -0,0 +1,3 @@ + TEXT cos(SB),$0 + FCOSD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/cosh.s b/sys/src/libc/68020/68881/cosh.s new file mode 100755 index 000000000..5269184ec --- /dev/null +++ b/sys/src/libc/68020/68881/cosh.s @@ -0,0 +1,3 @@ + TEXT cosh(SB),$0 + FCOSHD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/exp.s b/sys/src/libc/68020/68881/exp.s new file mode 100755 index 000000000..530334413 --- /dev/null +++ b/sys/src/libc/68020/68881/exp.s @@ -0,0 +1,3 @@ + TEXT exp(SB),$0 + FETOXD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/fabs.s b/sys/src/libc/68020/68881/fabs.s new file mode 100755 index 000000000..e29620f25 --- /dev/null +++ b/sys/src/libc/68020/68881/fabs.s @@ -0,0 +1,3 @@ + TEXT fabs(SB),$0 + FABSD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/log.s b/sys/src/libc/68020/68881/log.s new file mode 100755 index 000000000..3e39372da --- /dev/null +++ b/sys/src/libc/68020/68881/log.s @@ -0,0 +1,3 @@ + TEXT log(SB),$0 + FLOGND a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/log10.s b/sys/src/libc/68020/68881/log10.s new file mode 100755 index 000000000..92ec78005 --- /dev/null +++ b/sys/src/libc/68020/68881/log10.s @@ -0,0 +1,3 @@ + TEXT log10(SB),$0 + FLOG10D a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/mkfile b/sys/src/libc/68020/68881/mkfile new file mode 100755 index 000000000..08ce52c0a --- /dev/null +++ b/sys/src/libc/68020/68881/mkfile @@ -0,0 +1,31 @@ +objtype=68020 +</68020/mkfile +CFLAGS=-I/sys/ninclude $CFLAGS + +LIB=/$objtype/lib/lib68881.a +SFILES=\ + acos.s\ + asin.s\ + atan.s\ + cos.s\ + cosh.s\ + exp.s\ + fabs.s\ + log.s\ + log10.s\ + pow10.s\ + sin.s\ + sinh.s\ + sqrt.s\ + tan.s\ + tanh.s\ + +OFILES=${SFILES:%.s=%.$O} + +UPDATE=mkfile\ + $SFILES\ + +</sys/src/cmd/mksyslib + +installall:V: + mk install diff --git a/sys/src/libc/68020/68881/pow10.s b/sys/src/libc/68020/68881/pow10.s new file mode 100755 index 000000000..cdb83ec51 --- /dev/null +++ b/sys/src/libc/68020/68881/pow10.s @@ -0,0 +1,3 @@ + TEXT pow10(SB),$0 + FTENTOXL n+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/sin.s b/sys/src/libc/68020/68881/sin.s new file mode 100755 index 000000000..568fab952 --- /dev/null +++ b/sys/src/libc/68020/68881/sin.s @@ -0,0 +1,3 @@ + TEXT sin(SB),$0 + FSIND a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/sinh.s b/sys/src/libc/68020/68881/sinh.s new file mode 100755 index 000000000..b05186374 --- /dev/null +++ b/sys/src/libc/68020/68881/sinh.s @@ -0,0 +1,3 @@ + TEXT sinh(SB),$0 + FSINHD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/sqrt.s b/sys/src/libc/68020/68881/sqrt.s new file mode 100755 index 000000000..5109bc255 --- /dev/null +++ b/sys/src/libc/68020/68881/sqrt.s @@ -0,0 +1,3 @@ + TEXT sqrt(SB),$0 + FSQRTD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/tan.s b/sys/src/libc/68020/68881/tan.s new file mode 100755 index 000000000..9cedef2e4 --- /dev/null +++ b/sys/src/libc/68020/68881/tan.s @@ -0,0 +1,3 @@ + TEXT tan(SB),$0 + FTAND a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/68881/tanh.s b/sys/src/libc/68020/68881/tanh.s new file mode 100755 index 000000000..2f4e42728 --- /dev/null +++ b/sys/src/libc/68020/68881/tanh.s @@ -0,0 +1,3 @@ + TEXT tanh(SB),$0 + FTANHD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/argv0.s b/sys/src/libc/68020/argv0.s new file mode 100755 index 000000000..8d9f9b29b --- /dev/null +++ b/sys/src/libc/68020/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/68020/getcallerpc.s b/sys/src/libc/68020/getcallerpc.s new file mode 100755 index 000000000..78f2f9db9 --- /dev/null +++ b/sys/src/libc/68020/getcallerpc.s @@ -0,0 +1,3 @@ +TEXT getcallerpc(SB), $0 + MOVL (a+0(FP)), R0 + RTS diff --git a/sys/src/libc/68020/getfcr.s b/sys/src/libc/68020/getfcr.s new file mode 100755 index 000000000..7f67d038f --- /dev/null +++ b/sys/src/libc/68020/getfcr.s @@ -0,0 +1,19 @@ +TEXT getfsr(SB), $0 + MOVL $0, R0 + MOVL FPSR, R0 + RTS + +TEXT setfsr(SB), $0 + MOVL new+0(FP), R1 + MOVL R1, FPSR + RTS + +TEXT getfcr(SB), $0 + MOVL $0, R0 + MOVL FPCR, R0 + RTS + +TEXT setfcr(SB), $0 + MOVL new+0(FP), R1 + MOVL R1, FPCR + RTS diff --git a/sys/src/libc/68020/main9.s b/sys/src/libc/68020/main9.s new file mode 100755 index 000000000..38ed7322f --- /dev/null +++ b/sys/src/libc/68020/main9.s @@ -0,0 +1,19 @@ +#define NPRIVATES 16 + +TEXT _main(SB), 1, $(16 + NPRIVATES*4) + MOVL $a6base(SB), A6 + MOVL R0, _tos(SB) + LEA p-64(SP),A0 + MOVL A0,_privates+0(SB) + MOVL $16,R0 + MOVL R0,_nprivates+0(SB) + PEA inargv+0(FP) + MOVL inargc-4(FP), TOS + BSR main(SB) + MOVL $_exits<>+0(SB), R0 + MOVL R0,TOS + BSR exits(SB) + RTS + +DATA _exits<>+0(SB)/4, $"main" +GLOBL _exits<>+0(SB), $5 diff --git a/sys/src/libc/68020/main9p.s b/sys/src/libc/68020/main9p.s new file mode 100755 index 000000000..6c64f6404 --- /dev/null +++ b/sys/src/libc/68020/main9p.s @@ -0,0 +1,32 @@ +#define NPRIVATES 16 + +TEXT _mainp(SB), 1, $(16 + NPRIVATES*4) + MOVL $a6base(SB), A6 + MOVL R0, _tos(SB) /* return value of sys exec!! */ + LEA p-64(SP),A0 + MOVL A0,_privates+0(SB) + MOVL $16,R0 + MOVL R0,_nprivates+0(SB) + BSR _profmain(SB) + MOVL __prof+4(SB), __prof+0(SB) + PEA inargv+0(FP) + MOVL inargc-4(FP), TOS + BSR main(SB) + +loop: + MOVL $_exits<>+0(SB), R0 + MOVL R0,TOS + BSR exits(SB) + LEA _profin(SB), A0 /* force loading of profile */ + BRA loop + +TEXT _savearg(SB), 1, $0 + RTS + +TEXT _callpc(SB), 1, $0 + MOVL argp+0(FP), A0 + MOVL 4(A0), R0 + RTS + +DATA _exits<>+0(SB)/4, $"main" +GLOBL _exits<>+0(SB), $5 diff --git a/sys/src/libc/68020/memccpy.s b/sys/src/libc/68020/memccpy.s new file mode 100755 index 000000000..3e494e915 --- /dev/null +++ b/sys/src/libc/68020/memccpy.s @@ -0,0 +1,30 @@ + TEXT memccpy(SB),$0 + MOVL n+12(FP),R0 + BEQ ret + MOVL s1+0(FP),A2 + MOVL s2+4(FP),A1 + MOVL c+8(FP),R1 + BEQ l2 + +/* + * general case + */ +l1: MOVB (A1)+,R2 + MOVB R2,(A2)+ + CMPB R2,R1 + BEQ eq + SUBL $1,R0 + BNE l1 + RTS + +/* + * special case for null character + */ +l2: MOVB (A1)+,(A2)+ + BEQ eq + SUBL $1,R0 + BNE l2 + RTS + +eq: MOVL A2,R0 +ret: RTS diff --git a/sys/src/libc/68020/memchr.s b/sys/src/libc/68020/memchr.s new file mode 100755 index 000000000..ea2584df8 --- /dev/null +++ b/sys/src/libc/68020/memchr.s @@ -0,0 +1,15 @@ + TEXT memchr(SB),$0 + MOVL n+8(FP),R0 + BEQ ret + MOVL s1+0(FP),A1 + MOVL c+4(FP),R1 + +l1: CMPB R1,(A1)+ + BEQ eq + SUBL $1,R0 + BNE l1 + RTS + +eq: MOVL A1,R0 + SUBL $1,R0 +ret: RTS diff --git a/sys/src/libc/68020/memcmp.s b/sys/src/libc/68020/memcmp.s new file mode 100755 index 000000000..97d208e3b --- /dev/null +++ b/sys/src/libc/68020/memcmp.s @@ -0,0 +1,18 @@ + TEXT memcmp(SB),$0 + MOVL n+8(FP),R0 + BEQ ret + MOVL s1+0(FP),A2 + MOVL s2+4(FP),A1 + +l1: CMPB (A1)+,(A2)+ + BNE neq + SUBL $1,R0 + BNE l1 + RTS + +neq: BCS gtr + MOVL $-1,R0 + RTS + +gtr: MOVL $1,R0 +ret: RTS diff --git a/sys/src/libc/68020/memcpy.s b/sys/src/libc/68020/memcpy.s new file mode 100755 index 000000000..2a37573da --- /dev/null +++ b/sys/src/libc/68020/memcpy.s @@ -0,0 +1,98 @@ + TEXT memcpy(SB), $0 + + MOVL n+8(FP),R0 + BEQ return + BGT ok + MOVL 0, R0 +ok: + MOVL s1+0(FP),A2 + MOVL s2+4(FP),A1 + + CMPL A2,A1 + BHI back + +/* + * speed depends on source allignment + * destination allignment is secondary + * byte-at-a-time foreward copy to + * get source (A1) alligned. + */ +f1: + MOVL A1, R1 + ANDL $3, R1 + BEQ f2 + SUBL $1, R0 + BLT return + MOVB (A1)+, (A2)+ + BRA f1 +/* + * quad-long-at-a-time forward copy + */ +f2: + SUBL $16, R0 + BLT f3 + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + BRA f2 + +/* + * cleanup byte-at-a-time + */ +f3: + ADDL $15, R0 + BLT return +f4: + MOVB (A1)+, (A2)+ + SUBL $1, R0 + BGE f4 + BRA return + +return: + MOVL s1+0(FP),R0 + RTS + +/* + * everything the same, but + * copy backwards + */ +back: + ADDL R0, A1 + ADDL R0, A2 + +/* + * byte-at-a-time backward copy to + * get source (A1) alligned. + */ +b1: + MOVL A1, R1 + ANDL $3, R1 + BEQ b2 + SUBL $1, R0 + BLT return + MOVB -(A1), -(A2) + BRA b1 +/* + * quad-long-at-a-time backward copy + */ +b2: + SUBL $16, R0 + BLT b3 + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + BRA b2 + +/* + * cleanup byte-at-a-time backward + */ +b3: + ADDL $15, R0 + BLT return +b4: + MOVB -(A1), -(A2) + SUBL $1, R0 + BGE b4 + BRA return diff --git a/sys/src/libc/68020/memmove.s b/sys/src/libc/68020/memmove.s new file mode 100755 index 000000000..482b3d690 --- /dev/null +++ b/sys/src/libc/68020/memmove.s @@ -0,0 +1,99 @@ + TEXT memmove(SB), $0 +move: + + MOVL n+8(FP),R0 + BEQ return + BGT ok + MOVL 0, R0 +ok: + MOVL s1+0(FP),A2 + MOVL s2+4(FP),A1 + + CMPL A2,A1 + BHI back + +/* + * speed depends on source allignment + * destination allignment is secondary + * byte-at-a-time foreward copy to + * get source (A1) alligned. + */ +f1: + MOVL A1, R1 + ANDL $3, R1 + BEQ f2 + SUBL $1, R0 + BLT return + MOVB (A1)+, (A2)+ + BRA f1 +/* + * quad-long-at-a-time forward copy + */ +f2: + SUBL $16, R0 + BLT f3 + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + MOVL (A1)+, (A2)+ + BRA f2 + +/* + * cleanup byte-at-a-time + */ +f3: + ADDL $15, R0 + BLT return +f4: + MOVB (A1)+, (A2)+ + SUBL $1, R0 + BGE f4 + BRA return + +return: + MOVL s1+0(FP),R0 + RTS + +/* + * everything the same, but + * copy backwards + */ +back: + ADDL R0, A1 + ADDL R0, A2 + +/* + * byte-at-a-time backward copy to + * get source (A1) alligned. + */ +b1: + MOVL A1, R1 + ANDL $3, R1 + BEQ b2 + SUBL $1, R0 + BLT return + MOVB -(A1), -(A2) + BRA b1 +/* + * quad-long-at-a-time backward copy + */ +b2: + SUBL $16, R0 + BLT b3 + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + MOVL -(A1), -(A2) + BRA b2 + +/* + * cleanup byte-at-a-time backward + */ +b3: + ADDL $15, R0 + BLT return +b4: + MOVB -(A1), -(A2) + SUBL $1, R0 + BGE b4 + BRA return diff --git a/sys/src/libc/68020/memset.s b/sys/src/libc/68020/memset.s new file mode 100755 index 000000000..d4b773416 --- /dev/null +++ b/sys/src/libc/68020/memset.s @@ -0,0 +1,47 @@ + TEXT memset(SB), $0 + MOVL n+8(FP), R0 + BLE return + MOVL s1+0(FP), A1 + CLRL R1 + MOVB c+7(FP), R1 + BEQ l1 + +/* + * create 4 replicated copies + * of the byte in R1 + */ + MOVL R1, R2 + ASLL $8, R2 + ORL R2, R1 + MOVL R1, R2 + SWAP R2 + ORL R2, R1 + +/* + * quad-long-at-a-time set + * destination allignment is not + * very important. + */ +l1: + SUBL $16, R0 + BLT l2 + MOVL R1, (A1)+ + MOVL R1, (A1)+ + MOVL R1, (A1)+ + MOVL R1, (A1)+ + BRA l1 + +/* + * cleanup byte-at-a-time + */ +l2: + ADDL $15, R0 + BLT return +l3: + MOVB R1, (A1)+ + SUBL $1, R0 + BGE l3 + +return: + MOVL s1+0(FP),R0 + RTS diff --git a/sys/src/libc/68020/mkfile b/sys/src/libc/68020/mkfile new file mode 100755 index 000000000..bdd359164 --- /dev/null +++ b/sys/src/libc/68020/mkfile @@ -0,0 +1,53 @@ +objtype=68020 +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +SFILES=\ + argv0.s\ + getcallerpc.$O\ + getfcr.s\ + main9.s\ + main9p.s\ + memccpy.s\ + memchr.s\ + memcmp.s\ + memcpy.s\ + memmove.s\ + memset.s\ + scale.s\ + setjmp.s\ + sqrt.s\ + strcat.s\ + strchr.s\ + strcmp.s\ + strcpy.s\ + strlen.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 + +install:V: install.68881 +installall:V: + mk install +clean:V: clean.68881 +nuke:V: clean.68881 +update:V: update.68881 + +%.68881:V: + cd 68881 + mk $stem diff --git a/sys/src/libc/68020/notejmp.c b/sys/src/libc/68020/notejmp.c new file mode 100755 index 000000000..61562d441 --- /dev/null +++ b/sys/src/libc/68020/notejmp.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> +#define UREGVARSZ 4 /* not right but doesn't matter */ +#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->usp = j[JMPBUFSP] + 4; + noted(NCONT); +} diff --git a/sys/src/libc/68020/scale.s b/sys/src/libc/68020/scale.s new file mode 100755 index 000000000..0e0e50a86 --- /dev/null +++ b/sys/src/libc/68020/scale.s @@ -0,0 +1,4 @@ + TEXT fscale(SB), $0 + FMOVED a+0(FP), F0 + FSCALEL x+8(FP), F0 + RTS diff --git a/sys/src/libc/68020/setjmp.s b/sys/src/libc/68020/setjmp.s new file mode 100755 index 000000000..827b71fc1 --- /dev/null +++ b/sys/src/libc/68020/setjmp.s @@ -0,0 +1,15 @@ +TEXT setjmp(SB), 1, $0 + MOVL b+0(FP), A0 + MOVL A7, (A0)+ + MOVL (A7), (A0) + CLRL R0 + RTS + +TEXT longjmp(SB), 1, $0 + MOVL b+0(FP), A0 + MOVL r+4(FP), R0 + BNE ok /* ansi: "longjmp(0) => longjmp(1)" */ + MOVL $1, R0 /* bless their pointed heads */ +ok: MOVL (A0)+, A7 + MOVL (A0), (A7) + RTS diff --git a/sys/src/libc/68020/sqrt.s b/sys/src/libc/68020/sqrt.s new file mode 100755 index 000000000..5109bc255 --- /dev/null +++ b/sys/src/libc/68020/sqrt.s @@ -0,0 +1,3 @@ + TEXT sqrt(SB),$0 + FSQRTD a+0(FP),F0 + RTS diff --git a/sys/src/libc/68020/strcat.s b/sys/src/libc/68020/strcat.s new file mode 100755 index 000000000..95821408b --- /dev/null +++ b/sys/src/libc/68020/strcat.s @@ -0,0 +1,15 @@ + TEXT strcat(SB), $0 + MOVL s1+0(FP), A2 + MOVL s2+4(FP), A1 + +l1: TSTB (A2)+ + BNE l1 + + MOVB (A1)+, -1(A2) + BEQ done + +l2: MOVB (A1)+, (A2)+ + BNE l2 + +done: MOVL s1+0(FP), R0 + RTS diff --git a/sys/src/libc/68020/strchr.s b/sys/src/libc/68020/strchr.s new file mode 100755 index 000000000..a5d4be2c6 --- /dev/null +++ b/sys/src/libc/68020/strchr.s @@ -0,0 +1,27 @@ + TEXT strchr(SB), $0 + + MOVL s+0(FP), A0 + MOVB c+7(FP), R2 + BEQ null + +l: + MOVB (A0)+, R1 + BEQ out + CMPB R1, R2 + BNE l + + MOVL A0, R0 + ADDL $-1, R0 + RTS + +out: + CLRL R0 + RTS + +null: + TSTB (A0)+ + BNE null + + MOVL A0, R0 + ADDL $-1, R0 + RTS diff --git a/sys/src/libc/68020/strcmp.s b/sys/src/libc/68020/strcmp.s new file mode 100755 index 000000000..c6072efd7 --- /dev/null +++ b/sys/src/libc/68020/strcmp.s @@ -0,0 +1,20 @@ + TEXT strcmp(SB), $0 + MOVL s1+0(FP), A2 + MOVL s2+4(FP), A1 + +l1: MOVB (A1)+, R0 + BEQ end + CMPB R0, (A2)+ + BEQ l1 + + BCS gtr + MOVL $-1, R0 + RTS + +gtr: MOVL $1, R0 + RTS + +end: TSTB (A2) + BNE gtr + CLRL R0 + RTS diff --git a/sys/src/libc/68020/strcpy.s b/sys/src/libc/68020/strcpy.s new file mode 100755 index 000000000..ce5c30bdb --- /dev/null +++ b/sys/src/libc/68020/strcpy.s @@ -0,0 +1,10 @@ + TEXT strcpy(SB), $0 + + MOVL s1+0(FP), A2 + MOVL s2+4(FP), A1 + +l1: MOVB (A1)+, (A2)+ + BNE l1 + + MOVL s1+0(FP), R0 + RTS diff --git a/sys/src/libc/68020/strlen.s b/sys/src/libc/68020/strlen.s new file mode 100755 index 000000000..4d787c704 --- /dev/null +++ b/sys/src/libc/68020/strlen.s @@ -0,0 +1,18 @@ + TEXT strlen(SB), $0 + MOVL s+0(FP), A1 + + TSTB (A1)+ + BEQ null + MOVL A1, A2 + +l1: + TSTB (A1)+ + BNE l1 + + SUBL A2, A1 + MOVL A1, R0 + RTS + +null: + MOVL $0, R0 + RTS diff --git a/sys/src/libc/68020/tas.s b/sys/src/libc/68020/tas.s new file mode 100755 index 000000000..769472f71 --- /dev/null +++ b/sys/src/libc/68020/tas.s @@ -0,0 +1,9 @@ +TEXT _tas(SB), $0 + + MOVL $0, R0 + MOVL a+0(FP), A0 + TAS (A0) + BEQ tas_1 + MOVL $1, R0 +tas_1: + RTS diff --git a/sys/src/libc/68020/vlop.s b/sys/src/libc/68020/vlop.s new file mode 100755 index 000000000..2f34fd645 --- /dev/null +++ b/sys/src/libc/68020/vlop.s @@ -0,0 +1,23 @@ +TEXT _mulv(SB), $0 + MOVL r+0(FP), A0 + MOVL a+8(FP), R0 + + WORD $0x4c2f + WORD $0x0401 + WORD $0x0014 +/* + * MULUL b+16(FP), R0:R1 + * philw made me do it! + */ + + MOVL a+4(FP), R2 + MULUL b+16(FP), R2 + ADDL R2, R1 + + MOVL a+8(FP), R2 + MULUL b+12(FP), R2 + ADDL R2, R1 + + MOVL R1, (A0)+ + MOVL R0, (A0) + RTS diff --git a/sys/src/libc/68020/vlrt.c b/sys/src/libc/68020/vlrt.c new file mode 100755 index 000000000..cfad2afc0 --- /dev/null +++ b/sys/src/libc/68020/vlrt.c @@ -0,0 +1,730 @@ +typedef unsigned long ulong; +typedef unsigned int uint; +typedef unsigned short ushort; +typedef unsigned char uchar; +typedef signed char schar; + +#define SIGN(n) (1UL<<(n-1)) + +typedef struct Vlong Vlong; +struct Vlong +{ + union + { + struct + { + ulong hi; + ulong lo; + }; + struct + { + ushort hims; + ushort hils; + ushort loms; + ushort lols; + }; + }; +}; + +void abort(void); + +void +_addv(Vlong *r, Vlong a, Vlong b) +{ + ulong lo, hi; + + lo = a.lo + b.lo; + hi = a.hi + b.hi; + if(lo < a.lo) + hi++; + r->lo = lo; + r->hi = hi; +} + +void +_subv(Vlong *r, Vlong a, Vlong b) +{ + ulong lo, hi; + + lo = a.lo - b.lo; + hi = a.hi - b.hi; + if(lo > a.lo) + hi--; + r->lo = lo; + r->hi = hi; +} + +void +_d2v(Vlong *y, double d) +{ + union { double d; struct Vlong; } x; + ulong xhi, xlo, ylo, yhi; + int sh; + + x.d = d; + + xhi = (x.hi & 0xfffff) | 0x100000; + xlo = x.lo; + sh = 1075 - ((x.hi >> 20) & 0x7ff); + + ylo = 0; + yhi = 0; + if(sh >= 0) { + /* v = (hi||lo) >> sh */ + if(sh < 32) { + if(sh == 0) { + ylo = xlo; + yhi = xhi; + } else { + ylo = (xlo >> sh) | (xhi << (32-sh)); + yhi = xhi >> sh; + } + } else { + if(sh == 32) { + ylo = xhi; + } else + if(sh < 64) { + ylo = xhi >> (sh-32); + } + } + } else { + /* v = (hi||lo) << -sh */ + sh = -sh; + if(sh <= 10) { + ylo = xlo << sh; + yhi = (xhi << sh) | (xlo >> (32-sh)); + } else { + /* overflow */ + yhi = d; /* causes something awful */ + } + } + if(x.hi & SIGN(32)) { + if(ylo != 0) { + ylo = -ylo; + yhi = ~yhi; + } else + yhi = -yhi; + } + + y->hi = yhi; + y->lo = ylo; +} + +void +_f2v(Vlong *y, float f) +{ + + _d2v(y, f); +} + +double +_v2d(Vlong x) +{ + if(x.hi & SIGN(32)) { + if(x.lo) { + x.lo = -x.lo; + x.hi = ~x.hi; + } else + x.hi = -x.hi; + return -((long)x.hi*4294967296. + x.lo); + } + return (long)x.hi*4294967296. + x.lo; +} + +float +_v2f(Vlong x) +{ + return _v2d(x); +} + +static void +dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) +{ + ulong numlo, numhi, denhi, denlo, quohi, quolo, t; + int i; + + numhi = num.hi; + numlo = num.lo; + denhi = den.hi; + denlo = den.lo; + + /* + * get a divide by zero + */ + if(denlo==0 && denhi==0) { + numlo = numlo / denlo; + } + + /* + * set up the divisor and find the number of iterations needed + */ + if(numhi >= SIGN(32)) { + quohi = SIGN(32); + quolo = 0; + } else { + quohi = numhi; + quolo = numlo; + } + i = 0; + while(denhi < quohi || (denhi == quohi && denlo < quolo)) { + denhi = (denhi<<1) | (denlo>>31); + denlo <<= 1; + i++; + } + + quohi = 0; + quolo = 0; + for(; i >= 0; i--) { + quohi = (quohi<<1) | (quolo>>31); + quolo <<= 1; + if(numhi > denhi || (numhi == denhi && numlo >= denlo)) { + t = numlo; + numlo -= denlo; + if(numlo > t) + numhi--; + numhi -= denhi; + quolo |= 1; + } + denlo = (denlo>>1) | (denhi<<31); + denhi >>= 1; + } + + if(q) { + q->lo = quolo; + q->hi = quohi; + } + if(r) { + r->lo = numlo; + r->hi = numhi; + } +} + +void +_divvu(Vlong *q, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + q->hi = 0; + q->lo = n.lo / d.lo; + return; + } + dodiv(n, d, q, 0); +} + +void +_modvu(Vlong *r, Vlong n, Vlong d) +{ + + if(n.hi == 0 && d.hi == 0) { + r->hi = 0; + r->lo = n.lo % d.lo; + return; + } + dodiv(n, d, 0, r); +} + +static void +vneg(Vlong *v) +{ + + if(v->lo == 0) { + v->hi = -v->hi; + return; + } + v->lo = -v->lo; + v->hi = ~v->hi; +} + +void +_divv(Vlong *q, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + q->lo = (long)n.lo / (long)d.lo; + q->hi = ((long)q->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, q, 0); + if(nneg != dneg) + vneg(q); +} + +void +_modv(Vlong *r, Vlong n, Vlong d) +{ + long nneg, dneg; + + if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { + r->lo = (long)n.lo % (long)d.lo; + r->hi = ((long)r->lo) >> 31; + return; + } + nneg = n.hi >> 31; + if(nneg) + vneg(&n); + dneg = d.hi >> 31; + if(dneg) + vneg(&d); + dodiv(n, d, 0, r); + if(nneg) + vneg(r); +} + +void +_rshav(Vlong *r, Vlong a, int b) +{ + long t; + + t = a.hi; + if(b >= 32) { + r->hi = t>>31; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = t>>31; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_rshlv(Vlong *r, Vlong a, int b) +{ + ulong t; + + t = a.hi; + if(b >= 32) { + r->hi = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->lo = 0; + return; + } + r->lo = t >> (b-32); + return; + } + if(b <= 0) { + r->hi = t; + r->lo = a.lo; + return; + } + r->hi = t >> b; + r->lo = (t << (32-b)) | (a.lo >> b); +} + +void +_lshv(Vlong *r, Vlong a, int b) +{ + ulong t; + + t = a.lo; + if(b >= 32) { + r->lo = 0; + if(b >= 64) { + /* this is illegal re C standard */ + r->hi = 0; + return; + } + r->hi = t << (b-32); + return; + } + if(b <= 0) { + r->lo = t; + r->hi = a.hi; + return; + } + r->lo = t << b; + r->hi = (t >> (32-b)) | (a.hi << b); +} + +void +_andv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi & b.hi; + r->lo = a.lo & b.lo; +} + +void +_orv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi | b.hi; + r->lo = a.lo | b.lo; +} + +void +_xorv(Vlong *r, Vlong a, Vlong b) +{ + r->hi = a.hi ^ b.hi; + r->lo = a.lo ^ b.lo; +} + +void +_negv(Vlong *r, Vlong a) +{ + if(a.lo == 0) { + r->hi = -a.hi; + r->lo = 0; + return; + } + r->hi = ~a.hi; + r->lo = -a.lo; +} + +void +_vpp(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + r->lo++; + if(r->lo == 0) + r->hi++; +} + +void +_vmm(Vlong *l, Vlong *r) +{ + + l->hi = r->hi; + l->lo = r->lo; + if(r->lo == 0) + r->hi--; + r->lo--; +} + +void +_ppv(Vlong *l, Vlong *r) +{ + + r->lo++; + if(r->lo == 0) + r->hi++; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_mmv(Vlong *l, Vlong *r) +{ + + if(r->lo == 0) + r->hi--; + r->lo--; + l->hi = r->hi; + l->lo = r->lo; +} + +void +_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv) +{ + Vlong t, u; + + u = *ret; + switch(type) { + default: + abort(); + break; + + case 1: /* schar */ + t.lo = *(schar*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(schar*)lv = u.lo; + break; + + case 2: /* uchar */ + t.lo = *(uchar*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uchar*)lv = u.lo; + break; + + case 3: /* short */ + t.lo = *(short*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(short*)lv = u.lo; + break; + + case 4: /* ushort */ + t.lo = *(ushort*)lv; + t.hi = 0; + fn(&u, t, rv); + *(ushort*)lv = u.lo; + break; + + case 9: /* int */ + t.lo = *(int*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(int*)lv = u.lo; + break; + + case 10: /* uint */ + t.lo = *(uint*)lv; + t.hi = 0; + fn(&u, t, rv); + *(uint*)lv = u.lo; + break; + + case 5: /* long */ + t.lo = *(long*)lv; + t.hi = t.lo >> 31; + fn(&u, t, rv); + *(long*)lv = u.lo; + break; + + case 6: /* ulong */ + t.lo = *(ulong*)lv; + t.hi = 0; + fn(&u, t, rv); + *(ulong*)lv = u.lo; + break; + + case 7: /* vlong */ + case 8: /* uvlong */ + fn(&u, *(Vlong*)lv, rv); + *(Vlong*)lv = u; + break; + } + *ret = u; +} + +void +_p2v(Vlong *ret, void *p) +{ + long t; + + t = (ulong)p; + ret->lo = t; + ret->hi = 0; +} + +void +_sl2v(Vlong *ret, long sl) +{ + long t; + + t = sl; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ul2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul; + ret->lo = t; + ret->hi = 0; +} + +void +_si2v(Vlong *ret, int si) +{ + long t; + + t = si; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_ui2v(Vlong *ret, uint ui) +{ + long t; + + t = ui; + ret->lo = t; + ret->hi = 0; +} + +void +_sh2v(Vlong *ret, long sh) +{ + long t; + + t = (sh << 16) >> 16; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uh2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul & 0xffff; + ret->lo = t; + ret->hi = 0; +} + +void +_sc2v(Vlong *ret, long uc) +{ + long t; + + t = (uc << 24) >> 24; + ret->lo = t; + ret->hi = t >> 31; +} + +void +_uc2v(Vlong *ret, ulong ul) +{ + long t; + + t = ul & 0xff; + ret->lo = t; + ret->hi = 0; +} + +long +_v2sc(Vlong rv) +{ + long t; + + t = rv.lo & 0xff; + return (t << 24) >> 24; +} + +long +_v2uc(Vlong rv) +{ + + return rv.lo & 0xff; +} + +long +_v2sh(Vlong rv) +{ + long t; + + t = rv.lo & 0xffff; + return (t << 16) >> 16; +} + +long +_v2uh(Vlong rv) +{ + + return rv.lo & 0xffff; +} + +long +_v2sl(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ul(Vlong rv) +{ + + return rv.lo; +} + +long +_v2si(Vlong rv) +{ + + return rv.lo; +} + +long +_v2ui(Vlong rv) +{ + + return rv.lo; +} + +int +_testv(Vlong rv) +{ + return rv.lo || rv.hi; +} + +int +_eqv(Vlong lv, Vlong rv) +{ + return lv.lo == rv.lo && lv.hi == rv.hi; +} + +int +_nev(Vlong lv, Vlong rv) +{ + return lv.lo != rv.lo || lv.hi != rv.hi; +} + +int +_ltv(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lev(Vlong lv, Vlong rv) +{ + return (long)lv.hi < (long)rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_gtv(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_gev(Vlong lv, Vlong rv) +{ + return (long)lv.hi > (long)rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} + +int +_lov(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo < rv.lo); +} + +int +_lsv(Vlong lv, Vlong rv) +{ + return lv.hi < rv.hi || + (lv.hi == rv.hi && lv.lo <= rv.lo); +} + +int +_hiv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo > rv.lo); +} + +int +_hsv(Vlong lv, Vlong rv) +{ + return lv.hi > rv.hi || + (lv.hi == rv.hi && lv.lo >= rv.lo); +} diff --git a/sys/src/libc/9sys/abort.c b/sys/src/libc/9sys/abort.c new file mode 100755 index 000000000..b0fd74cd5 --- /dev/null +++ b/sys/src/libc/9sys/abort.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> +void +abort(void) +{ + while(*(int*)0) + ; +} diff --git a/sys/src/libc/9sys/access.c b/sys/src/libc/9sys/access.c new file mode 100755 index 000000000..c9fee3432 --- /dev/null +++ b/sys/src/libc/9sys/access.c @@ -0,0 +1,33 @@ +#include <u.h> +#include <libc.h> + +int +access(char *name, int mode) +{ + int fd; + Dir *db; + static char omode[] = { + 0, + OEXEC, + OWRITE, + ORDWR, + OREAD, + OEXEC, /* only approximate */ + ORDWR, + ORDWR /* only approximate */ + }; + + if(mode == AEXIST){ + db = dirstat(name); + free(db); + if(db != nil) + return 0; + return -1; + } + fd = open(name, omode[mode&7]); + if(fd >= 0){ + close(fd); + return 0; + } + return -1; +} diff --git a/sys/src/libc/9sys/announce.c b/sys/src/libc/9sys/announce.c new file mode 100755 index 000000000..b2252ed21 --- /dev/null +++ b/sys/src/libc/9sys/announce.c @@ -0,0 +1,274 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +static int nettrans(char*, char*, int na, char*, int); + +enum +{ + Maxpath= 256, +}; + +/* + * announce a network service. + */ +int +announce(char *addr, char *dir) +{ + int ctl, n, m; + char buf[Maxpath]; + char buf2[Maxpath]; + char netdir[Maxpath]; + char naddr[Maxpath]; + char *cp; + + /* + * translate the address + */ + if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0) + return -1; + + /* + * get a control channel + */ + ctl = open(netdir, ORDWR); + if(ctl<0){ + werrstr("announce opening %s: %r", netdir); + return -1; + } + cp = strrchr(netdir, '/'); + if(cp == nil){ + werrstr("announce arg format %s", netdir); + close(ctl); + return -1; + } + *cp = 0; + + /* + * find out which line we have + */ + n = snprint(buf, sizeof(buf), "%s/", netdir); + m = read(ctl, &buf[n], sizeof(buf)-n-1); + if(m <= 0){ + werrstr("announce reading %s: %r", netdir); + close(ctl); + return -1; + } + buf[n+m] = 0; + + /* + * make the call + */ + n = snprint(buf2, sizeof(buf2), "announce %s", naddr); + if(write(ctl, buf2, n)!=n){ + werrstr("announce writing %s: %r", netdir); + close(ctl); + return -1; + } + + /* + * return directory etc. + */ + if(dir){ + strncpy(dir, buf, NETPATHLEN); + dir[NETPATHLEN-1] = 0; + } + return ctl; +} + +/* + * listen for an incoming call + */ +int +listen(char *dir, char *newdir) +{ + int ctl, n, m; + char buf[Maxpath]; + char *cp; + + /* + * open listen, wait for a call + */ + snprint(buf, sizeof(buf), "%s/listen", dir); + ctl = open(buf, ORDWR); + if(ctl < 0){ + werrstr("listen opening %s: %r", buf); + return -1; + } + + /* + * find out which line we have + */ + strncpy(buf, dir, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + cp = strrchr(buf, '/'); + if(cp == nil){ + close(ctl); + werrstr("listen arg format %s", dir); + return -1; + } + *++cp = 0; + n = cp-buf; + m = read(ctl, cp, sizeof(buf) - n - 1); + if(m <= 0){ + close(ctl); + werrstr("listen reading %s/listen: %r", dir); + return -1; + } + buf[n+m] = 0; + + /* + * return directory etc. + */ + if(newdir){ + strncpy(newdir, buf, NETPATHLEN); + newdir[NETPATHLEN-1] = 0; + } + return ctl; + +} + +/* + * accept a call, return an fd to the open data file + */ +int +accept(int ctl, char *dir) +{ + char buf[Maxpath]; + char *num; + long n; + + num = strrchr(dir, '/'); + if(num == nil) + num = dir; + else + num++; + + n = snprint(buf, sizeof(buf), "accept %s", num); + write(ctl, buf, n); /* ignore return value, network might not need accepts */ + + snprint(buf, sizeof(buf), "%s/data", dir); + return open(buf, ORDWR); +} + +/* + * reject a call, tell device the reason for the rejection + */ +int +reject(int ctl, char *dir, char *cause) +{ + char buf[Maxpath]; + char *num; + long n; + + num = strrchr(dir, '/'); + if(num == 0) + num = dir; + else + num++; + snprint(buf, sizeof(buf), "reject %s %s", num, cause); + n = strlen(buf); + if(write(ctl, buf, n) != n) + return -1; + return 0; +} + +/* + * perform the identity translation (in case we can't reach cs) + */ +static int +identtrans(char *netdir, char *addr, char *naddr, int na, char *file, int nf) +{ + char proto[Maxpath]; + char *p; + + USED(nf); + + /* parse the protocol */ + strncpy(proto, addr, sizeof(proto)); + proto[sizeof(proto)-1] = 0; + p = strchr(proto, '!'); + if(p) + *p++ = 0; + + snprint(file, nf, "%s/%s/clone", netdir, proto); + strncpy(naddr, p, na); + naddr[na-1] = 0; + + return 1; +} + +/* + * call up the connection server and get a translation + */ +static int +nettrans(char *addr, char *naddr, int na, char *file, int nf) +{ + int i, fd; + char buf[Maxpath]; + char netdir[Maxpath]; + char *p, *p2; + long n; + + /* + * parse, get network directory + */ + p = strchr(addr, '!'); + if(p == 0){ + werrstr("bad dial string: %s", addr); + return -1; + } + if(*addr != '/'){ + strncpy(netdir, "/net", sizeof(netdir)); + netdir[sizeof(netdir) - 1] = 0; + } else { + for(p2 = p; *p2 != '/'; p2--) + ; + i = p2 - addr; + if(i == 0 || i >= sizeof(netdir)){ + werrstr("bad dial string: %s", addr); + return -1; + } + strncpy(netdir, addr, i); + netdir[i] = 0; + addr = p2 + 1; + } + + /* + * ask the connection server + */ + snprint(buf, sizeof(buf), "%s/cs", netdir); + fd = open(buf, ORDWR); + if(fd < 0) + return identtrans(netdir, addr, naddr, na, file, nf); + if(write(fd, addr, strlen(addr)) < 0){ + close(fd); + return -1; + } + seek(fd, 0, 0); + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if(n <= 0) + return -1; + buf[n] = 0; + + /* + * parse the reply + */ + p = strchr(buf, ' '); + if(p == 0) + return -1; + *p++ = 0; + strncpy(naddr, p, na); + naddr[na-1] = 0; + + if(buf[0] == '/'){ + p = strchr(buf+1, '/'); + if(p == nil) + p = buf; + else + p++; + } + snprint(file, nf, "%s/%s", netdir, p); + return 0; +} diff --git a/sys/src/libc/9sys/convD2M.c b/sys/src/libc/9sys/convD2M.c new file mode 100755 index 000000000..dfc0e5d79 --- /dev/null +++ b/sys/src/libc/9sys/convD2M.c @@ -0,0 +1,95 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +uint +sizeD2M(Dir *d) +{ + char *sv[4]; + int i, ns; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++) + if(sv[i]) + ns += strlen(sv[i]); + + return STATFIXLEN + ns; +} + +uint +convD2M(Dir *d, uchar *buf, uint nbuf) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns, nsv[4], ss; + + if(nbuf < BIT16SZ) + return 0; + + p = buf; + ebuf = buf + nbuf; + + sv[0] = d->name; + sv[1] = d->uid; + sv[2] = d->gid; + sv[3] = d->muid; + + ns = 0; + for(i = 0; i < 4; i++){ + if(sv[i]) + nsv[i] = strlen(sv[i]); + else + nsv[i] = 0; + ns += nsv[i]; + } + + ss = STATFIXLEN + ns; + + /* set size before erroring, so user can know how much is needed */ + /* note that length excludes count field itself */ + PBIT16(p, ss-BIT16SZ); + p += BIT16SZ; + + if(ss > nbuf) + return BIT16SZ; + + PBIT16(p, d->type); + p += BIT16SZ; + PBIT32(p, d->dev); + p += BIT32SZ; + PBIT8(p, d->qid.type); + p += BIT8SZ; + PBIT32(p, d->qid.vers); + p += BIT32SZ; + PBIT64(p, d->qid.path); + p += BIT64SZ; + PBIT32(p, d->mode); + p += BIT32SZ; + PBIT32(p, d->atime); + p += BIT32SZ; + PBIT32(p, d->mtime); + p += BIT32SZ; + PBIT64(p, d->length); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + ns = nsv[i]; + if(p + ns + BIT16SZ > ebuf) + return 0; + PBIT16(p, ns); + p += BIT16SZ; + if(ns) + memmove(p, sv[i], ns); + p += ns; + } + + if(ss != p - buf) + return 0; + + return p - buf; +} diff --git a/sys/src/libc/9sys/convM2D.c b/sys/src/libc/9sys/convM2D.c new file mode 100755 index 000000000..6f4b4bd93 --- /dev/null +++ b/sys/src/libc/9sys/convM2D.c @@ -0,0 +1,94 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +statcheck(uchar *buf, uint nbuf) +{ + uchar *ebuf; + int i; + + ebuf = buf + nbuf; + + if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf)) + return -1; + + buf += STATFIXLEN - 4 * BIT16SZ; + + for(i = 0; i < 4; i++){ + if(buf + BIT16SZ > ebuf) + return -1; + buf += BIT16SZ + GBIT16(buf); + } + + if(buf != ebuf) + return -1; + + return 0; +} + +static char nullstring[] = ""; + +uint +convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) +{ + uchar *p, *ebuf; + char *sv[4]; + int i, ns; + + if(nbuf < STATFIXLEN) + return 0; + + p = buf; + ebuf = buf + nbuf; + + p += BIT16SZ; /* ignore size */ + d->type = GBIT16(p); + p += BIT16SZ; + d->dev = GBIT32(p); + p += BIT32SZ; + d->qid.type = GBIT8(p); + p += BIT8SZ; + d->qid.vers = GBIT32(p); + p += BIT32SZ; + d->qid.path = GBIT64(p); + p += BIT64SZ; + d->mode = GBIT32(p); + p += BIT32SZ; + d->atime = GBIT32(p); + p += BIT32SZ; + d->mtime = GBIT32(p); + p += BIT32SZ; + d->length = GBIT64(p); + p += BIT64SZ; + + for(i = 0; i < 4; i++){ + if(p + BIT16SZ > ebuf) + return 0; + ns = GBIT16(p); + p += BIT16SZ; + if(p + ns > ebuf) + return 0; + if(strs){ + sv[i] = strs; + memmove(strs, p, ns); + strs += ns; + *strs++ = '\0'; + } + p += ns; + } + + if(strs){ + d->name = sv[0]; + d->uid = sv[1]; + d->gid = sv[2]; + d->muid = sv[3]; + }else{ + d->name = nullstring; + d->uid = nullstring; + d->gid = nullstring; + d->muid = nullstring; + } + + return p - buf; +} diff --git a/sys/src/libc/9sys/convM2S.c b/sys/src/libc/9sys/convM2S.c new file mode 100755 index 000000000..fcdcd42d6 --- /dev/null +++ b/sys/src/libc/9sys/convM2S.c @@ -0,0 +1,315 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static +uchar* +gstring(uchar *p, uchar *ep, char **s) +{ + uint n; + + if(p+BIT16SZ > ep) + return nil; + n = GBIT16(p); + p += BIT16SZ - 1; + if(p+n+1 > ep) + return nil; + /* move it down, on top of count, to make room for '\0' */ + memmove(p, p + 1, n); + p[n] = '\0'; + *s = (char*)p; + p += n+1; + return p; +} + +static +uchar* +gqid(uchar *p, uchar *ep, Qid *q) +{ + if(p+QIDSZ > ep) + return nil; + q->type = GBIT8(p); + p += BIT8SZ; + q->vers = GBIT32(p); + p += BIT32SZ; + q->path = GBIT64(p); + p += BIT64SZ; + return p; +} + +/* + * no syntactic checks. + * three causes for error: + * 1. message size field is incorrect + * 2. input buffer too short for its own data (counts too long, etc.) + * 3. too many names or qids + * gqid() and gstring() return nil if they would reach beyond buffer. + * main switch statement checks range and also can fall through + * to test at end of routine. + */ +uint +convM2S(uchar *ap, uint nap, Fcall *f) +{ + uchar *p, *ep; + uint i, size; + + p = ap; + ep = p + nap; + + if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep) + return 0; + size = GBIT32(p); + p += BIT32SZ; + + if(size < BIT32SZ+BIT8SZ+BIT16SZ) + return 0; + + f->type = GBIT8(p); + p += BIT8SZ; + f->tag = GBIT16(p); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Tflush: + if(p+BIT16SZ > ep) + return 0; + f->oldtag = GBIT16(p); + p += BIT16SZ; + break; + + case Tauth: + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Tattach: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + if(p+BIT32SZ > ep) + return 0; + f->afid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->uname); + if(p == nil) + break; + p = gstring(p, ep, &f->aname); + if(p == nil) + break; + break; + + case Twalk: + if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->newfid = GBIT32(p); + p += BIT32SZ; + f->nwname = GBIT16(p); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; i<f->nwname; i++){ + p = gstring(p, ep, &f->wname[i]); + if(p == nil) + break; + } + break; + + case Topen: + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tcreate: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->name); + if(p == nil) + break; + if(p+BIT32SZ+BIT8SZ > ep) + return 0; + f->perm = GBIT32(p); + p += BIT32SZ; + f->mode = GBIT8(p); + p += BIT8SZ; + break; + + case Tread: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Twrite: + if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->offset = GBIT64(p); + p += BIT64SZ; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Tclunk: + case Tremove: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Tstat: + if(p+BIT32SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + break; + + case Twstat: + if(p+BIT32SZ+BIT16SZ > ep) + return 0; + f->fid = GBIT32(p); + p += BIT32SZ; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + +/* + */ + case Rversion: + if(p+BIT32SZ > ep) + return 0; + f->msize = GBIT32(p); + p += BIT32SZ; + p = gstring(p, ep, &f->version); + break; + + case Rerror: + p = gstring(p, ep, &f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = gqid(p, ep, &f->aqid); + if(p == nil) + break; + break; + + case Rattach: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + break; + + case Rwalk: + if(p+BIT16SZ > ep) + return 0; + f->nwqid = GBIT16(p); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; i<f->nwqid; i++){ + p = gqid(p, ep, &f->wqid[i]); + if(p == nil) + break; + } + break; + + case Ropen: + case Rcreate: + p = gqid(p, ep, &f->qid); + if(p == nil) + break; + if(p+BIT32SZ > ep) + return 0; + f->iounit = GBIT32(p); + p += BIT32SZ; + break; + + case Rread: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + if(p+f->count > ep) + return 0; + f->data = (char*)p; + p += f->count; + break; + + case Rwrite: + if(p+BIT32SZ > ep) + return 0; + f->count = GBIT32(p); + p += BIT32SZ; + break; + + case Rclunk: + case Rremove: + break; + + case Rstat: + if(p+BIT16SZ > ep) + return 0; + f->nstat = GBIT16(p); + p += BIT16SZ; + if(p+f->nstat > ep) + return 0; + f->stat = p; + p += f->nstat; + break; + + case Rwstat: + break; + } + + if(p==nil || p>ep) + return 0; + if(ap+size == p) + return size; + return 0; +} diff --git a/sys/src/libc/9sys/convS2M.c b/sys/src/libc/9sys/convS2M.c new file mode 100755 index 000000000..fb5f596ce --- /dev/null +++ b/sys/src/libc/9sys/convS2M.c @@ -0,0 +1,389 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static +uchar* +pstring(uchar *p, char *s) +{ + uint n; + + if(s == nil){ + PBIT16(p, 0); + p += BIT16SZ; + return p; + } + + n = strlen(s); + /* + * We are moving the string before the length, + * so you can S2M a struct into an existing message + */ + memmove(p + BIT16SZ, s, n); + PBIT16(p, n); + p += n + BIT16SZ; + return p; +} + +static +uchar* +pqid(uchar *p, Qid *q) +{ + PBIT8(p, q->type); + p += BIT8SZ; + PBIT32(p, q->vers); + p += BIT32SZ; + PBIT64(p, q->path); + p += BIT64SZ; + return p; +} + +static +uint +stringsz(char *s) +{ + if(s == nil) + return BIT16SZ; + + return BIT16SZ+strlen(s); +} + +uint +sizeS2M(Fcall *f) +{ + uint n; + int i; + + n = 0; + n += BIT32SZ; /* size */ + n += BIT8SZ; /* type */ + n += BIT16SZ; /* tag */ + + switch(f->type) + { + default: + return 0; + + case Tversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Tflush: + n += BIT16SZ; + break; + + case Tauth: + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Tattach: + n += BIT32SZ; + n += BIT32SZ; + n += stringsz(f->uname); + n += stringsz(f->aname); + break; + + case Twalk: + n += BIT32SZ; + n += BIT32SZ; + n += BIT16SZ; + for(i=0; i<f->nwname; i++) + n += stringsz(f->wname[i]); + break; + + case Topen: + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tcreate: + n += BIT32SZ; + n += stringsz(f->name); + n += BIT32SZ; + n += BIT8SZ; + break; + + case Tread: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + break; + + case Twrite: + n += BIT32SZ; + n += BIT64SZ; + n += BIT32SZ; + n += f->count; + break; + + case Tclunk: + case Tremove: + n += BIT32SZ; + break; + + case Tstat: + n += BIT32SZ; + break; + + case Twstat: + n += BIT32SZ; + n += BIT16SZ; + n += f->nstat; + break; +/* + */ + + case Rversion: + n += BIT32SZ; + n += stringsz(f->version); + break; + + case Rerror: + n += stringsz(f->ename); + break; + + case Rflush: + break; + + case Rauth: + n += QIDSZ; + break; + + case Rattach: + n += QIDSZ; + break; + + case Rwalk: + n += BIT16SZ; + n += f->nwqid*QIDSZ; + break; + + case Ropen: + case Rcreate: + n += QIDSZ; + n += BIT32SZ; + break; + + case Rread: + n += BIT32SZ; + n += f->count; + break; + + case Rwrite: + n += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + n += BIT16SZ; + n += f->nstat; + break; + + case Rwstat: + break; + } + return n; +} + +uint +convS2M(Fcall *f, uchar *ap, uint nap) +{ + uchar *p; + uint i, size; + + size = sizeS2M(f); + if(size == 0) + return 0; + if(size > nap) + return 0; + + p = (uchar*)ap; + + PBIT32(p, size); + p += BIT32SZ; + PBIT8(p, f->type); + p += BIT8SZ; + PBIT16(p, f->tag); + p += BIT16SZ; + + switch(f->type) + { + default: + return 0; + + case Tversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Tflush: + PBIT16(p, f->oldtag); + p += BIT16SZ; + break; + + case Tauth: + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Tattach: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->afid); + p += BIT32SZ; + p = pstring(p, f->uname); + p = pstring(p, f->aname); + break; + + case Twalk: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT32(p, f->newfid); + p += BIT32SZ; + PBIT16(p, f->nwname); + p += BIT16SZ; + if(f->nwname > MAXWELEM) + return 0; + for(i=0; i<f->nwname; i++) + p = pstring(p, f->wname[i]); + break; + + case Topen: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tcreate: + PBIT32(p, f->fid); + p += BIT32SZ; + p = pstring(p, f->name); + PBIT32(p, f->perm); + p += BIT32SZ; + PBIT8(p, f->mode); + p += BIT8SZ; + break; + + case Tread: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Twrite: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT64(p, f->offset); + p += BIT64SZ; + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Tclunk: + case Tremove: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Tstat: + PBIT32(p, f->fid); + p += BIT32SZ; + break; + + case Twstat: + PBIT32(p, f->fid); + p += BIT32SZ; + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; +/* + */ + + case Rversion: + PBIT32(p, f->msize); + p += BIT32SZ; + p = pstring(p, f->version); + break; + + case Rerror: + p = pstring(p, f->ename); + break; + + case Rflush: + break; + + case Rauth: + p = pqid(p, &f->aqid); + break; + + case Rattach: + p = pqid(p, &f->qid); + break; + + case Rwalk: + PBIT16(p, f->nwqid); + p += BIT16SZ; + if(f->nwqid > MAXWELEM) + return 0; + for(i=0; i<f->nwqid; i++) + p = pqid(p, &f->wqid[i]); + break; + + case Ropen: + case Rcreate: + p = pqid(p, &f->qid); + PBIT32(p, f->iounit); + p += BIT32SZ; + break; + + case Rread: + PBIT32(p, f->count); + p += BIT32SZ; + memmove(p, f->data, f->count); + p += f->count; + break; + + case Rwrite: + PBIT32(p, f->count); + p += BIT32SZ; + break; + + case Rclunk: + break; + + case Rremove: + break; + + case Rstat: + PBIT16(p, f->nstat); + p += BIT16SZ; + memmove(p, f->stat, f->nstat); + p += f->nstat; + break; + + case Rwstat: + break; + } + if(size != p-ap) + return 0; + return size; +} diff --git a/sys/src/libc/9sys/cputime.c b/sys/src/libc/9sys/cputime.c new file mode 100755 index 000000000..1e05634aa --- /dev/null +++ b/sys/src/libc/9sys/cputime.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +#define HZ 1000 + +double +cputime(void) +{ + long t[4]; + long times(long*); + int i; + + times(t); + for(i=1; i<4; i++) + t[0] += t[i]; + return t[0] / (double)HZ; +} diff --git a/sys/src/libc/9sys/ctime.c b/sys/src/libc/9sys/ctime.c new file mode 100755 index 000000000..d841b64e9 --- /dev/null +++ b/sys/src/libc/9sys/ctime.c @@ -0,0 +1,304 @@ +/* + * This routine converts time as follows. + * The epoch is 0000 Jan 1 1970 GMT. + * The argument time is in seconds since then. + * The localtime(t) entry returns a pointer to an array + * containing + * + * seconds (0-59) + * minutes (0-59) + * hours (0-23) + * day of month (1-31) + * month (0-11) + * year-1970 + * weekday (0-6, Sun is 0) + * day of the year + * daylight savings flag + * + * The routine gets the daylight savings time from the environment. + * + * asctime(tvec)) + * where tvec is produced by localtime + * returns a ptr to a character string + * that has the ascii time in the form + * + * \\ + * Thu Jan 01 00:00:00 GMT 1970n0 + * 012345678901234567890123456789 + * 0 1 2 + * + * ctime(t) just calls localtime, then asctime. + */ + +#include <u.h> +#include <libc.h> + +static char dmsize[12] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * The following table is used for 1974 and 1975 and + * gives the day number of the first day after the Sunday of the + * change. + */ + +static int dysize(int); +static void ct_numb(char*, int); + +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +char* +ctime(long t) +{ + return asctime(localtime(t)); +} + +Tm* +localtime(long tim) +{ + Tm *ct; + long t, *p; + int dlflag; + + if(timezone.stname[0] == 0) + readtimezone(); + t = tim + timezone.stdiff; + dlflag = 0; + for(p = timezone.dlpairs; *p; p += 2) + if(t >= p[0]) + if(t < p[1]) { + t = tim + timezone.dldiff; + dlflag++; + break; + } + ct = gmtime(t); + if(dlflag){ + strcpy(ct->zone, timezone.dlname); + ct->tzoff = timezone.dldiff; + } else { + strcpy(ct->zone, timezone.stname); + ct->tzoff = timezone.stdiff; + } + return ct; +} + +Tm* +gmtime(long tim) +{ + int d0, d1; + long hms, day; + static Tm xtime; + + /* + * break initial number into days + */ + hms = tim % 86400L; + day = tim / 86400L; + if(hms < 0) { + hms += 86400L; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + xtime.sec = hms % 60; + d1 = hms / 60; + xtime.min = d1 % 60; + d1 /= 60; + xtime.hour = d1; + + /* + * day is the day number. + * generate day of the week. + * The addend is 4 mod 7 (1/1/1970 was Thursday) + */ + + xtime.wday = (day + 7340036L) % 7; + + /* + * year number + */ + if(day >= 0) + for(d1 = 1970; day >= dysize(d1); d1++) + day -= dysize(d1); + else + for (d1 = 1970; day < 0; d1--) + day += dysize(d1-1); + xtime.year = d1-1900; + xtime.yday = d0 = day; + + /* + * generate month + */ + + if(dysize(d1) == 366) + dmsize[1] = 29; + for(d1 = 0; d0 >= dmsize[d1]; d1++) + d0 -= dmsize[d1]; + dmsize[1] = 28; + xtime.mday = d0 + 1; + xtime.mon = d1; + strcpy(xtime.zone, "GMT"); + return &xtime; +} + +char* +asctime(Tm *t) +{ + char *ncp; + static char cbuf[30]; + + strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n"); + ncp = &"SunMonTueWedThuFriSat"[t->wday*3]; + cbuf[0] = *ncp++; + cbuf[1] = *ncp++; + cbuf[2] = *ncp; + ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3]; + cbuf[4] = *ncp++; + cbuf[5] = *ncp++; + cbuf[6] = *ncp; + ct_numb(cbuf+8, t->mday); + ct_numb(cbuf+11, t->hour+100); + ct_numb(cbuf+14, t->min+100); + ct_numb(cbuf+17, t->sec+100); + ncp = t->zone; + cbuf[20] = *ncp++; + cbuf[21] = *ncp++; + cbuf[22] = *ncp; + if(t->year >= 100) { + cbuf[24] = '2'; + cbuf[25] = '0'; + } + ct_numb(cbuf+26, t->year+100); + return cbuf; +} + +static +dysize(int y) +{ + + if(y%4 == 0 && (y%100 != 0 || y%400 == 0)) + return 366; + return 365; +} + +static +void +ct_numb(char *cp, int n) +{ + + cp[0] = ' '; + if(n >= 10) + cp[0] = (n/10)%10 + '0'; + cp[1] = n%10 + '0'; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)){ + close(i); + goto error; + } + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i<TZSIZE; i++) { + if(rd_long(&p, &timezone.dlpairs[i])) + goto error; + if(timezone.dlpairs[i] == 0) + return; + } + +error: + timezone.stdiff = 0; + strcpy(timezone.stname, "GMT"); + timezone.dlpairs[0] = 0; +} + +static +rd_name(char **f, char *p) +{ + int c, i; + + for(;;) { + c = *(*f)++; + if(c != ' ' && c != '\n') + break; + } + for(i=0; i<3; i++) { + if(c == ' ' || c == '\n') + return 1; + *p++ = c; + c = *(*f)++; + } + if(c != ' ' && c != '\n') + return 1; + *p = 0; + return 0; +} + +static +rd_long(char **f, long *p) +{ + int c, s; + long l; + + s = 0; + for(;;) { + c = *(*f)++; + if(c == '-') { + s++; + continue; + } + if(c != ' ' && c != '\n') + break; + } + if(c == 0) { + *p = 0; + return 0; + } + l = 0; + for(;;) { + if(c == ' ' || c == '\n') + break; + if(c < '0' || c > '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; +} diff --git a/sys/src/libc/9sys/dial.c b/sys/src/libc/9sys/dial.c new file mode 100755 index 000000000..74fc6e6ae --- /dev/null +++ b/sys/src/libc/9sys/dial.c @@ -0,0 +1,492 @@ +/* + * dial - connect to a service (parallel version) + */ +#include <u.h> +#include <libc.h> + +typedef struct Conn Conn; +typedef struct Dest Dest; +typedef struct DS DS; + +enum +{ + Maxstring = 128, + Maxpath = 256, + + Maxcsreply = 64*80, /* this is probably overly generous */ + /* + * this should be a plausible slight overestimate for non-interactive + * use even if it's ridiculously long for interactive use. + */ + Maxconnms = 20*60*1000, /* 20 minutes */ +}; + +struct DS { + /* dist string */ + char buf[Maxstring]; + char *netdir; + char *proto; + char *rem; + + /* other args */ + char *local; + char *dir; + int *cfdp; +}; + +/* + * malloc these; they need to be writable by this proc & all children. + * the stack is private to each proc, and static allocation in the data + * segment would not permit concurrent dials within a multi-process program. + */ +struct Conn { + int pid; + int dead; + + int dfd; + int cfd; + char dir[NETPATHLEN]; + char err[ERRMAX]; +}; +struct Dest { + Conn *conn; /* allocated array */ + Conn *connend; + int nkid; + + QLock winlck; + int winner; /* index into conn[] */ + + char *nextaddr; + char addrlist[Maxcsreply]; +}; + +static int call(char*, char*, DS*, Dest*, Conn*); +static int csdial(DS*); +static void _dial_string_parse(char*, DS*); + + +/* + * the dialstring is of the form '[/net/]proto!dest' + */ +static int +dialimpl(char *dest, char *local, char *dir, int *cfdp) +{ + DS ds; + int rv; + char err[ERRMAX], alterr[ERRMAX]; + + ds.local = local; + ds.dir = dir; + ds.cfdp = cfdp; + + _dial_string_parse(dest, &ds); + if(ds.netdir) + return csdial(&ds); + + ds.netdir = "/net"; + rv = csdial(&ds); + if(rv >= 0) + return rv; + err[0] = '\0'; + errstr(err, sizeof err); + if(strstr(err, "refused") != 0){ + werrstr("%s", err); + return rv; + } + ds.netdir = "/net.alt"; + rv = csdial(&ds); + if(rv >= 0) + return rv; + + alterr[0] = 0; + errstr(alterr, sizeof alterr); + if(strstr(alterr, "translate") || strstr(alterr, "does not exist")) + werrstr("%s", err); + else + werrstr("%s", alterr); + return rv; +} + +/* + * the thread library can't cope with rfork(RFMEM|RFPROC), + * so it must override this with a private version of dial. + */ +int (*_dial)(char *, char *, char *, int *) = dialimpl; + +int +dial(char *dest, char *local, char *dir, int *cfdp) +{ + return (*_dial)(dest, local, dir, cfdp); +} + +static int +connsalloc(Dest *dp, int addrs) +{ + free(dp->conn); + dp->connend = nil; + assert(addrs > 0); + + dp->conn = mallocz(addrs * sizeof *dp->conn, 1); + if(dp->conn == nil) + return -1; + dp->connend = dp->conn + addrs; + return 0; +} + +static void +freedest(Dest *dp) +{ + if (dp != nil) { + free(dp->conn); + free(dp); + } +} + +static void +closeopenfd(int *fdp) +{ + if (*fdp > 0) { + close(*fdp); + *fdp = -1; + } +} + +static void +notedeath(Dest *dp, char *exitsts) +{ + int i, n, pid; + char *fields[5]; /* pid + 3 times + error */ + Conn *conn; + + for (i = 0; i < nelem(fields); i++) + fields[i] = ""; + n = tokenize(exitsts, fields, nelem(fields)); + if (n < 4) + return; + pid = atoi(fields[0]); + if (pid <= 0) + return; + for (conn = dp->conn; conn < dp->connend; conn++) + if (conn->pid == pid && !conn->dead) { /* it's one we know? */ + if (conn - dp->conn != dp->winner) { + closeopenfd(&conn->dfd); + closeopenfd(&conn->cfd); + } + strncpy(conn->err, fields[4], sizeof conn->err); + conn->dead = 1; + return; + } + /* not a proc that we forked */ +} + +static int +outstandingprocs(Dest *dp) +{ + Conn *conn; + + for (conn = dp->conn; conn < dp->connend; conn++) + if (!conn->dead) + return 1; + return 0; +} + +static int +reap(Dest *dp) +{ + char exitsts[2*ERRMAX]; + + if (outstandingprocs(dp) && await(exitsts, sizeof exitsts) >= 0) { + notedeath(dp, exitsts); + return 0; + } + return -1; +} + +static int +fillinds(DS *ds, Dest *dp) +{ + Conn *conn; + + if (dp->winner < 0) + return -1; + conn = &dp->conn[dp->winner]; + if (ds->cfdp) + *ds->cfdp = conn->cfd; + if (ds->dir) + strncpy(ds->dir, conn->dir, NETPATHLEN); + return conn->dfd; +} + +static int +connectwait(Dest *dp, char *besterr) +{ + Conn *conn; + + /* wait for a winner or all attempts to time out */ + while (dp->winner < 0 && reap(dp) >= 0) + ; + + /* kill all of our still-live kids & reap them */ + for (conn = dp->conn; conn < dp->connend; conn++) + if (!conn->dead) + postnote(PNPROC, conn->pid, "die"); + while (reap(dp) >= 0) + ; + + /* rummage about and report some error string */ + for (conn = dp->conn; conn < dp->connend; conn++) + if (conn - dp->conn != dp->winner && conn->dead && + conn->err[0]) { + strncpy(besterr, conn->err, ERRMAX); + break; + } + return dp->winner; +} + +static int +parsecs(Dest *dp, char **clonep, char **destp) +{ + char *dest, *p; + + dest = strchr(dp->nextaddr, ' '); + if(dest == nil) + return -1; + *dest++ = '\0'; + p = strchr(dest, '\n'); + if(p == nil) + return -1; + *p++ = '\0'; + *clonep = dp->nextaddr; + *destp = dest; + dp->nextaddr = p; /* advance to next line */ + return 0; +} + +static void +pickuperr(char *besterr, char *err) +{ + err[0] = '\0'; + errstr(err, ERRMAX); + if(strstr(err, "does not exist") == 0) + strcpy(besterr, err); +} + +/* + * try all addresses in parallel and take the first one that answers; + * this helps when systems have ip v4 and v6 addresses but are + * only reachable from here on one (or some) of them. + */ +static int +dialmulti(DS *ds, Dest *dp) +{ + int rv, kid, kidme; + char *clone, *dest; + char err[ERRMAX], besterr[ERRMAX]; + + dp->winner = -1; + dp->nkid = 0; + while(dp->winner < 0 && *dp->nextaddr != '\0' && + parsecs(dp, &clone, &dest) >= 0) { + kidme = dp->nkid++; /* make private copy on stack */ + kid = rfork(RFPROC|RFMEM); /* spin off a call attempt */ + if (kid < 0) + --dp->nkid; + else if (kid == 0) { + alarm(Maxconnms); + *besterr = '\0'; + rv = call(clone, dest, ds, dp, &dp->conn[kidme]); + if(rv < 0) + pickuperr(besterr, err); + _exits(besterr); /* avoid atexit callbacks */ + } + } + rv = connectwait(dp, besterr); + if(rv < 0 && *besterr) + werrstr("%s", besterr); + else + werrstr("%s", err); + return rv; +} + +static int +csdial(DS *ds) +{ + int n, fd, rv, addrs, bleft; + char c; + char *addrp, *clone2, *dest; + char buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX]; + Dest *dp; + + dp = mallocz(sizeof *dp, 1); + if(dp == nil) + return -1; + dp->winner = -1; + if (connsalloc(dp, 1) < 0) { /* room for a single conn. */ + freedest(dp); + return -1; + } + + /* + * open connection server + */ + snprint(buf, sizeof(buf), "%s/cs", ds->netdir); + fd = open(buf, ORDWR); + if(fd < 0){ + /* no connection server, don't translate */ + snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto); + rv = call(clone, ds->rem, ds, dp, &dp->conn[0]); + fillinds(ds, dp); + freedest(dp); + return rv; + } + + /* + * ask connection server to translate + */ + snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem); + if(write(fd, buf, strlen(buf)) < 0){ + close(fd); + freedest(dp); + return -1; + } + + /* + * read all addresses from the connection server. + */ + seek(fd, 0, 0); + addrs = 0; + addrp = dp->nextaddr = dp->addrlist; + bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */ + while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) { + if (addrp[n-1] != '\n') + addrp[n++] = '\n'; + addrs++; + addrp += n; + bleft -= n; + } + /* + * if we haven't read all of cs's output, assume the last line might + * have been truncated and ignore it. we really don't expect this + * to happen. + */ + if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1) + addrs--; + close(fd); + + *besterr = 0; + rv = -1; /* pessimistic default */ + if (addrs == 0) + werrstr("no address to dial"); + else if (addrs == 1) { + /* common case: dial one address without forking */ + if (parsecs(dp, &clone2, &dest) >= 0 && + (rv = call(clone2, dest, ds, dp, &dp->conn[0])) < 0) { + pickuperr(besterr, err); + werrstr("%s", besterr); + } + } else if (connsalloc(dp, addrs) >= 0) + rv = dialmulti(ds, dp); + + /* fill in results */ + if (rv >= 0 && dp->winner >= 0) + rv = fillinds(ds, dp); + + freedest(dp); + return rv; +} + +static int +call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn) +{ + int fd, cfd, n; + char cname[Maxpath], name[Maxpath], data[Maxpath], *p; + + /* because cs is in a different name space, replace the mount point */ + if(*clone == '/'){ + p = strchr(clone+1, '/'); + if(p == nil) + p = clone; + else + p++; + } else + p = clone; + snprint(cname, sizeof cname, "%s/%s", ds->netdir, p); + + conn->pid = getpid(); + conn->cfd = cfd = open(cname, ORDWR); + if(cfd < 0) + return -1; + + /* get directory name */ + n = read(cfd, name, sizeof(name)-1); + if(n < 0){ + closeopenfd(&conn->cfd); + return -1; + } + name[n] = 0; + for(p = name; *p == ' '; p++) + ; + snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0)); + p = strrchr(cname, '/'); + *p = 0; + if(ds->dir) + snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name); + snprint(data, sizeof(data), "%s/%s/data", cname, name); + + /* connect */ + if(ds->local) + snprint(name, sizeof(name), "connect %s %s", dest, ds->local); + else + snprint(name, sizeof(name), "connect %s", dest); + if(write(cfd, name, strlen(name)) < 0){ + closeopenfd(&conn->cfd); + return -1; + } + + /* open data connection */ + conn->dfd = fd = open(data, ORDWR); + if(fd < 0){ + closeopenfd(&conn->cfd); + return -1; + } + if(ds->cfdp == nil) + closeopenfd(&conn->cfd); + + qlock(&dp->winlck); + if (dp->winner < 0 && conn < dp->connend) + dp->winner = conn - dp->conn; + qunlock(&dp->winlck); + return fd; +} + +/* + * parse a dial string + */ +static void +_dial_string_parse(char *str, DS *ds) +{ + char *p, *p2; + + strncpy(ds->buf, str, Maxstring); + ds->buf[Maxstring-1] = 0; + + p = strchr(ds->buf, '!'); + if(p == 0) { + ds->netdir = 0; + ds->proto = "net"; + ds->rem = ds->buf; + } else { + if(*ds->buf != '/' && *ds->buf != '#'){ + ds->netdir = 0; + ds->proto = ds->buf; + } else { + for(p2 = p; *p2 != '/'; p2--) + ; + *p2++ = 0; + ds->netdir = ds->buf; + ds->proto = p2; + } + *p = 0; + ds->rem = p + 1; + } +} diff --git a/sys/src/libc/9sys/dirfstat.c b/sys/src/libc/9sys/dirfstat.c new file mode 100755 index 000000000..0534a2278 --- /dev/null +++ b/sys/src/libc/9sys/dirfstat.c @@ -0,0 +1,37 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +enum +{ + DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ +}; + +Dir* +dirfstat(int fd) +{ + Dir *d; + uchar *buf; + int n, nd, i; + + nd = DIRSIZE; + for(i=0; i<2; i++){ /* should work by the second try */ + d = malloc(sizeof(Dir) + BIT16SZ + nd); + if(d == nil) + return nil; + buf = (uchar*)&d[1]; + n = fstat(fd, buf, BIT16SZ+nd); + if(n < BIT16SZ){ + free(d); + return nil; + } + nd = GBIT16(buf); /* upper bound on size of Dir + strings */ + if(nd <= n){ + convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+BIT16SZ+nd is plenty */ + free(d); + } + return nil; +} diff --git a/sys/src/libc/9sys/dirfwstat.c b/sys/src/libc/9sys/dirfwstat.c new file mode 100755 index 000000000..85803ff4c --- /dev/null +++ b/sys/src/libc/9sys/dirfwstat.c @@ -0,0 +1,19 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +dirfwstat(int fd, Dir *d) +{ + uchar *buf; + int r; + + r = sizeD2M(d); + buf = malloc(r); + if(buf == nil) + return -1; + convD2M(d, buf, r); + r = fwstat(fd, buf, r); + free(buf); + return r; +} diff --git a/sys/src/libc/9sys/dirmodefmt.c b/sys/src/libc/9sys/dirmodefmt.c new file mode 100755 index 000000000..82eb5a308 --- /dev/null +++ b/sys/src/libc/9sys/dirmodefmt.c @@ -0,0 +1,48 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static char *modes[] = +{ + "---", + "--x", + "-w-", + "-wx", + "r--", + "r-x", + "rw-", + "rwx", +}; + +static void +rwx(long m, char *s) +{ + strncpy(s, modes[m], 3); +} + +int +dirmodefmt(Fmt *f) +{ + static char buf[16]; + ulong m; + + m = va_arg(f->args, ulong); + + if(m & DMDIR) + buf[0]='d'; + else if(m & DMAPPEND) + buf[0]='a'; + else if(m & DMAUTH) + buf[0]='A'; + else + buf[0]='-'; + if(m & DMEXCL) + buf[1]='l'; + else + buf[1]='-'; + rwx((m>>6)&7, buf+2); + rwx((m>>3)&7, buf+5); + rwx((m>>0)&7, buf+8); + buf[11] = 0; + return fmtstrcpy(f, buf); +} diff --git a/sys/src/libc/9sys/dirread.c b/sys/src/libc/9sys/dirread.c new file mode 100755 index 000000000..0efd2f954 --- /dev/null +++ b/sys/src/libc/9sys/dirread.c @@ -0,0 +1,97 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static +long +dirpackage(uchar *buf, long ts, Dir **d) +{ + char *s; + long ss, i, n, nn, m; + + *d = nil; + if(ts <= 0) + return 0; + + /* + * first find number of all stats, check they look like stats, & size all associated strings + */ + ss = 0; + n = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16(&buf[i]); + if(statcheck(&buf[i], m) < 0) + break; + ss += m; + n++; + } + + if(i != ts) + return -1; + + *d = malloc(n * sizeof(Dir) + ss); + if(*d == nil) + return -1; + + /* + * then convert all buffers + */ + s = (char*)*d + n * sizeof(Dir); + nn = 0; + for(i = 0; i < ts; i += m){ + m = BIT16SZ + GBIT16((uchar*)&buf[i]); + if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){ + free(*d); + *d = nil; + return -1; + } + nn++; + s += m; + } + + return nn; +} + +long +dirread(int fd, Dir **d) +{ + uchar *buf; + long ts; + + buf = malloc(DIRMAX); + if(buf == nil) + return -1; + ts = read(fd, buf, DIRMAX); + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + return ts; +} + +long +dirreadall(int fd, Dir **d) +{ + uchar *buf, *nbuf; + long n, ts; + + buf = nil; + ts = 0; + for(;;){ + nbuf = realloc(buf, ts+DIRMAX); + if(nbuf == nil){ + free(buf); + return -1; + } + buf = nbuf; + n = read(fd, buf+ts, DIRMAX); + if(n <= 0) + break; + ts += n; + } + if(ts >= 0) + ts = dirpackage(buf, ts, d); + free(buf); + if(ts == 0 && n < 0) + return -1; + return ts; +} diff --git a/sys/src/libc/9sys/dirstat.c b/sys/src/libc/9sys/dirstat.c new file mode 100755 index 000000000..eb5171d2a --- /dev/null +++ b/sys/src/libc/9sys/dirstat.c @@ -0,0 +1,37 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +enum +{ + DIRSIZE = STATFIXLEN + 16 * 4 /* enough for encoded stat buf + some reasonable strings */ +}; + +Dir* +dirstat(char *name) +{ + Dir *d; + uchar *buf; + int n, nd, i; + + nd = DIRSIZE; + for(i=0; i<2; i++){ /* should work by the second try */ + d = malloc(sizeof(Dir) + BIT16SZ + nd); + if(d == nil) + return nil; + buf = (uchar*)&d[1]; + n = stat(name, buf, BIT16SZ+nd); + if(n < BIT16SZ){ + free(d); + return nil; + } + nd = GBIT16((uchar*)buf); /* upper bound on size of Dir + strings */ + if(nd <= n){ + convM2D(buf, n, d, (char*)&d[1]); + return d; + } + /* else sizeof(Dir)+BIT16SZ+nd is plenty */ + free(d); + } + return nil; +} diff --git a/sys/src/libc/9sys/dirwstat.c b/sys/src/libc/9sys/dirwstat.c new file mode 100755 index 000000000..cb62e3fc4 --- /dev/null +++ b/sys/src/libc/9sys/dirwstat.c @@ -0,0 +1,19 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +dirwstat(char *name, Dir *d) +{ + uchar *buf; + int r; + + r = sizeD2M(d); + buf = malloc(r); + if(buf == nil) + return -1; + convD2M(d, buf, r); + r = wstat(name, buf, r); + free(buf); + return r; +} diff --git a/sys/src/libc/9sys/fcallfmt.c b/sys/src/libc/9sys/fcallfmt.c new file mode 100755 index 000000000..c5a8af614 --- /dev/null +++ b/sys/src/libc/9sys/fcallfmt.c @@ -0,0 +1,234 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +static uint dumpsome(char*, char*, char*, long); +static void fdirconv(char*, char*, Dir*); +static char *qidtype(char*, uchar); + +#define QIDFMT "(%.16llux %lud %s)" + +int +fcallfmt(Fmt *fmt) +{ + Fcall *f; + int fid, type, tag, i; + char buf[512], tmp[200]; + char *p, *e; + Dir *d; + Qid *q; + + e = buf+sizeof(buf); + f = va_arg(fmt->args, Fcall*); + type = f->type; + fid = f->fid; + tag = f->tag; + switch(type){ + case Tversion: /* 100 */ + seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Rversion: + seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version); + break; + case Tauth: /* 102 */ + seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag, + f->afid, f->uname, f->aname); + break; + case Rauth: + seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag, + f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type)); + break; + case Tattach: /* 104 */ + seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag, + fid, f->afid, f->uname, f->aname); + break; + case Rattach: + seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type)); + break; + case Rerror: /* 107; 106 (Terror) illegal */ + seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename); + break; + case Tflush: /* 108 */ + seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag); + break; + case Rflush: + seprint(buf, e, "Rflush tag %ud", tag); + break; + case Twalk: /* 110 */ + p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname); + if(f->nwname <= MAXWELEM) + for(i=0; i<f->nwname; i++) + p = seprint(p, e, "%d:%s ", i, f->wname[i]); + break; + case Rwalk: + p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid); + if(f->nwqid <= MAXWELEM) + for(i=0; i<f->nwqid; i++){ + q = &f->wqid[i]; + p = seprint(p, e, "%d:" QIDFMT " ", i, + q->path, q->vers, qidtype(tmp, q->type)); + } + break; + case Topen: /* 112 */ + seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode); + break; + case Ropen: + seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tcreate: /* 114 */ + seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode); + break; + case Rcreate: + seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag, + f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit); + break; + case Tread: /* 116 */ + seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud", + tag, fid, f->offset, f->count); + break; + case Rread: + p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Twrite: /* 118 */ + p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ", + tag, fid, f->offset, f->count); + dumpsome(p, e, f->data, f->count); + break; + case Rwrite: + seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count); + break; + case Tclunk: /* 120 */ + seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid); + break; + case Rclunk: + seprint(buf, e, "Rclunk tag %ud", tag); + break; + case Tremove: /* 122 */ + seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid); + break; + case Rremove: + seprint(buf, e, "Rremove tag %ud", tag); + break; + case Tstat: /* 124 */ + seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid); + break; + case Rstat: + p = seprint(buf, e, "Rstat tag %ud ", tag); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Twstat: /* 126 */ + p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); + if(f->nstat > sizeof tmp) + seprint(p, e, " stat(%d bytes)", f->nstat); + else{ + d = (Dir*)tmp; + convM2D(f->stat, f->nstat, d, (char*)(d+1)); + seprint(p, e, " stat "); + fdirconv(p+6, e, d); + } + break; + case Rwstat: + seprint(buf, e, "Rwstat tag %ud", tag); + break; + default: + seprint(buf, e, "unknown type %d", type); + } + return fmtstrcpy(fmt, buf); +} + +static char* +qidtype(char *s, uchar t) +{ + char *p; + + p = s; + if(t & QTDIR) + *p++ = 'd'; + if(t & QTAPPEND) + *p++ = 'a'; + if(t & QTEXCL) + *p++ = 'l'; + if(t & QTAUTH) + *p++ = 'A'; + *p = '\0'; + return s; +} + +int +dirfmt(Fmt *fmt) +{ + char buf[160]; + + fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*)); + return fmtstrcpy(fmt, buf); +} + +static void +fdirconv(char *buf, char *e, Dir *d) +{ + char tmp[16]; + + seprint(buf, e, "'%s' '%s' '%s' '%s' " + "q " QIDFMT " m %#luo " + "at %ld mt %ld l %lld " + "t %d d %d", + d->name, d->uid, d->gid, d->muid, + d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode, + d->atime, d->mtime, d->length, + d->type, d->dev); +} + +/* + * dump out count (or DUMPL, if count is bigger) bytes from + * buf to ans, as a string if they are all printable, + * else as a series of hex bytes + */ +#define DUMPL 64 + +static uint +dumpsome(char *ans, char *e, char *buf, long count) +{ + int i, printable; + char *p; + + if(buf == nil){ + seprint(ans, e, "<no data>"); + return strlen(ans); + } + printable = 1; + if(count > DUMPL) + count = DUMPL; + for(i=0; i<count && printable; i++) + if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127) + printable = 0; + p = ans; + *p++ = '\''; + if(printable){ + if(count > e-p-2) + count = e-p-2; + memmove(p, buf, count); + p += count; + }else{ + if(2*count > e-p-2) + count = (e-p-2)/2; + for(i=0; i<count; i++){ + if(i>0 && i%4==0) + *p++ = ' '; + sprint(p, "%2.2ux", (uchar)buf[i]); + p += 2; + } + } + *p++ = '\''; + *p = 0; + return p - ans; +} diff --git a/sys/src/libc/9sys/fork.c b/sys/src/libc/9sys/fork.c new file mode 100755 index 000000000..46296ed5d --- /dev/null +++ b/sys/src/libc/9sys/fork.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +int +fork(void) +{ + return rfork(RFPROC|RFFDG|RFREND); +} diff --git a/sys/src/libc/9sys/getenv.c b/sys/src/libc/9sys/getenv.c new file mode 100755 index 000000000..146b35b62 --- /dev/null +++ b/sys/src/libc/9sys/getenv.c @@ -0,0 +1,36 @@ +#include <u.h> +#include <libc.h> + +char* +getenv(char *name) +{ + int r, f; + long s; + char *ans; + char *p, *ep, ename[100]; + + if(strchr(name, '/') != nil) + return nil; + snprint(ename, sizeof ename, "/env/%s", name); + if(strcmp(ename+5, name) != 0) + return nil; + f = open(ename, OREAD); + if(f < 0) + return 0; + s = seek(f, 0, 2); + ans = malloc(s+1); + if(ans) { + setmalloctag(ans, getcallerpc(&name)); + seek(f, 0, 0); + r = read(f, ans, s); + if(r >= 0) { + ep = ans + s - 1; + for(p = ans; p < ep; p++) + if(*p == '\0') + *p = ' '; + ans[s] = '\0'; + } + } + close(f); + return ans; +} diff --git a/sys/src/libc/9sys/getnetconninfo.c b/sys/src/libc/9sys/getnetconninfo.c new file mode 100755 index 000000000..8dbb95f89 --- /dev/null +++ b/sys/src/libc/9sys/getnetconninfo.c @@ -0,0 +1,133 @@ +#include <u.h> +#include <libc.h> + +static char *unknown = "???"; + +static void +getendpoint(char *dir, char *file, char **sysp, char **servp) +{ + int fd, n; + char buf[128]; + char *sys, *serv; + + sys = serv = 0; + + snprint(buf, sizeof buf, "%s/%s", dir, file); + fd = open(buf, OREAD); + if(fd >= 0){ + n = read(fd, buf, sizeof(buf)-1); + if(n>0){ + buf[n-1] = 0; + serv = strchr(buf, '!'); + if(serv){ + *serv++ = 0; + serv = strdup(serv); + } + sys = strdup(buf); + } + close(fd); + } + if(serv == 0) + serv = unknown; + if(sys == 0) + sys = unknown; + *servp = serv; + *sysp = sys; +} + +NetConnInfo* +getnetconninfo(char *dir, int fd) +{ + NetConnInfo *nci; + char *cp; + Dir *d; + char spec[10]; + char path[128]; + char netname[128], *p; + + /* get a directory address via fd */ + if(dir == nil || *dir == 0){ + if(fd2path(fd, path, sizeof(path)) < 0) + return nil; + cp = strrchr(path, '/'); + if(cp == nil) + return nil; + *cp = 0; + dir = path; + } + + nci = mallocz(sizeof *nci, 1); + if(nci == nil) + return nil; + + /* copy connection directory */ + nci->dir = strdup(dir); + if(nci->dir == nil) + goto err; + + /* get netroot */ + nci->root = strdup(dir); + if(nci->root == nil) + goto err; + cp = strchr(nci->root+1, '/'); + if(cp == nil) + goto err; + *cp = 0; + + /* figure out bind spec */ + d = dirstat(nci->dir); + if(d != nil){ + sprint(spec, "#%C%d", d->type, d->dev); + nci->spec = strdup(spec); + } + if(nci->spec == nil) + nci->spec = unknown; + free(d); + + /* get the two end points */ + getendpoint(nci->dir, "local", &nci->lsys, &nci->lserv); + if(nci->lsys == nil || nci->lserv == nil) + goto err; + getendpoint(nci->dir, "remote", &nci->rsys, &nci->rserv); + if(nci->rsys == nil || nci->rserv == nil) + goto err; + + strecpy(netname, netname+sizeof netname, nci->dir); + if((p = strrchr(netname, '/')) != nil) + *p = 0; + if(strncmp(netname, "/net/", 5) == 0) + memmove(netname, netname+5, strlen(netname+5)+1); + nci->laddr = smprint("%s!%s!%s", netname, nci->lsys, nci->lserv); + nci->raddr = smprint("%s!%s!%s", netname, nci->rsys, nci->rserv); + if(nci->laddr == nil || nci->raddr == nil) + goto err; + return nci; +err: + freenetconninfo(nci); + return nil; +} + +static void +xfree(char *x) +{ + if(x == nil || x == unknown) + return; + free(x); +} + +void +freenetconninfo(NetConnInfo *nci) +{ + if(nci == nil) + return; + xfree(nci->root); + xfree(nci->dir); + xfree(nci->spec); + xfree(nci->lsys); + xfree(nci->lserv); + xfree(nci->rsys); + xfree(nci->rserv); + xfree(nci->laddr); + xfree(nci->raddr); + free(nci); +} diff --git a/sys/src/libc/9sys/getpid.c b/sys/src/libc/9sys/getpid.c new file mode 100755 index 000000000..9a9c86c13 --- /dev/null +++ b/sys/src/libc/9sys/getpid.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +int +getpid(void) +{ + char b[20]; + int f; + + memset(b, 0, sizeof(b)); + f = open("#c/pid", 0); + if(f >= 0) { + read(f, b, sizeof(b)); + close(f); + } + return atol(b); +} diff --git a/sys/src/libc/9sys/getppid.c b/sys/src/libc/9sys/getppid.c new file mode 100755 index 000000000..b90b57ee5 --- /dev/null +++ b/sys/src/libc/9sys/getppid.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +int +getppid(void) +{ + char b[20]; + int f; + + memset(b, 0, sizeof(b)); + f = open("/dev/ppid", 0); + if(f >= 0) { + read(f, b, sizeof(b)); + close(f); + } + return atol(b); +} diff --git a/sys/src/libc/9sys/getwd.c b/sys/src/libc/9sys/getwd.c new file mode 100755 index 000000000..ed73cb775 --- /dev/null +++ b/sys/src/libc/9sys/getwd.c @@ -0,0 +1,19 @@ +#include <u.h> +#include <libc.h> + +static char *nsgetwd(char*, int); + +char* +getwd(char *buf, int nbuf) +{ + int n, fd; + + fd = open(".", OREAD); + if(fd < 0) + return nil; + n = fd2path(fd, buf, nbuf); + close(fd); + if(n < 0) + return nil; + return buf; +} diff --git a/sys/src/libc/9sys/iounit.c b/sys/src/libc/9sys/iounit.c new file mode 100755 index 000000000..194b17173 --- /dev/null +++ b/sys/src/libc/9sys/iounit.c @@ -0,0 +1,27 @@ +#include <u.h> +#include <libc.h> + +/* + * Format: + 3 r M 4 (0000000000457def 11 00) 8192 512 /rc/lib/rcmain + */ + +int +iounit(int fd) +{ + int i, cfd; + char buf[128], *args[10]; + + snprint(buf, sizeof buf, "#d/%dctl", fd); + cfd = open(buf, OREAD); + if(cfd < 0) + return 0; + i = read(cfd, buf, sizeof buf-1); + close(cfd); + if(i <= 0) + return 0; + buf[i] = '\0'; + if(tokenize(buf, args, nelem(args)) != nelem(args)) + return 0; + return atoi(args[7]); +} diff --git a/sys/src/libc/9sys/mkfile b/sys/src/libc/9sys/mkfile new file mode 100755 index 000000000..3b7d95e8e --- /dev/null +++ b/sys/src/libc/9sys/mkfile @@ -0,0 +1,64 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +OFILES=\ + abort.$O\ + access.$O\ + announce.$O\ + convD2M.$O\ + convM2D.$O\ + convM2S.$O\ + convS2M.$O\ + cputime.$O\ + ctime.$O\ + dial.$O\ + dirfstat.$O\ + dirfwstat.$O\ + dirmodefmt.$O\ + dirread.$O\ + dirstat.$O\ + dirwstat.$O\ + fcallfmt.$O\ + fork.$O\ + getnetconninfo.$O\ + getenv.$O\ + getpid.$O\ + getppid.$O\ + getwd.$O\ + iounit.$O\ + nsec.$O\ + nulldir.$O\ + postnote.$O\ + privalloc.$O\ + pushssl.$O\ + pushtls.$O\ + putenv.$O\ + qlock.$O\ + read.$O\ + read9pmsg.$O\ + readv.$O\ + rerrstr.$O\ + sbrk.$O\ + setnetmtpt.$O\ + sysfatal.$O\ + syslog.$O\ + sysname.$O\ + time.$O\ + times.$O\ + tm2sec.$O\ + truerand.$O\ + wait.$O\ + waitpid.$O\ + werrstr.$O\ + write.$O\ + writev.$O\ + +HFILES=/sys/include/libc.h + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + +</sys/src/cmd/mksyslib + diff --git a/sys/src/libc/9sys/nsec.c b/sys/src/libc/9sys/nsec.c new file mode 100755 index 000000000..f0e981d04 --- /dev/null +++ b/sys/src/libc/9sys/nsec.c @@ -0,0 +1,75 @@ +#include <u.h> +#include <libc.h> +#include <tos.h> + +static uvlong order = 0x0001020304050607ULL; + +static void +be2vlong(vlong *to, uchar *f) +{ + uchar *t, *o; + int i; + + t = (uchar*)to; + o = (uchar*)ℴ + for(i = 0; i < sizeof order; i++) + t[o[i]] = f[i]; +} + +static int fd = -1; +static struct { + int pid; + int fd; +} fds[64]; + +vlong +nsec(void) +{ + uchar b[8]; + vlong t; + int pid, i, f, tries; + + /* + * Threaded programs may have multiple procs + * with different fd tables, so we may need to open + * /dev/bintime on a per-pid basis + */ + + /* First, look if we've opened it for this particular pid */ + pid = _tos->pid; + do{ + f = -1; + for(i = 0; i < nelem(fds); i++) + if(fds[i].pid == pid){ + f = fds[i].fd; + break; + } + tries = 0; + if(f < 0){ + /* If it's not open for this pid, try the global pid */ + if(fd >= 0) + f = fd; + else{ + /* must open */ + if((f = open("/dev/bintime", OREAD|OCEXEC)) < 0) + return 0; + fd = f; + for(i = 0; i < nelem(fds); i++) + if(fds[i].pid == pid || fds[i].pid == 0){ + fds[i].pid = pid; + fds[i].fd = f; + break; + } + } + } + if(pread(f, b, sizeof b, 0) == sizeof b){ + be2vlong(&t, b); + return t; + } + close(f); + if(i < nelem(fds)) + fds[i].fd = -1; + }while(tries++ == 0); /* retry once */ + USED(tries); + return 0; +} diff --git a/sys/src/libc/9sys/nulldir.c b/sys/src/libc/9sys/nulldir.c new file mode 100755 index 000000000..612725d81 --- /dev/null +++ b/sys/src/libc/9sys/nulldir.c @@ -0,0 +1,9 @@ +#include <u.h> +#include <libc.h> + +void +nulldir(Dir *d) +{ + memset(d, ~0, sizeof(Dir)); + d->name = d->uid = d->gid = d->muid = ""; +} diff --git a/sys/src/libc/9sys/postnote.c b/sys/src/libc/9sys/postnote.c new file mode 100755 index 000000000..46564e9ea --- /dev/null +++ b/sys/src/libc/9sys/postnote.c @@ -0,0 +1,32 @@ +#include <u.h> +#include <libc.h> + +int +postnote(int group, int pid, char *note) +{ + char file[128]; + int f, r; + + switch(group) { + case PNPROC: + sprint(file, "/proc/%d/note", pid); + break; + case PNGROUP: + sprint(file, "/proc/%d/notepg", pid); + break; + default: + return -1; + } + + f = open(file, OWRITE); + if(f < 0) + return -1; + + r = strlen(note); + if(write(f, note, r) != r) { + close(f); + return -1; + } + close(f); + return 0; +} diff --git a/sys/src/libc/9sys/privalloc.c b/sys/src/libc/9sys/privalloc.c new file mode 100755 index 000000000..907485e2f --- /dev/null +++ b/sys/src/libc/9sys/privalloc.c @@ -0,0 +1,45 @@ +#include <u.h> +#include <libc.h> + +static Lock privlock; +static int privinit; +static void **privs; + +extern void **_privates; +extern int _nprivates; + +void ** +privalloc(void) +{ + void **p; + int i; + + lock(&privlock); + if(!privinit){ + privinit = 1; + if(_nprivates){ + _privates[0] = 0; + for(i = 1; i < _nprivates; i++) + _privates[i] = &_privates[i - 1]; + privs = &_privates[i - 1]; + } + } + p = privs; + if(p != nil){ + privs = *p; + *p = nil; + } + unlock(&privlock); + return p; +} + +void +privfree(void **p) +{ + lock(&privlock); + if(p != nil && privinit){ + *p = privs; + privs = p; + } + unlock(&privlock); +} diff --git a/sys/src/libc/9sys/pushssl.c b/sys/src/libc/9sys/pushssl.c new file mode 100755 index 000000000..8817dd1c3 --- /dev/null +++ b/sys/src/libc/9sys/pushssl.c @@ -0,0 +1,44 @@ +#include <u.h> +#include <libc.h> + +/* + * Since the SSL device uses decimal file descriptors to name channels, + * it is impossible for a user-level file server to stand in for the kernel device. + * Thus we hard-code #D rather than use /net/ssl. + */ + +int +pushssl(int fd, char *alg, char *secin, char *secout, int *cfd) +{ + char buf[8]; + char dname[64]; + int n, data, ctl; + + ctl = open("#D/ssl/clone", ORDWR); + if(ctl < 0) + return -1; + n = read(ctl, buf, sizeof(buf)-1); + if(n < 0) + goto error; + buf[n] = 0; + sprint(dname, "#D/ssl/%s/data", buf); + data = open(dname, ORDWR); + if(data < 0) + goto error; + if(fprint(ctl, "fd %d", fd) < 0 || + fprint(ctl, "secretin %s", secin) < 0 || + fprint(ctl, "secretout %s", secout) < 0 || + fprint(ctl, "alg %s", alg) < 0){ + close(data); + goto error; + } + close(fd); + if(cfd != 0) + *cfd = ctl; + else + close(ctl); + return data; +error: + close(ctl); + return -1; +} diff --git a/sys/src/libc/9sys/pushtls.c b/sys/src/libc/9sys/pushtls.c new file mode 100755 index 000000000..038aad748 --- /dev/null +++ b/sys/src/libc/9sys/pushtls.c @@ -0,0 +1,99 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <mp.h> +#include <libsec.h> + +enum { + TLSFinishedLen = 12, + HFinished = 20, +}; + +static int +finished(int hand, int isclient) +{ + int i, n; + uchar buf[500], buf2[500]; + + buf[0] = HFinished; + buf[1] = TLSFinishedLen>>16; + buf[2] = TLSFinishedLen>>8; + buf[3] = TLSFinishedLen; + n = TLSFinishedLen+4; + + for(i=0; i<2; i++){ + if(i==0) + memmove(buf+4, "client finished", TLSFinishedLen); + else + memmove(buf+4, "server finished", TLSFinishedLen); + if(isclient == 1-i){ + if(write(hand, buf, n) != n) + return -1; + }else{ + if(readn(hand, buf2, n) != n || memcmp(buf,buf2,n) != 0) + return -1; + } + } + return 1; +} + + +// given a plain fd and secrets established beforehand, return encrypted connection +int +pushtls(int fd, char *hashalg, char *encalg, int isclient, char *secret, char *dir) +{ + char buf[8]; + char dname[64]; + int n, data, ctl, hand; + + // open a new filter; get ctl fd + data = hand = -1; + // /net/tls uses decimal file descriptors to name channels, hence a + // user-level file server can't stand in for #a; may as well hard-code it. + ctl = open("#a/tls/clone", ORDWR); + if(ctl < 0) + goto error; + n = read(ctl, buf, sizeof(buf)-1); + if(n < 0) + goto error; + buf[n] = 0; + if(dir) + sprint(dir, "#a/tls/%s", buf); + + // get application fd + sprint(dname, "#a/tls/%s/data", buf); + data = open(dname, ORDWR); + if(data < 0) + goto error; + + // get handshake fd + sprint(dname, "#a/tls/%s/hand", buf); + hand = open(dname, ORDWR); + if(hand < 0) + goto error; + + // speak a minimal handshake + if(fprint(ctl, "fd %d 0x301", fd) < 0 || + fprint(ctl, "version 0x301") < 0 || + fprint(ctl, "secret %s %s %d %s", hashalg, encalg, isclient, secret) < 0 || + fprint(ctl, "changecipher") < 0 || + finished(hand, isclient) < 0 || + fprint(ctl, "opened") < 0){ + close(hand); + hand = -1; + goto error; + } + close(ctl); + close(hand); + close(fd); + return data; + +error: + if(data>=0) + close(data); + if(ctl>=0) + close(ctl); + if(hand>=0) + close(hand); + return -1; +} diff --git a/sys/src/libc/9sys/putenv.c b/sys/src/libc/9sys/putenv.c new file mode 100755 index 000000000..de2389482 --- /dev/null +++ b/sys/src/libc/9sys/putenv.c @@ -0,0 +1,26 @@ +#include <u.h> +#include <libc.h> + +int +putenv(char *name, char *val) +{ + int f; + char ename[100]; + long s; + + if(strchr(name, '/') != nil) + return -1; + snprint(ename, sizeof ename, "/env/%s", name); + if(strcmp(ename+5, name) != 0) + return -1; + f = create(ename, OWRITE, 0664); + if(f < 0) + return -1; + s = strlen(val); + if(write(f, val, s) != s){ + close(f); + return -1; + } + close(f); + return 0; +} diff --git a/sys/src/libc/9sys/qlock.c b/sys/src/libc/9sys/qlock.c new file mode 100755 index 000000000..fb2d80238 --- /dev/null +++ b/sys/src/libc/9sys/qlock.c @@ -0,0 +1,363 @@ +#include <u.h> +#include <libc.h> + +static struct { + QLp *p; + QLp x[1024]; +} ql = { + ql.x +}; + +enum +{ + Queuing, + QueuingR, + QueuingW, + Sleeping, +}; + +static void* (*_rendezvousp)(void*, void*) = rendezvous; + +/* this gets called by the thread library ONLY to get us to use its rendezvous */ +void +_qlockinit(void* (*r)(void*, void*)) +{ + _rendezvousp = r; +} + +/* find a free shared memory location to queue ourselves in */ +static QLp* +getqlp(void) +{ + QLp *p, *op; + + op = ql.p; + for(p = op+1; ; p++){ + if(p == &ql.x[nelem(ql.x)]) + p = ql.x; + if(p == op) + abort(); + if(_tas(&(p->inuse)) == 0){ + ql.p = p; + p->next = nil; + break; + } + } + return p; +} + +void +qlock(QLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return; + } + + + /* chain into waiting list */ + mp = getqlp(); + p = q->tail; + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->state = Queuing; + unlock(&q->lock); + + /* wait */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + ; + mp->inuse = 0; +} + +void +qunlock(QLock *q) +{ + QLp *p; + + lock(&q->lock); + if (q->locked == 0) + fprint(2, "qunlock called with qlock not held, from %#p\n", + getcallerpc(&q)); + p = q->head; + if(p != nil){ + /* wakeup head waiting process */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)(p, (void*)0x12345) == (void*)~0) + ; + return; + } + q->locked = 0; + unlock(&q->lock); +} + +int +canqlock(QLock *q) +{ + if(!canlock(&q->lock)) + return 0; + if(!q->locked){ + q->locked = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +rlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->writer == 0 && q->head == nil){ + /* no writer, go for it */ + q->readers++; + unlock(&q->lock); + return; + } + + mp = getqlp(); + p = q->tail; + if(p == 0) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingR; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + ; + mp->inuse = 0; +} + +int +canrlock(RWLock *q) +{ + lock(&q->lock); + if (q->writer == 0 && q->head == nil) { + /* no writer; go for it */ + q->readers++; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +runlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->readers <= 0) + abort(); + p = q->head; + if(--(q->readers) > 0 || p == nil){ + unlock(&q->lock); + return; + } + + /* start waiting writer */ + if(p->state != QueuingW) + abort(); + q->head = p->next; + if(q->head == 0) + q->tail = 0; + q->writer = 1; + unlock(&q->lock); + + /* wakeup waiter */ + while((*_rendezvousp)(p, 0) == (void*)~0) + ; +} + +void +wlock(RWLock *q) +{ + QLp *p, *mp; + + lock(&q->lock); + if(q->readers == 0 && q->writer == 0){ + /* noone waiting, go for it */ + q->writer = 1; + unlock(&q->lock); + return; + } + + /* wait */ + p = q->tail; + mp = getqlp(); + if(p == nil) + q->head = mp; + else + p->next = mp; + q->tail = mp; + mp->next = nil; + mp->state = QueuingW; + unlock(&q->lock); + + /* wait in kernel */ + while((*_rendezvousp)(mp, (void*)1) == (void*)~0) + ; + mp->inuse = 0; +} + +int +canwlock(RWLock *q) +{ + lock(&q->lock); + if (q->readers == 0 && q->writer == 0) { + /* no one waiting; go for it */ + q->writer = 1; + unlock(&q->lock); + return 1; + } + unlock(&q->lock); + return 0; +} + +void +wunlock(RWLock *q) +{ + QLp *p; + + lock(&q->lock); + if(q->writer == 0) + abort(); + p = q->head; + if(p == nil){ + q->writer = 0; + unlock(&q->lock); + return; + } + if(p->state == QueuingW){ + /* start waiting writer */ + q->head = p->next; + if(q->head == nil) + q->tail = nil; + unlock(&q->lock); + while((*_rendezvousp)(p, 0) == (void*)~0) + ; + return; + } + + if(p->state != QueuingR) + abort(); + + /* wake waiting readers */ + while(q->head != nil && q->head->state == QueuingR){ + p = q->head; + q->head = p->next; + q->readers++; + while((*_rendezvousp)(p, 0) == (void*)~0) + ; + } + if(q->head == nil) + q->tail = nil; + q->writer = 0; + unlock(&q->lock); +} + +void +rsleep(Rendez *r) +{ + QLp *t, *me; + + if(!r->l) + abort(); + lock(&r->l->lock); + /* we should hold the qlock */ + if(!r->l->locked) + abort(); + + /* add ourselves to the wait list */ + me = getqlp(); + me->state = Sleeping; + if(r->head == nil) + r->head = me; + else + r->tail->next = me; + me->next = nil; + r->tail = me; + + /* pass the qlock to the next guy */ + t = r->l->head; + if(t){ + r->l->head = t->next; + if(r->l->head == nil) + r->l->tail = nil; + unlock(&r->l->lock); + while((*_rendezvousp)(t, (void*)0x12345) == (void*)~0) + ; + }else{ + r->l->locked = 0; + unlock(&r->l->lock); + } + + /* wait for a wakeup */ + while((*_rendezvousp)(me, (void*)1) == (void*)~0) + ; + me->inuse = 0; +} + +int +rwakeup(Rendez *r) +{ + QLp *t; + + /* + * take off wait and put on front of queue + * put on front so guys that have been waiting will not get starved + */ + + if(!r->l) + abort(); + lock(&r->l->lock); + if(!r->l->locked) + abort(); + + t = r->head; + if(t == nil){ + unlock(&r->l->lock); + return 0; + } + + r->head = t->next; + if(r->head == nil) + r->tail = nil; + + t->next = r->l->head; + r->l->head = t; + if(r->l->tail == nil) + r->l->tail = t; + + t->state = Queuing; + unlock(&r->l->lock); + return 1; +} + +int +rwakeupall(Rendez *r) +{ + int i; + + for(i=0; rwakeup(r); i++) + ; + return i; +} + diff --git a/sys/src/libc/9sys/read.c b/sys/src/libc/9sys/read.c new file mode 100755 index 000000000..2119ab2ac --- /dev/null +++ b/sys/src/libc/9sys/read.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +long +read(int fd, void *buf, long n) +{ + return pread(fd, buf, n, -1LL); +} diff --git a/sys/src/libc/9sys/read9pmsg.c b/sys/src/libc/9sys/read9pmsg.c new file mode 100755 index 000000000..9e90ec5d6 --- /dev/null +++ b/sys/src/libc/9sys/read9pmsg.c @@ -0,0 +1,31 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +read9pmsg(int fd, void *abuf, uint n) +{ + int m, len; + uchar *buf; + + buf = abuf; + + /* read count */ + m = readn(fd, buf, BIT32SZ); + if(m != BIT32SZ){ + if(m < 0) + return -1; + return 0; + } + + len = GBIT32(buf); + if(len <= BIT32SZ || len > n){ + werrstr("bad length in 9P2000 message header"); + return -1; + } + len -= BIT32SZ; + m = readn(fd, buf+BIT32SZ, len); + if(m < len) + return 0; + return BIT32SZ+m; +} diff --git a/sys/src/libc/9sys/readv.c b/sys/src/libc/9sys/readv.c new file mode 100755 index 000000000..a0dc10aaf --- /dev/null +++ b/sys/src/libc/9sys/readv.c @@ -0,0 +1,49 @@ +#include <u.h> +#include <libc.h> + +static +long +ioreadv(int fd, IOchunk *io, int nio, vlong offset) +{ + int i; + long m, n, tot; + char *buf, *p; + + tot = 0; + for(i=0; i<nio; i++) + tot += io[i].len; + buf = malloc(tot); + if(buf == nil) + return -1; + + tot = pread(fd, buf, tot, offset); + + p = buf; + n = tot; + for(i=0; i<nio; i++){ + if(n <= 0) + break; + m = io->len; + if(m > n) + m = n; + memmove(io->addr, p, m); + n -= m; + p += m; + io++; + } + + free(buf); + return tot; +} + +long +readv(int fd, IOchunk *io, int nio) +{ + return ioreadv(fd, io, nio, -1LL); +} + +long +preadv(int fd, IOchunk *io, int nio, vlong off) +{ + return ioreadv(fd, io, nio, off); +} diff --git a/sys/src/libc/9sys/rerrstr.c b/sys/src/libc/9sys/rerrstr.c new file mode 100755 index 000000000..c64cd4940 --- /dev/null +++ b/sys/src/libc/9sys/rerrstr.c @@ -0,0 +1,13 @@ +#include <u.h> +#include <libc.h> + +void +rerrstr(char *buf, uint nbuf) +{ + char tmp[ERRMAX]; + + tmp[0] = 0; + errstr(tmp, sizeof tmp); + utfecpy(buf, buf+nbuf, tmp); + errstr(tmp, sizeof tmp); +} diff --git a/sys/src/libc/9sys/sbrk.c b/sys/src/libc/9sys/sbrk.c new file mode 100755 index 000000000..88b593e11 --- /dev/null +++ b/sys/src/libc/9sys/sbrk.c @@ -0,0 +1,35 @@ +#include <u.h> +#include <libc.h> + +extern char end[]; +static char *bloc = { end }; +extern int brk_(void*); + +enum +{ + Round = 7 +}; + +int +brk(void *p) +{ + uintptr bl; + + bl = ((uintptr)p + Round) & ~Round; + if(brk_((void*)bl) < 0) + return -1; + bloc = (char*)bl; + return 0; +} + +void* +sbrk(ulong n) +{ + uintptr bl; + + bl = ((uintptr)bloc + Round) & ~Round; + if(brk_((void*)(bl+n)) < 0) + return (void*)-1; + bloc = (char*)bl + n; + return (void*)bl; +} diff --git a/sys/src/libc/9sys/setnetmtpt.c b/sys/src/libc/9sys/setnetmtpt.c new file mode 100755 index 000000000..3d984f08f --- /dev/null +++ b/sys/src/libc/9sys/setnetmtpt.c @@ -0,0 +1,16 @@ +#include <u.h> +#include <libc.h> + +void +setnetmtpt(char *net, int n, char *x) +{ + if(x == nil) + x = "/net"; + + if(*x == '/'){ + strncpy(net, x, n); + net[n-1] = 0; + } else { + snprint(net, n, "/net%s", x); + } +} diff --git a/sys/src/libc/9sys/sysfatal.c b/sys/src/libc/9sys/sysfatal.c new file mode 100755 index 000000000..e2cef6c48 --- /dev/null +++ b/sys/src/libc/9sys/sysfatal.c @@ -0,0 +1,28 @@ +#include <u.h> +#include <libc.h> + + +static void +_sysfatalimpl(char *fmt, va_list arg) +{ + char buf[1024]; + + vseprint(buf, buf+sizeof(buf), fmt, arg); + if(argv0) + fprint(2, "%s: %s\n", argv0, buf); + else + fprint(2, "%s\n", buf); + exits(buf); +} + +void (*_sysfatal)(char *fmt, va_list arg) = _sysfatalimpl; + +void +sysfatal(char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + (*_sysfatal)(fmt, arg); + va_end(arg); +} diff --git a/sys/src/libc/9sys/syslog.c b/sys/src/libc/9sys/syslog.c new file mode 100755 index 000000000..828ad04a7 --- /dev/null +++ b/sys/src/libc/9sys/syslog.c @@ -0,0 +1,117 @@ +#include <u.h> +#include <libc.h> + +static struct +{ + int fd; + int consfd; + char *name; + Dir *d; + Dir *consd; + Lock; +} sl = +{ + -1, -1, +}; + +static void +_syslogopen(void) +{ + char buf[1024]; + + if(sl.fd >= 0) + close(sl.fd); + snprint(buf, sizeof(buf), "/sys/log/%s", sl.name); + sl.fd = open(buf, OWRITE|OCEXEC); +} + +/* + * Print + * sysname: time: mesg + * on /sys/log/logname. + * If cons or log file can't be opened, print on the system console, too. + */ +void +syslog(int cons, char *logname, char *fmt, ...) +{ + char buf[1024]; + char *ctim, *p; + va_list arg; + int n; + Dir *d; + char err[ERRMAX]; + + err[0] = '\0'; + errstr(err, sizeof err); + lock(&sl); + + /* + * paranoia makes us stat to make sure a fork+close + * hasn't broken our fd's + */ + d = dirfstat(sl.fd); + if(sl.fd < 0 + || sl.name == nil + || strcmp(sl.name, logname)!=0 + || sl.d == nil + || d == nil + || d->dev != sl.d->dev + || d->type != sl.d->type + || d->qid.path != sl.d->qid.path){ + free(sl.name); + sl.name = strdup(logname); + if(sl.name == nil) + cons = 1; + else{ + _syslogopen(); + if(sl.fd < 0) + cons = 1; + free(sl.d); + sl.d = d; + d = nil; /* don't free it */ + } + } + free(d); + if(cons){ + d = dirfstat(sl.consfd); + if(sl.consfd < 0 + || d == nil + || sl.consd == nil + || d->dev != sl.consd->dev + || d->type != sl.consd->type + || d->qid.path != sl.consd->qid.path){ + sl.consfd = open("#c/cons", OWRITE|OCEXEC); + free(sl.consd); + sl.consd = d; + d = nil; /* don't free it */ + } + free(d); + } + + if(fmt == nil){ + unlock(&sl); + return; + } + + ctim = ctime(time(0)); + werrstr(err); + p = buf + snprint(buf, sizeof(buf)-1, "%s ", sysname()); + strncpy(p, ctim+4, 15); + p += 15; + *p++ = ' '; + va_start(arg, fmt); + p = vseprint(p, buf+sizeof(buf)-1, fmt, arg); + va_end(arg); + *p++ = '\n'; + n = p - buf; + + if(sl.fd >= 0){ + seek(sl.fd, 0, 2); + write(sl.fd, buf, n); + } + + if(cons && sl.consfd >=0) + write(sl.consfd, buf, n); + + unlock(&sl); +} diff --git a/sys/src/libc/9sys/sysname.c b/sys/src/libc/9sys/sysname.c new file mode 100755 index 000000000..1854ddceb --- /dev/null +++ b/sys/src/libc/9sys/sysname.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> + +char* +sysname(void) +{ + int f, n; + static char b[128]; + + if(b[0]) + return b; + + f = open("#c/sysname", 0); + if(f >= 0) { + n = read(f, b, sizeof(b)-1); + if(n > 0) + b[n] = 0; + close(f); + } + return b; +} diff --git a/sys/src/libc/9sys/time.c b/sys/src/libc/9sys/time.c new file mode 100755 index 000000000..3e5f83b04 --- /dev/null +++ b/sys/src/libc/9sys/time.c @@ -0,0 +1,51 @@ +#include <u.h> +#include <libc.h> + + +/* + * After a fork with fd's copied, both fd's are pointing to + * the same Chan structure. Since the offset is kept in the Chan + * structure, the seek's and read's in the two processes can + * compete at moving the offset around. Hence the unusual loop + * in the middle of this routine. + */ +static long +oldtime(long *tp) +{ + char b[20]; + static int f = -1; + int i, retries; + long t; + + memset(b, 0, sizeof(b)); + for(retries = 0; retries < 100; retries++){ + if(f < 0) + f = open("/dev/time", OREAD|OCEXEC); + if(f < 0) + break; + if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){ + close(f); + f = -1; + } else { + if(i != 0) + break; + } + } + t = atol(b); + if(tp) + *tp = t; + return t; +} + +long +time(long *tp) +{ + vlong t; + + t = nsec()/1000000000LL; + if(t == 0) + t = oldtime(0); + if(tp != nil) + *tp = t; + return t; +} diff --git a/sys/src/libc/9sys/times.c b/sys/src/libc/9sys/times.c new file mode 100755 index 000000000..b8303474f --- /dev/null +++ b/sys/src/libc/9sys/times.c @@ -0,0 +1,60 @@ +#include <u.h> +#include <libc.h> + +static +char* +skip(char *p) +{ + + while(*p == ' ') + p++; + while(*p != ' ' && *p != 0) + p++; + return p; +} + +/* + * after a fork with fd's copied, both fd's are pointing to + * the same Chan structure. Since the offset is kept in the Chan + * structure, the seek's and read's in the two processes can be + * are competing moving the offset around. Hence the unusual loop + * in the middle of this routine. + */ +long +times(long *t) +{ + char b[200], *p; + static int f = -1; + int i, retries; + ulong r; + + memset(b, 0, sizeof(b)); + for(retries = 0; retries < 100; retries++){ + if(f < 0) + f = open("/dev/cputime", OREAD|OCEXEC); + if(f < 0) + break; + if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof(b))) < 0){ + close(f); + f = -1; + } else { + if(i != 0) + break; + } + } + p = b; + if(t) + t[0] = atol(p); + p = skip(p); + if(t) + t[1] = atol(p); + p = skip(p); + r = atol(p); + if(t){ + p = skip(p); + t[2] = atol(p); + p = skip(p); + t[3] = atol(p); + } + return r; +} diff --git a/sys/src/libc/9sys/tm2sec.c b/sys/src/libc/9sys/tm2sec.c new file mode 100755 index 000000000..223d3f1d9 --- /dev/null +++ b/sys/src/libc/9sys/tm2sec.c @@ -0,0 +1,194 @@ +#include <u.h> +#include <libc.h> + +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int y) +{ + if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0)) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 GMT + * and convert to our timezone. + */ +long +tm2sec(Tm *tm) +{ + long secs; + int i, yday, year, *d2m; + + if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0) + readtimezone(); + secs = 0; + + /* + * seconds per year + */ + year = tm->year + 1900; + for(i = 1970; i < year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * if mday is set, use mon and mday to compute yday + */ + if(tm->mday){ + yday = 0; + d2m = yrsize(year); + for(i=0; i<tm->mon; i++) + yday += d2m[i+1]; + yday += tm->mday-1; + }else{ + yday = tm->yday; + } + secs += yday * SEC2DAY; + + /* + * hours, minutes, seconds + */ + secs += tm->hour * SEC2HOUR; + secs += tm->min * SEC2MIN; + secs += tm->sec; + + /* + * Only handles zones mentioned in /env/timezone, + * but things get too ambiguous otherwise. + */ + if(strcmp(tm->zone, timezone.stname) == 0) + secs -= timezone.stdiff; + else if(strcmp(tm->zone, timezone.dlname) == 0) + secs -= timezone.dldiff; + if(secs < 0) + secs = 0; + return secs; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)) + goto error; + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i<TZSIZE; i++) { + if(rd_long(&p, &timezone.dlpairs[i])) + goto error; + if(timezone.dlpairs[i] == 0) + return; + } + +error: + timezone.stdiff = 0; + strcpy(timezone.stname, "GMT"); + timezone.dlpairs[0] = 0; +} + +static int +rd_name(char **f, char *p) +{ + int c, i; + + for(;;) { + c = *(*f)++; + if(c != ' ' && c != '\n') + break; + } + for(i=0; i<3; i++) { + if(c == ' ' || c == '\n') + return 1; + *p++ = c; + c = *(*f)++; + } + if(c != ' ' && c != '\n') + return 1; + *p = 0; + return 0; +} + +static int +rd_long(char **f, long *p) +{ + int c, s; + long l; + + s = 0; + for(;;) { + c = *(*f)++; + if(c == '-') { + s++; + continue; + } + if(c != ' ' && c != '\n') + break; + } + if(c == 0) { + *p = 0; + return 0; + } + l = 0; + for(;;) { + if(c == ' ' || c == '\n') + break; + if(c < '0' || c > '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; +} diff --git a/sys/src/libc/9sys/truerand.c b/sys/src/libc/9sys/truerand.c new file mode 100755 index 000000000..10a0f14de --- /dev/null +++ b/sys/src/libc/9sys/truerand.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +ulong +truerand(void) +{ + ulong x; + static int randfd = -1; + + if(randfd < 0) + randfd = open("/dev/random", OREAD|OCEXEC); + if(randfd < 0) + sysfatal("can't open /dev/random"); + if(read(randfd, &x, sizeof(x)) != sizeof(x)) + sysfatal("can't read /dev/random"); + return x; +} diff --git a/sys/src/libc/9sys/wait.c b/sys/src/libc/9sys/wait.c new file mode 100755 index 000000000..e2ac817ea --- /dev/null +++ b/sys/src/libc/9sys/wait.c @@ -0,0 +1,32 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +Waitmsg* +wait(void) +{ + int n, l; + char buf[512], *fld[5]; + Waitmsg *w; + + n = await(buf, sizeof buf-1); + if(n < 0) + return nil; + buf[n] = '\0'; + if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){ + werrstr("couldn't parse wait message"); + return nil; + } + l = strlen(fld[4])+1; + w = malloc(sizeof(Waitmsg)+l); + if(w == nil) + return nil; + w->pid = atoi(fld[0]); + w->time[0] = atoi(fld[1]); + w->time[1] = atoi(fld[2]); + w->time[2] = atoi(fld[3]); + w->msg = (char*)&w[1]; + memmove(w->msg, fld[4], l); + return w; +} + diff --git a/sys/src/libc/9sys/waitpid.c b/sys/src/libc/9sys/waitpid.c new file mode 100755 index 000000000..098c428cf --- /dev/null +++ b/sys/src/libc/9sys/waitpid.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> +#include <fcall.h> + +int +waitpid(void) +{ + int n; + char buf[512], *fld[5]; + + n = await(buf, sizeof buf-1); + if(n <= 0) + return -1; + buf[n] = '\0'; + if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){ + werrstr("couldn't parse wait message"); + return -1; + } + return atoi(fld[0]); +} + diff --git a/sys/src/libc/9sys/werrstr.c b/sys/src/libc/9sys/werrstr.c new file mode 100755 index 000000000..da542aa17 --- /dev/null +++ b/sys/src/libc/9sys/werrstr.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +void +werrstr(char *fmt, ...) +{ + va_list arg; + char buf[ERRMAX]; + + va_start(arg, fmt); + vseprint(buf, buf+ERRMAX, fmt, arg); + va_end(arg); + errstr(buf, ERRMAX); +} diff --git a/sys/src/libc/9sys/write.c b/sys/src/libc/9sys/write.c new file mode 100755 index 000000000..5bbd3064e --- /dev/null +++ b/sys/src/libc/9sys/write.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +long +write(int fd, void *buf, long n) +{ + return pwrite(fd, buf, n, -1LL); +} diff --git a/sys/src/libc/9sys/writev.c b/sys/src/libc/9sys/writev.c new file mode 100755 index 000000000..e3692db27 --- /dev/null +++ b/sys/src/libc/9sys/writev.c @@ -0,0 +1,42 @@ +#include <u.h> +#include <libc.h> + +static +long +iowritev(int fd, IOchunk *io, int nio, vlong offset) +{ + int i; + long tot; + char *buf, *p; + + tot = 0; + for(i=0; i<nio; i++) + tot += io[i].len; + buf = malloc(tot); + if(buf == nil) + return -1; + + p = buf; + for(i=0; i<nio; i++){ + memmove(p, io->addr, io->len); + p += io->len; + io++; + } + + tot = pwrite(fd, buf, tot, offset); + + free(buf); + return tot; +} + +long +writev(int fd, IOchunk *io, int nio) +{ + return iowritev(fd, io, nio, -1LL); +} + +long +pwritev(int fd, IOchunk *io, int nio, vlong off) +{ + return iowritev(fd, io, nio, off); +} diff --git a/sys/src/libc/9syscall/mkfile b/sys/src/libc/9syscall/mkfile new file mode 100755 index 000000000..081310e34 --- /dev/null +++ b/sys/src/libc/9syscall/mkfile @@ -0,0 +1,145 @@ +NPROC=1 +</$objtype/mkfile + +install:V: + SYS=`{sed '/^#define._X[123]/d; s/#define.([A-Z0-9_]*).*/\1/' sys.h} + for(I in $SYS) { + i=`{echo $I|tr A-Z a-z} + n=`{sed -n '/[ ]'$I'[ ]/s/.* //p' sys.h} + if(~ $i exits) i=_exits + {switch($objtype){ + case 68000 68020 + echo TEXT $i'(SB)', 1, '$0' + echo MOVL '$'$n, R0 + echo TRAP '$0' + echo RTS + case mips + echo TEXT $i'(SB)', 1, '$0' + echo MOVW R1, '0(FP)' + echo MOVW '$'$n, R1 + echo SYSCALL + if(~ $i seek) { + echo 'MOVW $-1,R5 + BNE R1,R5,4(PC) + MOVW a+0(FP),R5 + MOVW R1,0(R5) + MOVW R1,4(R5)' + } + echo RET + case mips2 + echo TEXT $i'(SB)', 1, '$0' + echo MOVW R1, '0(FP)' + echo MOVW '$'$n, R1 + echo ADD '$4',R29 + echo SYSCALL + echo ADD '$-4',R29 + echo RET + case spim + echo TEXT $i'(SB)', 1, '$0' + echo MOVW R1, '0(FP)' + echo MOVW '$'$n, R1 + echo ADD '$4',R29 + echo SYSCALL + echo ADD '$-4',R29 + if(~ $i seek) { # untested so far - geoff + echo 'MOVW $-1,R5 + BNE R1,R5,4(PC) + MOVW a+0(FP),R5 + MOVW R1,0(R5) + MOVW R1,4(R5)' + } + echo RET + case 386 + echo TEXT $i'(SB)', 1, '$0' + echo MOVL '$'$n, AX + echo INT '$'64 + if(~ $i seek) { + echo 'CMPL AX,$-1 + JNE 4(PC) + MOVL a+0(FP),CX + MOVL AX,0(CX) + MOVL AX,4(CX)' + } + echo RET + case amd64 + if(~ $i seek) + echo TEXT _seek'(SB)', 1, '$0' + if not + echo TEXT $i'(SB)', 1, '$0' + echo MOVQ RARG, 'a0+0(FP)' + echo MOVQ '$'$n, RARG + echo SYSCALL + echo RET + case sparc sparc64 + echo TEXT $i'(SB)', 1, '$0' + echo MOVW R7, '0(FP)' + echo MOVW '$'$n, R7 + echo TA R0 + if(~ $i seek) { + echo 'CMP R7,$-1 + BNE 4(PC) + MOVW a+0(FP),R8 + MOVW R7,0(R8) + MOVW R7,4(R8)' + } + echo RETURN + case 3210 + echo TEXT $i'(SB)', 1, '$0' + echo MOVW R3, '0(FP)' + echo MOVW '$'$n, R3 + echo WORD '$0x06000000' + echo RETURN + case 29000 + echo TEXT $i'(SB)', 1, '$0' + echo MOVL R69, '0(FP)' + echo MOVL '$'$n, R69 + echo EMULATE 0 + echo RET + case arm + echo TEXT $i'(SB)', 1, '$0' + echo MOVW R0, '0(FP)' + echo MOVW '$'$n, R0 + echo SWI 0 + if(~ $i seek) { + echo 'CMP $-1,R0 + BNE 4(PC) + MOVW a+0(FP),R1 + MOVW R0,0(R1) + MOVW R0,4(R1)' + } + echo RET + case power + echo TEXT $i'(SB)', 1, '$0' + echo MOVW R3, '0(FP)' + echo MOVW '$'$n, R3 + echo SYSCALL + if(~ $i seek) { + echo 'CMP R3,$-1 + BNE 4(PC) + MOVW a+0(FP),R8 + MOVW R3,0(R8) + MOVW R3,4(R8)' + } + echo RETURN + case alpha + j=$i + if(~ $i seek) j=_seek + echo TEXT $j'(SB)', 1, '$0' + echo MOVL R0, '0(FP)' + echo MOVQ '$'$n, R0 + echo CALL_PAL '$'0x83 + echo RET + }} > $i.s + $AS $i.s + } + ar vu /$objtype/lib/libc.a *.$O + rm -f *.$O *.s + +nuke clean:V: + rm -f *.[$OS] + +installall:V: + for(objtype in $CPUS) mk install + +update:V: + update $UPDATEFLAGS mkfile sys.h diff --git a/sys/src/libc/9syscall/sys.h b/sys/src/libc/9syscall/sys.h new file mode 100755 index 000000000..105baf89c --- /dev/null +++ b/sys/src/libc/9syscall/sys.h @@ -0,0 +1,50 @@ +#define SYSR1 0 +#define _ERRSTR 1 +#define BIND 2 +#define CHDIR 3 +#define CLOSE 4 +#define DUP 5 +#define ALARM 6 +#define EXEC 7 +#define EXITS 8 +#define _FSESSION 9 +#define FAUTH 10 +#define _FSTAT 11 +#define SEGBRK 12 +#define _MOUNT 13 +#define OPEN 14 +#define _READ 15 +#define OSEEK 16 +#define SLEEP 17 +#define _STAT 18 +#define RFORK 19 +#define _WRITE 20 +#define PIPE 21 +#define CREATE 22 +#define FD2PATH 23 +#define BRK_ 24 +#define REMOVE 25 +#define _WSTAT 26 +#define _FWSTAT 27 +#define NOTIFY 28 +#define NOTED 29 +#define SEGATTACH 30 +#define SEGDETACH 31 +#define SEGFREE 32 +#define SEGFLUSH 33 +#define RENDEZVOUS 34 +#define UNMOUNT 35 +#define _WAIT 36 +#define SEMACQUIRE 37 +#define SEMRELEASE 38 +#define SEEK 39 +#define FVERSION 40 +#define ERRSTR 41 +#define STAT 42 +#define FSTAT 43 +#define WSTAT 44 +#define FWSTAT 45 +#define MOUNT 46 +#define AWAIT 47 +#define PREAD 50 +#define PWRITE 51 diff --git a/sys/src/libc/alpha/_seek.c b/sys/src/libc/alpha/_seek.c new file mode 100755 index 000000000..0aa741a66 --- /dev/null +++ b/sys/src/libc/alpha/_seek.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +extern int _seek(vlong*, int, vlong, int); + +vlong +seek(int fd, vlong o, int p) +{ + vlong l; + + if(_seek(&l, fd, o, p) < 0) + l = -1LL; + return l; +} diff --git a/sys/src/libc/alpha/argv0.s b/sys/src/libc/alpha/argv0.s new file mode 100755 index 000000000..8d9f9b29b --- /dev/null +++ b/sys/src/libc/alpha/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/alpha/atom.s b/sys/src/libc/alpha/atom.s new file mode 100755 index 000000000..e9dbd14aa --- /dev/null +++ b/sys/src/libc/alpha/atom.s @@ -0,0 +1,67 @@ +TEXT ainc(SB),$-8 /* long ainc(long *); */ + MOVQ R0, R1 /* p */ +inc1: + MOVLL (R1), R2 /* *p */ + ADDL $1, R2 + MOVQ R2, R0 /* copy to return */ + MOVLC R2, (R1) /* (*p)++ */ + BEQ R2, inc1 /* write failed, retry */ + RET + +TEXT adec(SB),$-8 /* long ainc(long *); */ + MOVQ R0, R1 /* p */ +dec1: + MOVLL (R1), R2 /* *p */ + SUBL $1, R2 + MOVQ R2, R0 /* copy to return */ + MOVLC R2, (R1) /* (*p)++ */ + BEQ R2, dec1 /* write failed, retry */ + RET + +TEXT _xinc(SB), $-8 + MOVQ R0, R1 /* p */ +xinc1: + MOVLL (R1), R0 /* *p */ + ADDL $1, R0 + MOVLC R0, (R1) /* (*p)++ */ + BEQ R0, xinc1 /* write failed, retry */ + RET + +TEXT _xdec(SB), $-8 + MOVQ R0, R1 /* p */ +xdec1: + MOVLL (R1), R0 /* *p */ + SUBL $1, R0 + MOVQ R0, R2 + MOVLC R2, (R1) /* --(*p) */ + BEQ R2, xdec1 /* write failed, retry */ + RET + +TEXT cas(SB), $-8 +TEXT casp(SB), $-8 + MOVQ R0, R1 /* p */ + MOVL old+4(FP), R2 + MOVL new+8(FP), R3 + MOVLL (R1), R0 + CMPEQ R0, R2, R4 + BEQ R4, fail /* if R0 != [sic] R2, goto fail */ + MOVQ R3, R0 + MOVLC R0, (R1) + RET +fail: + MOVL $0, R0 + RET + +TEXT loadlink(SB), $-8 + MOVLL (R0), R0 + RET + +TEXT storecond(SB), $-8 + MOVW val+4(FP), R1 + MOVLC R1, (R0) + BEQ R1, storecondfail /* write failed */ + MOVW $1, R0 + RET +storecondfail: + MOVW $0, R0 + RET diff --git a/sys/src/libc/alpha/cycles.c b/sys/src/libc/alpha/cycles.c new file mode 100755 index 000000000..9bad3a989 --- /dev/null +++ b/sys/src/libc/alpha/cycles.c @@ -0,0 +1,7 @@ +#include <u.h> +#include <libc.h> + +void cycles(uvlong*u) +{ + *u = 0LL; +} diff --git a/sys/src/libc/alpha/divl.s b/sys/src/libc/alpha/divl.s new file mode 100755 index 000000000..bce568a8e --- /dev/null +++ b/sys/src/libc/alpha/divl.s @@ -0,0 +1,189 @@ +/* + * 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: 8(R30) + * den: 12(R30) + * returns + * quo: 8(R30) + * rem: 12(R30) + */ +TEXT _udivmodl(SB), NOPROF, $-8 + + MOVQ $-1, R11 + SLLQ $31, R11 /* (1<<31) in canonical form */ + MOVL 8(R30), R23 /* numerator */ + MOVL 12(R30), R10 /* denominator */ + BNE R10, udm20 + MOVQ R31, -1(R31) /* fault -- divide by zero; todo: use gentrap? */ +udm20: + MOVQ R23, R12 + BGE R12, udm34 + MOVQ R11, R12 +udm34: + MOVQ R31, R11 +udm38: + CMPUGE R10, R12, R24 + BNE R24, udm54 + SLLL $1, R10 + ADDQ $1, R11 + JMP udm38 +udm54: + MOVQ R31, R12 +udm58: + BLT R11, udm8c + SLLL $1, R12 + CMPUGE R23, R10, R24 + BEQ R24, udm7c + SUBL R10, R23 + OR $1, R12 +udm7c: + SRLL $1, R10 + SUBQ $1, R11 + JMP udm58 +udm8c: + MOVL R12, 8(R30) /* quotient */ + MOVL R23, 12(R30) /* remainder */ + RET + +/* + * save working registers + * and bring in num/den parameters + */ +TEXT _unsargl(SB), NOPROF, $-8 + MOVQ R10, 24(R30) + MOVQ R11, 32(R30) + MOVQ R12, 40(R30) + MOVQ R23, 48(R30) + MOVQ R24, 56(R30) + + MOVL R27, 8(R30) + MOVL 72(R30), R27 + MOVL R27, 12(R30) + + RET + +/* + * save working registers + * and bring in absolute value + * of num/den parameters + */ +TEXT _absargl(SB), NOPROF, $-8 + MOVQ R10, 24(R30) + MOVQ R11, 32(R30) + MOVQ R12, 40(R30) + MOVQ R23, 48(R30) + MOVQ R24, 56(R30) + + MOVL R27, 64(R30) + BGE R27, ab1 + SUBL R27, R31, R27 +ab1: + MOVL R27, 8(R30) /* numerator */ + + MOVL 72(R30), R27 + BGE R27, ab2 + SUBL R27, R31, R27 +ab2: + MOVL R27, 12(R30) /* denominator */ + RET + +/* + * restore registers and + * return to original caller + * answer is in R27 + */ +TEXT _retargl(SB), NOPROF, $-8 + MOVQ 24(R30), R10 + MOVQ 32(R30), R11 + MOVQ 40(R30), R12 + MOVQ 48(R30), R23 + MOVQ 56(R30), R24 + MOVL 0(R30), R26 + + ADDQ $64, R30 + RET /* back to main sequence */ + +TEXT _divl(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVL R26, 0(R30) + + JSR _absargl(SB) + JSR _udivmodl(SB) + MOVL 8(R30), R27 + + MOVL 64(R30), R10 /* clean up the sign */ + MOVL 72(R30), R11 + XOR R11, R10 + BGE R10, div1 + SUBL R27, R31, R27 +div1: + + JSR _retargl(SB) + RET /* not executed */ + +TEXT _divlu(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVL R26, 0(R30) + + JSR _unsargl(SB) + JSR _udivmodl(SB) + MOVL 8(R30), R27 + + JSR _retargl(SB) + RET /* not executed */ + +TEXT _modl(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVL R26, 0(R30) + + JSR _absargl(SB) + JSR _udivmodl(SB) + MOVL 12(R30), R27 + + MOVL 64(R30), R10 /* clean up the sign */ + BGE R10, div2 + SUBL R27, R31, R27 +div2: + + JSR _retargl(SB) + RET /* not executed */ + +TEXT _modlu(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVL R26, 0(R30) + + JSR _unsargl(SB) + JSR _udivmodl(SB) + MOVL 12(R30), R27 + + JSR _retargl(SB) + RET /* not executed */ + diff --git a/sys/src/libc/alpha/divq.s b/sys/src/libc/alpha/divq.s new file mode 100755 index 000000000..98a58e4a8 --- /dev/null +++ b/sys/src/libc/alpha/divq.s @@ -0,0 +1,191 @@ +/* + * uvlong + * _udiv(uvlong num, uvlong den) + * { + * int i; + * uvlong quo; + * + * if(den == 0) + * *(ulong*)-1 = 0; + * quo = num; + * if(quo > 1<<(64-1)) + * quo = 1<<(64-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: 8(R30) + * den: 16(R30) + * returns + * quo: 8(R30) + * rem: 16(R30) + */ +TEXT _udivmodq(SB), NOPROF, $-8 + + MOVQ $1, R11 + SLLQ $63, R11 + MOVQ 8(R30), R23 /* numerator */ + MOVQ 16(R30), R10 /* denominator */ + BNE R10, udm20 + MOVQ R31, -1(R31) /* fault -- divide by zero; todo: use gentrap? */ +udm20: + MOVQ R23, R12 + BGE R12, udm34 + MOVQ R11, R12 +udm34: + MOVQ R31, R11 +udm38: + CMPUGE R10, R12, R24 + BNE R24, udm54 + SLLQ $1, R10 + ADDQ $1, R11 + JMP udm38 +udm54: + MOVQ R31, R12 +udm58: + BLT R11, udm8c + SLLQ $1, R12 + CMPUGE R23, R10, R24 + BEQ R24, udm7c + SUBQ R10, R23 + OR $1, R12 +udm7c: + SRLQ $1, R10 + SUBQ $1, R11 + JMP udm58 +udm8c: + MOVQ R12, 8(R30) /* quotient */ + MOVQ R23, 16(R30) /* remainder */ + RET + +/* + * save working registers + * and bring in num/den parameters + */ +TEXT _unsargq(SB), NOPROF, $-8 + MOVQ R10, 24(R30) + MOVQ R11, 32(R30) + MOVQ R12, 40(R30) + MOVQ R23, 48(R30) + MOVQ R24, 56(R30) + + MOVQ R27, 8(R30) + MOVQ 72(R30), R27 + MOVQ R27, 16(R30) + +MOVQ (R30), R10 /* debug */ + RET + +/* + * save working registers + * and bring in absolute value + * of num/den parameters + */ +TEXT _absargq(SB), NOPROF, $-8 + MOVQ R10, 24(R30) + MOVQ R11, 32(R30) + MOVQ R12, 40(R30) + MOVQ R23, 48(R30) + MOVQ R24, 56(R30) + + MOVQ R27, 64(R30) + BGE R27, ab1 + SUBQ R27, R31, R27 +ab1: + MOVQ R27, 8(R30) /* numerator */ + + MOVQ 72(R30), R27 + BGE R27, ab2 + SUBQ R27, R31, R27 +ab2: + MOVQ R27, 16(R30) /* denominator */ +MOVQ (R30), R10 /* debug */ + RET + +/* + * restore registers and + * return to original caller + * answer is in R27 + */ +TEXT _retargq(SB), NOPROF, $-8 + MOVQ 24(R30), R10 + MOVQ 32(R30), R11 + MOVQ 40(R30), R12 + MOVQ 48(R30), R23 + MOVQ 56(R30), R24 + MOVL 0(R30), R26 + + ADDQ $64, R30 + RET /* back to main sequence */ + +TEXT _divq(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVQ R26, 0(R30) + + JSR _absargq(SB) + JSR _udivmodq(SB) + MOVQ 8(R30), R27 + + MOVQ 64(R30), R10 /* clean up the sign */ + MOVQ 72(R30), R11 + XOR R11, R10 + BGE R10, div1 + SUBQ R27, R31, R27 +div1: + + JSR _retargq(SB) + RET /* not executed */ + +TEXT _divqu(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVQ R26, 0(R30) + + JSR _unsargq(SB) + JSR _udivmodq(SB) + MOVQ 8(R30), R27 + + JSR _retargq(SB) + RET /* not executed */ + +TEXT _modq(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVQ R26, 0(R30) + + JSR _absargq(SB) + JSR _udivmodq(SB) + MOVQ 16(R30), R27 + + MOVQ 64(R30), R10 /* clean up the sign */ + BGE R10, div2 + SUBQ R27, R31, R27 +div2: + + JSR _retargq(SB) + RET /* not executed */ + +TEXT _modqu(SB), NOPROF, $-8 + SUBQ $64, R30 /* 5 reg save, 2 parameters, link */ + MOVQ R26, 0(R30) + + JSR _unsargq(SB) + JSR _udivmodq(SB) + MOVQ 16(R30), R27 + + JSR _retargq(SB) + RET /* not executed */ + diff --git a/sys/src/libc/alpha/getcallerpc.s b/sys/src/libc/alpha/getcallerpc.s new file mode 100755 index 000000000..2214561be --- /dev/null +++ b/sys/src/libc/alpha/getcallerpc.s @@ -0,0 +1,4 @@ +TEXT getcallerpc(SB), $-8 + MOVL 0(SP), R0 + RET + diff --git a/sys/src/libc/alpha/getfcr.s b/sys/src/libc/alpha/getfcr.s new file mode 100755 index 000000000..06df5de98 --- /dev/null +++ b/sys/src/libc/alpha/getfcr.s @@ -0,0 +1,57 @@ +#define EXCB WORD $0x60000400 /* until 7a/7l catch up */ + +TEXT getfsr(SB), $8 + EXCB + MOVT FPCR, F0 + EXCB + MOVT F0, tmp-8(SP) + MOVL tmp-4(SP), R1 + MOVQ $0x01e00000, R2 + AND R2, R1, R0 + RET + +TEXT setfsr(SB), $8 + MOVQ $0x01e00000, R2 + EXCB + MOVT FPCR, F0 + EXCB + MOVT F0, tmp-8(SP) + MOVL tmp-4(SP), R1 + ANDNOT R2, R1, R3 + AND R2, R0, R4 + OR R3, R4, R5 + MOVL R5, tmp-4(SP) + MOVT tmp-8(SP), F0 + EXCB + MOVT F0, FPCR + EXCB + RET + +TEXT getfcr(SB), $8 + EXCB + MOVT FPCR, F0 + EXCB + MOVT F0, tmp-8(SP) + MOVL tmp-4(SP), R1 + MOVQ $0x700c0000, R2 + AND R2, R1, R0 + XOR R2, R0 + RET + +TEXT setfcr(SB), $8 + MOVQ $0x700c0000, R2 + XOR R2, R0 + EXCB + MOVT FPCR, F0 + EXCB + MOVT F0, tmp-8(SP) + MOVL tmp-4(SP), R1 + ANDNOT R2, R1, R3 + AND R2, R0, R4 + OR R3, R4, R5 + MOVL R5, tmp-4(SP) + MOVT tmp-8(SP), F0 + EXCB + MOVT F0, FPCR + EXCB + RET diff --git a/sys/src/libc/alpha/main9.s b/sys/src/libc/alpha/main9.s new file mode 100755 index 000000000..5e51d5d28 --- /dev/null +++ b/sys/src/libc/alpha/main9.s @@ -0,0 +1,27 @@ +#define NPRIVATES 16 + +TEXT _main(SB), 1, $(16 + NPRIVATES*4) + + MOVQ $setSB(SB), R29 + MOVL R0, _tos(SB) + + MOVQ $p-64(SP),R1 + MOVL R1,_privates+0(SB) + MOVQ $16,R1 + MOVL R1,_nprivates+0(SB) + + MOVL inargc-8(FP), R0 + MOVL $inargv-4(FP), R1 + MOVL R0, 8(R30) + MOVL R1, 12(R30) + JSR main(SB) +loop: + MOVL $_exitstr<>(SB), R0 + MOVL R0, 8(R30) + JSR exits(SB) + MOVQ $_divq(SB), R31 /* force loading of divq */ + MOVQ $_divl(SB), R31 /* force loading of divl */ + JMP loop + +DATA _exitstr<>+0(SB)/4, $"main" +GLOBL _exitstr<>+0(SB), $5 diff --git a/sys/src/libc/alpha/main9p.s b/sys/src/libc/alpha/main9p.s new file mode 100755 index 000000000..defdb4842 --- /dev/null +++ b/sys/src/libc/alpha/main9p.s @@ -0,0 +1,37 @@ +#define NPRIVATES 16 + +TEXT _mainp(SB), 1, $16 + + MOVQ $setSB(SB), R29 + MOVL R0, _tos(SB) + + MOVQ $p-64(SP),R1 + MOVL R1,_privates+0(SB) + MOVQ $16,R1 + MOVL R1,_nprivates+0(SB) + JSR _profmain(SB) + MOVL __prof+4(SB), R0 + MOVL R0, __prof+0(SB) + MOVL inargc-4(FP), R0 + MOVL $inargv+0(FP), R1 + MOVL R0, 8(R30) + MOVL R1, 12(R30) + JSR main(SB) +loop: + MOVQ $exits<>(SB), R0 + MOVL R0, 8(R30) + JSR exits(SB) + MOVQ $_divq(SB), R31 /* force loading of divq */ + MOVQ $_divl(SB), R31 /* force loading of divl */ + MOVQ $_profin(SB), R31 /* force loading of profile */ + JMP loop + +TEXT _savearg(SB), 1, $0 + RET + +TEXT _callpc(SB), 1, $0 + MOVL argp-8(FP), R0 + RET + +DATA exits<>+0(SB)/4, $"main" +GLOBL exits<>+0(SB), $5 diff --git a/sys/src/libc/alpha/memmove.s b/sys/src/libc/alpha/memmove.s new file mode 100755 index 000000000..8a77f68d7 --- /dev/null +++ b/sys/src/libc/alpha/memmove.s @@ -0,0 +1,201 @@ +#define QUAD 8 +#define ALIGN 64 +#define BLOCK 64 + +TEXT memmove(SB), $0 +_memmove: + MOVL from+4(FP), R7 + MOVL n+8(FP), R10 + MOVQ R0, R6 + + CMPUGE R7, R0, R5 + BNE R5, _forward + + MOVQ R6, R8 /* end to address */ + ADDL R10, R6, R6 /* to+n */ + ADDL R10, R7, R7 /* from+n */ + + CMPUGE $ALIGN, R10, R1 /* need at least ALIGN bytes */ + BNE R1, _b1tail + +_balign: + AND $(ALIGN-1), R6, R1 + BEQ R1, _baligned + + MOVBU -1(R7), R2 + ADDL $-1, R6, R6 + MOVB R2, (R6) + ADDL $-1, R7, R7 + JMP _balign + +_baligned: + AND $(QUAD-1), R7, R1 /* is the source quad-aligned */ + BNE R1, _bunaligned + + ADDL $(BLOCK-1), R8, R9 +_bblock: + CMPUGE R9, R6, R1 + BNE R1, _b8tail + + MOVQ -64(R7), R22 + MOVQ -56(R7), R23 + MOVQ -48(R7), R24 + MOVQ -40(R7), R25 + MOVQ -32(R7), R2 + MOVQ -24(R7), R3 + MOVQ -16(R7), R4 + MOVQ -8(R7), R5 + + SUBL $64, R6, R6 + SUBL $64, R7, R7 + + MOVQ R22, (R6) + MOVQ R23, 8(R6) + MOVQ R24, 16(R6) + MOVQ R25, 24(R6) + MOVQ R2, 32(R6) + MOVQ R3, 40(R6) + MOVQ R4, 48(R6) + MOVQ R5, 56(R6) + JMP _bblock + +_b8tail: + ADDL $(QUAD-1), R8, R9 +_b8block: + CMPUGE R9, R6, R1 + BNE R1, _b1tail + + MOVQ -8(R7), R2 + SUBL $8, R6 + MOVQ R2, (R6) + SUBL $8, R7 + JMP _b8block + +_b1tail: + CMPUGE R8, R6, R1 + BNE R1, _ret + + MOVBU -1(R7), R2 + SUBL $1, R6, R6 + MOVB R2, (R6) + SUBL $1, R7, R7 + JMP _b1tail +_ret: + RET + +_bunaligned: + ADDL $(16-1), R8, R9 + +_bu8block: + CMPUGE R9, R6, R1 + BNE R1, _b1tail + + MOVQU -16(R7), R4 + MOVQU -8(R7), R3 + MOVQU (R7), R2 + SUBL $16, R6 + EXTQH R7, R2, R2 + EXTQL R7, R3, R5 + OR R5, R2, R11 + EXTQH R7, R3, R3 + EXTQL R7, R4, R4 + OR R3, R4, R13 + MOVQ R11, 8(R6) + MOVQ R13, (R6) + SUBL $16, R7 + JMP _bu8block + +_forward: + ADDL R10, R6, R8 /* end to address */ + + CMPUGE $ALIGN, R10, R1 /* need at least ALIGN bytes */ + BNE R1, _f1tail + +_falign: + AND $(ALIGN-1), R6, R1 + BEQ R1, _faligned + + MOVBU (R7), R2 + ADDL $1, R6, R6 + ADDL $1, R7, R7 + MOVB R2, -1(R6) + JMP _falign + +_faligned: + AND $(QUAD-1), R7, R1 /* is the source quad-aligned */ + BNE R1, _funaligned + + SUBL $(BLOCK-1), R8, R9 +_fblock: + CMPUGT R9, R6, R1 + BEQ R1, _f8tail + + MOVQ (R7), R2 + MOVQ 8(R7), R3 + MOVQ 16(R7), R4 + MOVQ 24(R7), R5 + MOVQ 32(R7), R22 + MOVQ 40(R7), R23 + MOVQ 48(R7), R24 + MOVQ 56(R7), R25 + + ADDL $64, R6, R6 + ADDL $64, R7, R7 + + MOVQ R2, -64(R6) + MOVQ R3, -56(R6) + MOVQ R4, -48(R6) + MOVQ R5, -40(R6) + MOVQ R22, -32(R6) + MOVQ R23, -24(R6) + MOVQ R24, -16(R6) + MOVQ R25, -8(R6) + JMP _fblock + +_f8tail: + SUBL $(QUAD-1), R8, R9 +_f8block: + CMPUGT R9, R6, R1 + BEQ R1, _f1tail + + MOVQ (R7), R2 + ADDL $8, R6 + ADDL $8, R7 + MOVQ R2, -8(R6) + JMP _f8block + +_f1tail: + CMPUGT R8, R6, R1 + BEQ R1, _fret + MOVBU (R7), R2 + ADDL $1, R6, R6 + ADDL $1, R7, R7 + MOVB R2, -1(R6) + JMP _f1tail + +_fret: + RET + +_funaligned: + SUBL $(16-1), R8, R9 +_fu8block: + CMPUGT R9, R6, R1 + BEQ R1, _f1tail + + MOVQU (R7), R2 + MOVQU 8(R7), R3 + MOVQU 16(R7), R4 + EXTQL R7, R2, R2 + EXTQH R7, R3, R5 + OR R5, R2, R11 + EXTQL R7, R3, R3 + MOVQ R11, (R6) + EXTQH R7, R4, R4 + OR R3, R4, R11 + MOVQ R11, 8(R6) + ADDL $16, R6 + ADDL $16, R7 + JMP _fu8block + +TEXT memcpy(SB), $0 + JMP _memmove diff --git a/sys/src/libc/alpha/memset.s b/sys/src/libc/alpha/memset.s new file mode 100755 index 000000000..e3cfd468b --- /dev/null +++ b/sys/src/libc/alpha/memset.s @@ -0,0 +1,61 @@ +TEXT memset(SB), $0 + MOVL R0, R6 + MOVBU data+4(FP), R2 + MOVL n+8(FP), R10 + + ADDL R10, R0, R8 + + CMPUGE $8, R10, R1 /* need at least 8 bytes */ + BNE R1, _1loop + + SLLQ $8, R2, R1 /* replicate the byte */ + OR R1, R2 + SLLQ $16, R2, R1 + OR R1, R2 + SLLQ $32, R2, R1 + OR R1, R2 + +_align: + AND $(8-1), R6, R1 + BEQ R1, _aligned + + MOVB R2, (R6) + ADDL $1, R6, R6 + JMP _align + +_aligned: + SUBL $(64-1), R8, R9 /* end pointer minus slop */ +_64loop: + CMPUGT R9, R6, R1 + BEQ R1, _8tail + + MOVQ R2, (R6) + MOVQ R2, 8(R6) + MOVQ R2, 16(R6) + MOVQ R2, 24(R6) + MOVQ R2, 32(R6) + MOVQ R2, 40(R6) + MOVQ R2, 48(R6) + MOVQ R2, 56(R6) + ADDL $64, R6, R6 + JMP _64loop + +_8tail: + SUBL $(8-1), R8, R9 +_8loop: + CMPUGT R9, R6, R1 + BEQ R1, _1loop + + MOVQ R2, (R6) + ADDL $8, R6 + JMP _8loop + +_1loop: + CMPUGT R8, R6, R1 + BEQ R1, _ret + MOVB R2, (R6) + ADDL $1, R6 + JMP _1loop + +_ret: + RET diff --git a/sys/src/libc/alpha/mkfile b/sys/src/libc/alpha/mkfile new file mode 100755 index 000000000..ef66ac423 --- /dev/null +++ b/sys/src/libc/alpha/mkfile @@ -0,0 +1,33 @@ +objtype=alpha +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +SFILES=\ + argv0.s\ + atom.s\ + divl.s\ + divq.s\ + getcallerpc.s\ + getfcr.s\ + main9.s\ + main9p.s\ + memmove.s\ + memset.s\ + setjmp.s\ + tas.s + +CFILES=\ + _seek.c\ + cycles.c\ + notejmp.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/alpha/notejmp.c b/sys/src/libc/alpha/notejmp.c new file mode 100755 index 000000000..dff612bce --- /dev/null +++ b/sys/src/libc/alpha/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->sp = j[JMPBUFSP]; + noted(NCONT); +} diff --git a/sys/src/libc/alpha/setjmp.s b/sys/src/libc/alpha/setjmp.s new file mode 100755 index 000000000..dd423df02 --- /dev/null +++ b/sys/src/libc/alpha/setjmp.s @@ -0,0 +1,14 @@ +TEXT setjmp(SB), 1, $-8 + MOVL R30, (R0) + MOVL R26, 4(R0) + MOVQ $0, R0 + RET + +TEXT longjmp(SB), 1, $-8 + MOVL r+4(FP), R3 + BNE R3, ok /* ansi: "longjmp(0) => longjmp(1)" */ + MOVQ $1, R3 /* bless their pointed heads */ +ok: MOVL (R0), R30 + MOVL 4(R0), R26 + MOVL R3, R0 + RET diff --git a/sys/src/libc/alpha/tas.s b/sys/src/libc/alpha/tas.s new file mode 100755 index 000000000..613eb7b91 --- /dev/null +++ b/sys/src/libc/alpha/tas.s @@ -0,0 +1,10 @@ +TEXT _tas(SB), $-8 + MOVQ R0, R1 /* l */ +tas1: + MOVLL (R1), R0 /* l->key */ + BNE R0, tas2 + MOVQ $1, R2 + MOVLC R2, (R1) /* l->key = 1 */ + BEQ R2, tas1 /* write failed, try again? */ +tas2: + RET 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); +} diff --git a/sys/src/libc/fmt/dofmt.c b/sys/src/libc/fmt/dofmt.c new file mode 100755 index 000000000..2a4b42959 --- /dev/null +++ b/sys/src/libc/fmt/dofmt.c @@ -0,0 +1,523 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +/* format the output into f->to and return the number of characters fmted */ +int +dofmt(Fmt *f, char *fmt) +{ + Rune rune, *rt, *rs; + int r; + char *t, *s; + int n, nfmt; + + nfmt = f->nfmt; + for(;;){ + if(f->runes){ + rt = f->to; + rs = f->stop; + while((r = *(uchar*)fmt) && r != '%'){ + if(r < Runeself) + fmt++; + else{ + fmt += chartorune(&rune, fmt); + r = rune; + } + FMTRCHAR(f, rt, rs, r); + } + fmt++; + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(!r) + return f->nfmt - nfmt; + f->stop = rs; + }else{ + t = f->to; + s = f->stop; + while((r = *(uchar*)fmt) && r != '%'){ + if(r < Runeself){ + FMTCHAR(f, t, s, r); + fmt++; + }else{ + n = chartorune(&rune, fmt); + if(t + n > s){ + t = _fmtflush(f, t, n); + if(t != nil) + s = f->stop; + else + return -1; + } + while(n--) + *t++ = *fmt++; + } + } + fmt++; + f->nfmt += t - (char *)f->to; + f->to = t; + if(!r) + return f->nfmt - nfmt; + f->stop = s; + } + + fmt = _fmtdispatch(f, fmt, 0); + if(fmt == nil) + return -1; + } +} + +void * +_fmtflush(Fmt *f, void *t, int len) +{ + if(f->runes) + f->nfmt += (Rune*)t - (Rune*)f->to; + else + f->nfmt += (char*)t - (char *)f->to; + f->to = t; + if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){ + f->stop = f->to; + return nil; + } + return f->to; +} + +/* + * put a formatted block of memory sz bytes long of n runes into the output buffer, + * left/right justified in a field of at least f->width charactes + */ +int +_fmtpad(Fmt *f, int n) +{ + char *t, *s; + int i; + + t = f->to; + s = f->stop; + for(i = 0; i < n; i++) + FMTCHAR(f, t, s, ' '); + f->nfmt += t - (char *)f->to; + f->to = t; + return 0; +} + +int +_rfmtpad(Fmt *f, int n) +{ + Rune *t, *s; + int i; + + t = f->to; + s = f->stop; + for(i = 0; i < n; i++) + FMTRCHAR(f, t, s, ' '); + f->nfmt += t - (Rune *)f->to; + f->to = t; + return 0; +} + +int +_fmtcpy(Fmt *f, void *vm, int n, int sz) +{ + Rune *rt, *rs, r; + char *t, *s, *m, *me; + ulong fl; + int nc, w; + + m = vm; + me = m + sz; + w = f->width; + fl = f->flags; + if((fl & FmtPrec) && n > f->prec) + n = f->prec; + if(f->runes){ + if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0) + return -1; + rt = f->to; + rs = f->stop; + for(nc = n; nc > 0; nc--){ + r = *(uchar*)m; + if(r < Runeself) + m++; + else if((me - m) >= UTFmax || fullrune(m, me-m)) + m += chartorune(&r, m); + else + break; + FMTRCHAR(f, rt, rs, r); + } + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) + return -1; + }else{ + if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) + return -1; + t = f->to; + s = f->stop; + for(nc = n; nc > 0; nc--){ + r = *(uchar*)m; + if(r < Runeself) + m++; + else if((me - m) >= UTFmax || fullrune(m, me-m)) + m += chartorune(&r, m); + else + break; + FMTRUNE(f, t, s, r); + } + f->nfmt += t - (char *)f->to; + f->to = t; + if(fl & FmtLeft && _fmtpad(f, w - n) < 0) + return -1; + } + return 0; +} + +int +_fmtrcpy(Fmt *f, void *vm, int n) +{ + Rune r, *m, *me, *rt, *rs; + char *t, *s; + ulong fl; + int w; + + m = vm; + w = f->width; + fl = f->flags; + if((fl & FmtPrec) && n > f->prec) + n = f->prec; + if(f->runes){ + if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0) + return -1; + rt = f->to; + rs = f->stop; + for(me = m + n; m < me; m++) + FMTRCHAR(f, rt, rs, *m); + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) + return -1; + }else{ + if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) + return -1; + t = f->to; + s = f->stop; + for(me = m + n; m < me; m++){ + r = *m; + FMTRUNE(f, t, s, r); + } + f->nfmt += t - (char *)f->to; + f->to = t; + if(fl & FmtLeft && _fmtpad(f, w - n) < 0) + return -1; + } + return 0; +} + +/* fmt out one character */ +int +_charfmt(Fmt *f) +{ + char x[1]; + + x[0] = va_arg(f->args, int); + f->prec = 1; + return _fmtcpy(f, x, 1, 1); +} + +/* fmt out one rune */ +int +_runefmt(Fmt *f) +{ + Rune x[1]; + + x[0] = va_arg(f->args, int); + return _fmtrcpy(f, x, 1); +} + +/* public helper routine: fmt out a null terminated string already in hand */ +int +fmtstrcpy(Fmt *f, char *s) +{ + int i, j; + Rune r; + + if(!s) + return _fmtcpy(f, "<nil>", 5, 5); + /* if precision is specified, make sure we don't wander off the end */ + if(f->flags & FmtPrec){ + i = 0; + for(j=0; j<f->prec && s[i]; j++) + i += chartorune(&r, s+i); + return _fmtcpy(f, s, j, i); + } + return _fmtcpy(f, s, utflen(s), strlen(s)); +} + +/* fmt out a null terminated utf string */ +int +_strfmt(Fmt *f) +{ + char *s; + + s = va_arg(f->args, char *); + return fmtstrcpy(f, s); +} + +/* public helper routine: fmt out a null terminated rune string already in hand */ +int +fmtrunestrcpy(Fmt *f, Rune *s) +{ + Rune *e; + int n, p; + + if(!s) + return _fmtcpy(f, "<nil>", 5, 5); + /* if precision is specified, make sure we don't wander off the end */ + if(f->flags & FmtPrec){ + p = f->prec; + for(n = 0; n < p; n++) + if(s[n] == 0) + break; + }else{ + for(e = s; *e; e++) + ; + n = e - s; + } + return _fmtrcpy(f, s, n); +} + +/* fmt out a null terminated rune string */ +int +_runesfmt(Fmt *f) +{ + Rune *s; + + s = va_arg(f->args, Rune *); + return fmtrunestrcpy(f, s); +} + +/* fmt a % */ +int +_percentfmt(Fmt *f) +{ + Rune x[1]; + + x[0] = f->r; + f->prec = 1; + return _fmtrcpy(f, x, 1); +} + +/* fmt an integer */ +int +_ifmt(Fmt *f) +{ + char buf[70], *p, *conv; + uvlong vu; + ulong u; + uintptr pu; + int neg, base, i, n, fl, w, isv; + + neg = 0; + fl = f->flags; + isv = 0; + vu = 0; + u = 0; + if(f->r == 'p'){ + pu = va_arg(f->args, uintptr); + if(sizeof(uintptr) == sizeof(uvlong)){ + vu = pu; + isv = 1; + }else + u = pu; + f->r = 'x'; + fl |= FmtUnsigned; + }else if(fl & FmtVLong){ + isv = 1; + if(fl & FmtUnsigned) + vu = va_arg(f->args, uvlong); + else + vu = va_arg(f->args, vlong); + }else if(fl & FmtLong){ + if(fl & FmtUnsigned) + u = va_arg(f->args, ulong); + else + u = va_arg(f->args, long); + }else if(fl & FmtByte){ + if(fl & FmtUnsigned) + u = (uchar)va_arg(f->args, int); + else + u = (char)va_arg(f->args, int); + }else if(fl & FmtShort){ + if(fl & FmtUnsigned) + u = (ushort)va_arg(f->args, int); + else + u = (short)va_arg(f->args, int); + }else{ + if(fl & FmtUnsigned) + u = va_arg(f->args, uint); + else + u = va_arg(f->args, int); + } + conv = "0123456789abcdef"; + switch(f->r){ + case 'd': + base = 10; + break; + case 'x': + base = 16; + break; + case 'X': + base = 16; + conv = "0123456789ABCDEF"; + break; + case 'b': + base = 2; + break; + case 'o': + base = 8; + break; + default: + return -1; + } + if(!(fl & FmtUnsigned)){ + if(isv && (vlong)vu < 0){ + vu = -(vlong)vu; + neg = 1; + }else if(!isv && (long)u < 0){ + u = -(long)u; + neg = 1; + } + } + p = buf + sizeof buf - 1; + n = 0; + if(isv){ + while(vu){ + i = vu % base; + vu /= base; + if((fl & FmtComma) && n % 4 == 3){ + *p-- = ','; + n++; + } + *p-- = conv[i]; + n++; + } + }else{ + while(u){ + i = u % base; + u /= base; + if((fl & FmtComma) && n % 4 == 3){ + *p-- = ','; + n++; + } + *p-- = conv[i]; + n++; + } + } + if(n == 0){ + *p-- = '0'; + n = 1; + } + for(w = f->prec; n < w && p > buf+3; n++) + *p-- = '0'; + if(neg || (fl & (FmtSign|FmtSpace))) + n++; + if(fl & FmtSharp){ + if(base == 16) + n += 2; + else if(base == 8){ + if(p[1] == '0') + fl &= ~FmtSharp; + else + n++; + } + } + if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){ + for(w = f->width; n < w && p > buf+3; n++) + *p-- = '0'; + f->width = 0; + } + if(fl & FmtSharp){ + if(base == 16) + *p-- = f->r; + if(base == 16 || base == 8) + *p-- = '0'; + } + if(neg) + *p-- = '-'; + else if(fl & FmtSign) + *p-- = '+'; + else if(fl & FmtSpace) + *p-- = ' '; + f->flags &= ~FmtPrec; + return _fmtcpy(f, p + 1, n, n); +} + +int +_countfmt(Fmt *f) +{ + void *p; + ulong fl; + + fl = f->flags; + p = va_arg(f->args, void*); + if(fl & FmtVLong){ + *(vlong*)p = f->nfmt; + }else if(fl & FmtLong){ + *(long*)p = f->nfmt; + }else if(fl & FmtByte){ + *(char*)p = f->nfmt; + }else if(fl & FmtShort){ + *(short*)p = f->nfmt; + }else{ + *(int*)p = f->nfmt; + } + return 0; +} + +int +_flagfmt(Fmt *f) +{ + switch(f->r){ + case ',': + f->flags |= FmtComma; + break; + case '-': + f->flags |= FmtLeft; + break; + case '+': + f->flags |= FmtSign; + break; + case '#': + f->flags |= FmtSharp; + break; + case ' ': + f->flags |= FmtSpace; + break; + case 'u': + f->flags |= FmtUnsigned; + break; + case 'h': + if(f->flags & FmtShort) + f->flags |= FmtByte; + f->flags |= FmtShort; + break; + case 'l': + if(f->flags & FmtLong) + f->flags |= FmtVLong; + f->flags |= FmtLong; + break; + } + return 1; +} + +/* default error format */ +int +_badfmt(Fmt *f) +{ + char x[3]; + + x[0] = '%'; + x[1] = f->r; + x[2] = '%'; + f->prec = 3; + _fmtcpy(f, x, 3, 3); + return 0; +} diff --git a/sys/src/libc/fmt/dorfmt.c b/sys/src/libc/fmt/dorfmt.c new file mode 100755 index 000000000..6e60073d9 --- /dev/null +++ b/sys/src/libc/fmt/dorfmt.c @@ -0,0 +1,45 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +/* format the output into f->to and return the number of characters fmted */ + +int +dorfmt(Fmt *f, Rune *fmt) +{ + Rune *rt, *rs; + int r; + char *t, *s; + int nfmt; + + nfmt = f->nfmt; + for(;;){ + if(f->runes){ + rt = f->to; + rs = f->stop; + while((r = *fmt++) && r != '%'){ + FMTRCHAR(f, rt, rs, r); + } + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(!r) + return f->nfmt - nfmt; + f->stop = rs; + }else{ + t = f->to; + s = f->stop; + while((r = *fmt++) && r != '%'){ + FMTRUNE(f, t, f->stop, r); + } + f->nfmt += t - (char *)f->to; + f->to = t; + if(!r) + return f->nfmt - nfmt; + f->stop = s; + } + + fmt = _fmtdispatch(f, fmt, 1); + if(fmt == nil) + return -1; + } +} diff --git a/sys/src/libc/fmt/errfmt.c b/sys/src/libc/fmt/errfmt.c new file mode 100755 index 000000000..5b29b1671 --- /dev/null +++ b/sys/src/libc/fmt/errfmt.c @@ -0,0 +1,12 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +int +errfmt(Fmt *f) +{ + char buf[ERRMAX]; + + rerrstr(buf, sizeof buf); + return _fmtcpy(f, buf, utflen(buf), strlen(buf)); +} diff --git a/sys/src/libc/fmt/fltfmt.c b/sys/src/libc/fmt/fltfmt.c new file mode 100755 index 000000000..ff5462910 --- /dev/null +++ b/sys/src/libc/fmt/fltfmt.c @@ -0,0 +1,318 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include "fmtdef.h" + +enum +{ + FDIGIT = 30, + FDEFLT = 6, + NSIGNIF = 17, + NEXP10 = 308, +}; + +static int +xadd(char *a, int n, int v) +{ + char *b; + int c; + + if(n < 0 || n >= NSIGNIF) + return 0; + for(b = a+n; b >= a; b--) { + c = *b + v; + if(c <= '9') { + *b = c; + return 0; + } + *b = '0'; + v = 1; + } + *a = '1'; // overflow adding + return 1; +} + +static int +xsub(char *a, int n, int v) +{ + char *b; + int c; + + for(b = a+n; b >= a; b--) { + c = *b - v; + if(c >= '0') { + *b = c; + return 0; + } + *b = '9'; + v = 1; + } + *a = '9'; // underflow subtracting + return 1; +} + +static void +xdtoa(Fmt *fmt, char *s2, double f) +{ + char s1[NSIGNIF+10]; + double g, h; + int e, d, i, n; + int c1, c2, c3, c4, ucase, sign, chr, prec; + + prec = FDEFLT; + if(fmt->flags & FmtPrec) + prec = fmt->prec; + if(prec > FDIGIT) + prec = FDIGIT; + if(isNaN(f)) { + strcpy(s2, "NaN"); + return; + } + if(isInf(f, 1)) { + strcpy(s2, "+Inf"); + return; + } + if(isInf(f, -1)) { + strcpy(s2, "-Inf"); + return; + } + sign = 0; + if(f < 0) { + f = -f; + sign++; + } + ucase = 0; + chr = fmt->r; + if(isupper(chr)) { + ucase = 1; + chr = tolower(chr); + } + + e = 0; + g = f; + if(g != 0) { + frexp(f, &e); + e = e * .301029995664; + if(e >= -150 && e <= +150) { + d = 0; + h = f; + } else { + d = e/2; + h = f * pow10(-d); + } + g = h * pow10(d-e); + while(g < 1) { + e--; + g = h * pow10(d-e); + } + while(g >= 10) { + e++; + g = h * pow10(d-e); + } + } + + /* + * convert NSIGNIF digits and convert + * back to get accuracy. + */ + for(i=0; i<NSIGNIF; i++) { + d = g; + s1[i] = d + '0'; + g = (g - d) * 10; + } + s1[i] = 0; + + /* + * try decimal rounding to eliminate 9s + */ + c2 = prec + 1; + if(chr == 'f') + c2 += e; + if(c2 >= NSIGNIF-2) { + strcpy(s2, s1); + d = e; + s1[NSIGNIF-2] = '0'; + s1[NSIGNIF-1] = '0'; + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + g = strtod(s1, nil); + if(g == f) + goto found; + if(xadd(s1, NSIGNIF-3, 1)) { + e++; + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + } + g = strtod(s1, nil); + if(g == f) + goto found; + strcpy(s1, s2); + e = d; + } + + /* + * convert back so s1 gets exact answer + */ + for(;;) { + sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); + g = strtod(s1, nil); + if(f > g) { + if(xadd(s1, NSIGNIF-1, 1)) + e--; + continue; + } + if(f < g) { + if(xsub(s1, NSIGNIF-1, 1)) + e++; + continue; + } + break; + } + +found: + /* + * sign + */ + d = 0; + i = 0; + if(sign) + s2[d++] = '-'; + else if(fmt->flags & FmtSign) + s2[d++] = '+'; + else if(fmt->flags & FmtSpace) + s2[d++] = ' '; + + /* + * copy into final place + * c1 digits of leading '0' + * c2 digits from conversion + * c3 digits of trailing '0' + * c4 digits after '.' + */ + c1 = 0; + c2 = prec + 1; + c3 = 0; + c4 = prec; + switch(chr) { + default: + if(xadd(s1, c2, 5)) + e++; + break; + case 'g': + /* + * decide on 'e' of 'f' style convers + */ + if(xadd(s1, c2, 5)) + e++; + if(e >= -5 && e <= prec) { + c1 = -e - 1; + c4 = prec - e; + chr = 'h'; // flag for 'f' style + } + break; + case 'f': + if(xadd(s1, c2+e, 5)) + e++; + c1 = -e; + if(c1 > prec) + c1 = c2; + c2 += e; + break; + } + + /* + * clean up c1 c2 and c3 + */ + if(c1 < 0) + c1 = 0; + if(c2 < 0) + c2 = 0; + if(c2 > NSIGNIF) { + c3 = c2-NSIGNIF; + c2 = NSIGNIF; + } + + /* + * copy digits + */ + while(c1 > 0) { + if(c1+c2+c3 == c4) + s2[d++] = '.'; + s2[d++] = '0'; + c1--; + } + while(c2 > 0) { + if(c2+c3 == c4) + s2[d++] = '.'; + s2[d++] = s1[i++]; + c2--; + } + while(c3 > 0) { + if(c3 == c4) + s2[d++] = '.'; + s2[d++] = '0'; + c3--; + } + + /* + * strip trailing '0' on g conv + */ + if(fmt->flags & FmtSharp) { + if(0 == c4) + s2[d++] = '.'; + } else + if(chr == 'g' || chr == 'h') { + for(n=d-1; n>=0; n--) + if(s2[n] != '0') + break; + for(i=n; i>=0; i--) + if(s2[i] == '.') { + d = n; + if(i != n) + d++; + break; + } + } + if(chr == 'e' || chr == 'g') { + if(ucase) + s2[d++] = 'E'; + else + s2[d++] = 'e'; + c1 = e; + if(c1 < 0) { + s2[d++] = '-'; + c1 = -c1; + } else + s2[d++] = '+'; + if(c1 >= 100) { + s2[d++] = c1/100 + '0'; + c1 = c1%100; + } + s2[d++] = c1/10 + '0'; + s2[d++] = c1%10 + '0'; + } + s2[d] = 0; +} + +int +_floatfmt(Fmt *fmt, double f) +{ + char s[1+NEXP10+1+FDIGIT+1]; + + /* + * The max length of a %f string is + * '[+-]'+"max exponent"+'.'+"max precision"+'\0' + * which is 341 currently. + */ + xdtoa(fmt, s, f); + fmt->flags &= FmtWidth|FmtLeft; + _fmtcpy(fmt, s, strlen(s), strlen(s)); + return 0; +} + +int +_efgfmt(Fmt *f) +{ + double d; + + d = va_arg(f->args, double); + return _floatfmt(f, d); +} diff --git a/sys/src/libc/fmt/fmt.c b/sys/src/libc/fmt/fmt.c new file mode 100755 index 000000000..82ae36543 --- /dev/null +++ b/sys/src/libc/fmt/fmt.c @@ -0,0 +1,202 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +enum +{ + Maxfmt = 64 +}; + +typedef struct Convfmt Convfmt; +struct Convfmt +{ + int c; + volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */ +}; + +struct +{ + /* lock by calling _fmtlock, _fmtunlock */ + int nfmt; + Convfmt fmt[Maxfmt]; +} fmtalloc; + +static Convfmt knownfmt[] = { + ' ', _flagfmt, + '#', _flagfmt, + '%', _percentfmt, + '+', _flagfmt, + ',', _flagfmt, + '-', _flagfmt, + 'C', _runefmt, + 'E', _efgfmt, + 'G', _efgfmt, + 'S', _runesfmt, + 'X', _ifmt, + 'b', _ifmt, + 'c', _charfmt, + 'd', _ifmt, + 'e', _efgfmt, + 'f', _efgfmt, + 'g', _efgfmt, + 'h', _flagfmt, + 'l', _flagfmt, + 'n', _countfmt, + 'o', _ifmt, + 'p', _ifmt, + 'r', errfmt, + 's', _strfmt, + 'u', _flagfmt, + 'x', _ifmt, + 0, nil, +}; + +int (*doquote)(int); + +/* + * _fmtlock() must be set + */ +static int +_fmtinstall(int c, Fmts f) +{ + Convfmt *p, *ep; + + if(c<=0 || c>=65536) + return -1; + if(!f) + f = _badfmt; + + ep = &fmtalloc.fmt[fmtalloc.nfmt]; + for(p=fmtalloc.fmt; p<ep; p++) + if(p->c == c) + break; + + if(p == &fmtalloc.fmt[Maxfmt]) + return -1; + + p->fmt = f; + if(p == ep){ /* installing a new format character */ + fmtalloc.nfmt++; + p->c = c; + } + + return 0; +} + +int +fmtinstall(int c, Fmts f) +{ + int ret; + + _fmtlock(); + ret = _fmtinstall(c, f); + _fmtunlock(); + return ret; +} + +static Fmts +fmtfmt(int c) +{ + Convfmt *p, *ep; + + ep = &fmtalloc.fmt[fmtalloc.nfmt]; + for(p=fmtalloc.fmt; p<ep; p++) + if(p->c == c){ + while(p->fmt == nil) /* loop until value is updated */ + ; + return p->fmt; + } + + /* is this a predefined format char? */ + _fmtlock(); + for(p=knownfmt; p->c; p++) + if(p->c == c){ + _fmtinstall(p->c, p->fmt); + _fmtunlock(); + return p->fmt; + } + _fmtunlock(); + + return _badfmt; +} + +void* +_fmtdispatch(Fmt *f, void *fmt, int isrunes) +{ + Rune rune, r; + int i, n; + + f->flags = 0; + f->width = f->prec = 0; + + for(;;){ + if(isrunes){ + r = *(Rune*)fmt; + fmt = (Rune*)fmt + 1; + }else{ + fmt = (char*)fmt + chartorune(&rune, fmt); + r = rune; + } + f->r = r; + switch(r){ + case '\0': + return nil; + case '.': + f->flags |= FmtWidth|FmtPrec; + continue; + case '0': + if(!(f->flags & FmtWidth)){ + f->flags |= FmtZero; + continue; + } + /* fall through */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + i = 0; + while(r >= '0' && r <= '9'){ + i = i * 10 + r - '0'; + if(isrunes){ + r = *(Rune*)fmt; + fmt = (Rune*)fmt + 1; + }else{ + r = *(char*)fmt; + fmt = (char*)fmt + 1; + } + } + if(isrunes) + fmt = (Rune*)fmt - 1; + else + fmt = (char*)fmt - 1; + numflag: + if(f->flags & FmtWidth){ + f->flags |= FmtPrec; + f->prec = i; + }else{ + f->flags |= FmtWidth; + f->width = i; + } + continue; + case '*': + i = va_arg(f->args, int); + if(i < 0){ + /* + * negative precision => + * ignore the precision. + */ + if(f->flags & FmtPrec){ + f->flags &= ~FmtPrec; + f->prec = 0; + continue; + } + i = -i; + f->flags |= FmtLeft; + } + goto numflag; + } + n = (*fmtfmt(r))(f); + if(n < 0) + return nil; + if(n == 0) + return fmt; + } +} diff --git a/sys/src/libc/fmt/fmtdef.h b/sys/src/libc/fmt/fmtdef.h new file mode 100755 index 000000000..d8f3680fb --- /dev/null +++ b/sys/src/libc/fmt/fmtdef.h @@ -0,0 +1,85 @@ +/* + * dofmt -- format to a buffer + * the number of characters formatted is returned, + * or -1 if there was an error. + * if the buffer is ever filled, flush is called. + * it should reset the buffer and return whether formatting should continue. + */ + +typedef int (*Fmts)(Fmt*); + +typedef struct Quoteinfo Quoteinfo; +struct Quoteinfo +{ + int quoted; /* if set, string must be quoted */ + int nrunesin; /* number of input runes that can be accepted */ + int nbytesin; /* number of input bytes that can be accepted */ + int nrunesout; /* number of runes that will be generated */ + int nbytesout; /* number of bytes that will be generated */ +}; + +void *_fmtflush(Fmt*, void*, int); +void *_fmtdispatch(Fmt*, void*, int); +int _floatfmt(Fmt*, double); +int _fmtpad(Fmt*, int); +int _rfmtpad(Fmt*, int); +int _fmtFdFlush(Fmt*); + +int _efgfmt(Fmt*); +int _charfmt(Fmt*); +int _countfmt(Fmt*); +int _flagfmt(Fmt*); +int _percentfmt(Fmt*); +int _ifmt(Fmt*); +int _runefmt(Fmt*); +int _runesfmt(Fmt*); +int _strfmt(Fmt*); +int _badfmt(Fmt*); +int _fmtcpy(Fmt*, void*, int, int); +int _fmtrcpy(Fmt*, void*, int n); + +void _fmtlock(void); +void _fmtunlock(void); + +#define FMTCHAR(f, t, s, c)\ + do{\ + if(t + 1 > (char*)s){\ + t = _fmtflush(f, t, 1);\ + if(t != nil)\ + s = f->stop;\ + else\ + return -1;\ + }\ + *t++ = c;\ + }while(0) + +#define FMTRCHAR(f, t, s, c)\ + do{\ + if(t + 1 > (Rune*)s){\ + t = _fmtflush(f, t, sizeof(Rune));\ + if(t != nil)\ + s = f->stop;\ + else\ + return -1;\ + }\ + *t++ = c;\ + }while(0) + +#define FMTRUNE(f, t, s, r)\ + do{\ + Rune _rune;\ + int _runelen;\ + if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\ + t = _fmtflush(f, t, _runelen);\ + if(t != nil)\ + s = f->stop;\ + else\ + return -1;\ + }\ + if(r < Runeself)\ + *t++ = r;\ + else{\ + _rune = r;\ + t += runetochar(t, &_rune);\ + }\ + }while(0) diff --git a/sys/src/libc/fmt/fmtfd.c b/sys/src/libc/fmt/fmtfd.c new file mode 100755 index 000000000..db42eba7d --- /dev/null +++ b/sys/src/libc/fmt/fmtfd.c @@ -0,0 +1,31 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +/* + * public routine for final flush of a formatting buffer + * to a file descriptor; returns total char count. + */ +int +fmtfdflush(Fmt *f) +{ + if(_fmtFdFlush(f) <= 0) + return -1; + return f->nfmt; +} + +/* + * initialize an output buffer for buffered printing + */ +int +fmtfdinit(Fmt *f, int fd, char *buf, int size) +{ + f->runes = 0; + f->start = buf; + f->to = buf; + f->stop = buf + size; + f->flush = _fmtFdFlush; + f->farg = (void*)fd; + f->nfmt = 0; + return 0; +} diff --git a/sys/src/libc/fmt/fmtlock.c b/sys/src/libc/fmt/fmtlock.c new file mode 100755 index 000000000..02ae96312 --- /dev/null +++ b/sys/src/libc/fmt/fmtlock.c @@ -0,0 +1,16 @@ +#include <u.h> +#include <libc.h> + +static Lock fmtl; + +void +_fmtlock(void) +{ + lock(&fmtl); +} + +void +_fmtunlock(void) +{ + unlock(&fmtl); +} diff --git a/sys/src/libc/fmt/fmtprint.c b/sys/src/libc/fmt/fmtprint.c new file mode 100755 index 000000000..4c858b94c --- /dev/null +++ b/sys/src/libc/fmt/fmtprint.c @@ -0,0 +1,32 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + + +/* + * format a string into the output buffer + * designed for formats which themselves call fmt, + * but ignore any width flags + */ +int +fmtprint(Fmt *f, char *fmt, ...) +{ + va_list va; + int n; + + f->flags = 0; + f->width = 0; + f->prec = 0; + va = f->args; + va_start(f->args, fmt); + n = dofmt(f, fmt); + va_end(f->args); + f->flags = 0; + f->width = 0; + f->prec = 0; + f->args = va; + if(n >= 0) + return 0; + return n; +} + diff --git a/sys/src/libc/fmt/fmtquote.c b/sys/src/libc/fmt/fmtquote.c new file mode 100755 index 000000000..bede387bc --- /dev/null +++ b/sys/src/libc/fmt/fmtquote.c @@ -0,0 +1,249 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +/* + * How many bytes of output UTF will be produced by quoting (if necessary) this string? + * How many runes? How much of the input will be consumed? + * The parameter q is filled in by _quotesetup. + * The string may be UTF or Runes (s or r). + * Return count does not include NUL. + * Terminate the scan at the first of: + * NUL in input + * count exceeded in input + * count exceeded on output + * *ninp is set to number of input bytes accepted. + * nin may be <0 initially, to avoid checking input by count. + */ +void +_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout) +{ + int w; + Rune c; + + q->quoted = 0; + q->nbytesout = 0; + q->nrunesout = 0; + q->nbytesin = 0; + q->nrunesin = 0; + if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){ + if(nout < 2) + return; + q->quoted = 1; + q->nbytesout = 2; + q->nrunesout = 2; + } + for(; nin!=0; nin--){ + if(s) + w = chartorune(&c, s); + else{ + c = *r; + w = runelen(c); + } + + if(c == '\0') + break; + if(runesout){ + if(q->nrunesout+1 > nout) + break; + }else{ + if(q->nbytesout+w > nout) + break; + } + + if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){ + if(!q->quoted){ + if(runesout){ + if(1+q->nrunesout+1+1 > nout) /* no room for quotes */ + break; + }else{ + if(1+q->nbytesout+w+1 > nout) /* no room for quotes */ + break; + } + q->nrunesout += 2; /* include quotes */ + q->nbytesout += 2; /* include quotes */ + q->quoted = 1; + } + if(c == '\'') { + if(runesout){ + if(1+q->nrunesout+1 > nout) /* no room for quotes */ + break; + }else{ + if(1+q->nbytesout+w > nout) /* no room for quotes */ + break; + } + q->nbytesout++; + q->nrunesout++; /* quotes reproduce as two characters */ + } + } + + /* advance input */ + if(s) + s += w; + else + r++; + q->nbytesin += w; + q->nrunesin++; + + /* advance output */ + q->nbytesout += w; + q->nrunesout++; + } +} + +static int +qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f) +{ + Rune r, *rm, *rme; + char *t, *s, *m, *me; + Rune *rt, *rs; + ulong fl; + int nc, w; + + m = sin; + me = m + q->nbytesin; + rm = rin; + rme = rm + q->nrunesin; + + w = f->width; + fl = f->flags; + if(f->runes){ + if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0) + return -1; + }else{ + if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0) + return -1; + } + t = f->to; + s = f->stop; + rt = f->to; + rs = f->stop; + if(f->runes) + FMTRCHAR(f, rt, rs, '\''); + else + FMTRUNE(f, t, s, '\''); + for(nc = q->nrunesin; nc > 0; nc--){ + if(sin){ + r = *(uchar*)m; + if(r < Runeself) + m++; + else if((me - m) >= UTFmax || fullrune(m, me-m)) + m += chartorune(&r, m); + else + break; + }else{ + if(rm >= rme) + break; + r = *(uchar*)rm++; + } + if(f->runes){ + FMTRCHAR(f, rt, rs, r); + if(r == '\'') + FMTRCHAR(f, rt, rs, r); + }else{ + FMTRUNE(f, t, s, r); + if(r == '\'') + FMTRUNE(f, t, s, r); + } + } + + if(f->runes){ + FMTRCHAR(f, rt, rs, '\''); + USED(rs); + f->nfmt += rt - (Rune *)f->to; + f->to = rt; + if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0) + return -1; + }else{ + FMTRUNE(f, t, s, '\''); + USED(s); + f->nfmt += t - (char *)f->to; + f->to = t; + if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0) + return -1; + } + return 0; +} + +int +_quotestrfmt(int runesin, Fmt *f) +{ + int nin, outlen; + Rune *r; + char *s; + Quoteinfo q; + + nin = -1; + if(f->flags&FmtPrec) + nin = f->prec; + if(runesin){ + r = va_arg(f->args, Rune *); + s = nil; + }else{ + s = va_arg(f->args, char *); + r = nil; + } + if(!s && !r) + return _fmtcpy(f, "<nil>", 5, 5); + + if(f->flush) + outlen = 0x7FFFFFFF; /* if we can flush, no output limit */ + else if(f->runes) + outlen = (Rune*)f->stop - (Rune*)f->to; + else + outlen = (char*)f->stop - (char*)f->to; + + _quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes); +//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); + + if(runesin){ + if(!q.quoted) + return _fmtrcpy(f, r, q.nrunesin); + return qstrfmt(nil, r, &q, f); + } + + if(!q.quoted) + return _fmtcpy(f, s, q.nrunesin, q.nbytesin); + return qstrfmt(s, nil, &q, f); +} + +int +quotestrfmt(Fmt *f) +{ + return _quotestrfmt(0, f); +} + +int +quoterunestrfmt(Fmt *f) +{ + return _quotestrfmt(1, f); +} + +void +quotefmtinstall(void) +{ + fmtinstall('q', quotestrfmt); + fmtinstall('Q', quoterunestrfmt); +} + +int +_needsquotes(char *s, int *quotelenp) +{ + Quoteinfo q; + + _quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0); + *quotelenp = q.nbytesout; + + return q.quoted; +} + +int +_runeneedsquotes(Rune *r, int *quotelenp) +{ + Quoteinfo q; + + _quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0); + *quotelenp = q.nrunesout; + + return q.quoted; +} diff --git a/sys/src/libc/fmt/fmtrune.c b/sys/src/libc/fmt/fmtrune.c new file mode 100755 index 000000000..e2db137a3 --- /dev/null +++ b/sys/src/libc/fmt/fmtrune.c @@ -0,0 +1,25 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +int +fmtrune(Fmt *f, int r) +{ + Rune *rt; + char *t; + int n; + + if(f->runes){ + rt = f->to; + FMTRCHAR(f, rt, f->stop, r); + f->to = rt; + n = 1; + }else{ + t = f->to; + FMTRUNE(f, t, f->stop, r); + n = t - (char*)f->to; + f->to = t; + } + f->nfmt += n; + return 0; +} diff --git a/sys/src/libc/fmt/fmtstr.c b/sys/src/libc/fmt/fmtstr.c new file mode 100755 index 000000000..6f5821382 --- /dev/null +++ b/sys/src/libc/fmt/fmtstr.c @@ -0,0 +1,11 @@ +#include <u.h> +#include <libc.h> + +char* +fmtstrflush(Fmt *f) +{ + if(f->start == nil) + return nil; + *(char*)f->to = '\0'; + return f->start; +} diff --git a/sys/src/libc/fmt/fmtvprint.c b/sys/src/libc/fmt/fmtvprint.c new file mode 100755 index 000000000..1d6493eaa --- /dev/null +++ b/sys/src/libc/fmt/fmtvprint.c @@ -0,0 +1,31 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + + +/* + * format a string into the output buffer + * designed for formats which themselves call fmt, + * but ignore any width flags + */ +int +fmtvprint(Fmt *f, char *fmt, va_list args) +{ + va_list va; + int n; + + f->flags = 0; + f->width = 0; + f->prec = 0; + va = f->args; + f->args = args; + n = dofmt(f, fmt); + f->flags = 0; + f->width = 0; + f->prec = 0; + f->args = va; + if(n >= 0) + return 0; + return n; +} + diff --git a/sys/src/libc/fmt/fprint.c b/sys/src/libc/fmt/fprint.c new file mode 100755 index 000000000..b1376a05a --- /dev/null +++ b/sys/src/libc/fmt/fprint.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +int +fprint(int fd, char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vfprint(fd, fmt, args); + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/mkfile b/sys/src/libc/fmt/mkfile new file mode 100755 index 000000000..7930c0a47 --- /dev/null +++ b/sys/src/libc/fmt/mkfile @@ -0,0 +1,46 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a + +OFILES=\ + dofmt.$O\ + dorfmt.$O\ + errfmt.$O\ + fltfmt.$O\ + fmt.$O\ + fmtfd.$O\ + fmtlock.$O\ + fmtprint.$O\ + fmtquote.$O\ + fmtrune.$O\ + fmtstr.$O\ + fmtvprint.$O\ + fprint.$O\ + print.$O\ + runefmtstr.$O\ + runeseprint.$O\ + runesmprint.$O\ + runesnprint.$O\ + runesprint.$O\ + runevseprint.$O\ + runevsmprint.$O\ + runevsnprint.$O\ + seprint.$O\ + smprint.$O\ + snprint.$O\ + sprint.$O\ + vfprint.$O\ + vseprint.$O\ + vsmprint.$O\ + vsnprint.$O\ + +HFILES=/sys/include/libc.h\ + fmtdef.h\ + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c} + +</sys/src/cmd/mksyslib + diff --git a/sys/src/libc/fmt/print.c b/sys/src/libc/fmt/print.c new file mode 100755 index 000000000..fdbb52278 --- /dev/null +++ b/sys/src/libc/fmt/print.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +int +print(char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vfprint(1, fmt, args); + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/runefmtstr.c b/sys/src/libc/fmt/runefmtstr.c new file mode 100755 index 000000000..9ce9c131c --- /dev/null +++ b/sys/src/libc/fmt/runefmtstr.c @@ -0,0 +1,11 @@ +#include <u.h> +#include <libc.h> + +Rune* +runefmtstrflush(Fmt *f) +{ + if(f->start == nil) + return nil; + *(Rune*)f->to = '\0'; + return f->start; +} diff --git a/sys/src/libc/fmt/runeseprint.c b/sys/src/libc/fmt/runeseprint.c new file mode 100755 index 000000000..77a761e41 --- /dev/null +++ b/sys/src/libc/fmt/runeseprint.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +Rune* +runeseprint(Rune *buf, Rune *e, char *fmt, ...) +{ + Rune *p; + va_list args; + + va_start(args, fmt); + p = runevseprint(buf, e, fmt, args); + va_end(args); + return p; +} diff --git a/sys/src/libc/fmt/runesmprint.c b/sys/src/libc/fmt/runesmprint.c new file mode 100755 index 000000000..1f8b22025 --- /dev/null +++ b/sys/src/libc/fmt/runesmprint.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +Rune* +runesmprint(char *fmt, ...) +{ + va_list args; + Rune *p; + + va_start(args, fmt); + p = runevsmprint(fmt, args); + va_end(args); + return p; +} diff --git a/sys/src/libc/fmt/runesnprint.c b/sys/src/libc/fmt/runesnprint.c new file mode 100755 index 000000000..ac15ec031 --- /dev/null +++ b/sys/src/libc/fmt/runesnprint.c @@ -0,0 +1,15 @@ +#include <u.h> +#include <libc.h> + +int +runesnprint(Rune *buf, int len, char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = runevsnprint(buf, len, fmt, args); + va_end(args); + return n; +} + diff --git a/sys/src/libc/fmt/runesprint.c b/sys/src/libc/fmt/runesprint.c new file mode 100755 index 000000000..5eca8cd9a --- /dev/null +++ b/sys/src/libc/fmt/runesprint.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +int +runesprint(Rune *buf, char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = runevsnprint(buf, 256, fmt, args); + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/runevseprint.c b/sys/src/libc/fmt/runevseprint.c new file mode 100755 index 000000000..43c601e5e --- /dev/null +++ b/sys/src/libc/fmt/runevseprint.c @@ -0,0 +1,23 @@ +#include <u.h> +#include <libc.h> + +Rune* +runevseprint(Rune *buf, Rune *e, char *fmt, va_list args) +{ + Fmt f; + + if(e <= buf) + return nil; + f.runes = 1; + f.start = buf; + f.to = buf; + f.stop = e - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + f.args = args; + dofmt(&f, fmt); + *(Rune*)f.to = '\0'; + return f.to; +} + diff --git a/sys/src/libc/fmt/runevsmprint.c b/sys/src/libc/fmt/runevsmprint.c new file mode 100755 index 000000000..4db326297 --- /dev/null +++ b/sys/src/libc/fmt/runevsmprint.c @@ -0,0 +1,70 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +static int +runeFmtStrFlush(Fmt *f) +{ + Rune *s; + int n; + + if(f->start == nil) + return 0; + n = (int)(uintptr)f->farg; + n *= 2; + s = f->start; + f->start = realloc(s, sizeof(Rune)*n); + if(f->start == nil){ + f->farg = nil; + f->to = nil; + f->stop = nil; + free(s); + return 0; + } + f->farg = (void*)n; + f->to = (Rune*)f->start + ((Rune*)f->to - s); + f->stop = (Rune*)f->start + n - 1; + return 1; +} + +int +runefmtstrinit(Fmt *f) +{ + int n; + + memset(f, 0, sizeof *f); + f->runes = 1; + n = 32; + f->start = malloc(sizeof(Rune)*n); + if(f->start == nil) + return -1; + f->to = f->start; + f->stop = (Rune*)f->start + n - 1; + f->flush = runeFmtStrFlush; + f->farg = (void*)n; + f->nfmt = 0; + return 0; +} + +/* + * print into an allocated string buffer + */ +Rune* +runevsmprint(char *fmt, va_list args) +{ + Fmt f; + int n; + + if(runefmtstrinit(&f) < 0) + return nil; + f.args = args; + n = dofmt(&f, fmt); + if(f.start == nil) + return nil; + if(n < 0){ + free(f.start); + return nil; + } + *(Rune*)f.to = '\0'; + return f.start; +} diff --git a/sys/src/libc/fmt/runevsnprint.c b/sys/src/libc/fmt/runevsnprint.c new file mode 100755 index 000000000..61fe4af81 --- /dev/null +++ b/sys/src/libc/fmt/runevsnprint.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> + +int +runevsnprint(Rune *buf, int len, char *fmt, va_list args) +{ + Fmt f; + + if(len <= 0) + return -1; + f.runes = 1; + f.start = buf; + f.to = buf; + f.stop = buf + len - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + f.args = args; + dofmt(&f, fmt); + *(Rune*)f.to = '\0'; + return (Rune*)f.to - buf; +} diff --git a/sys/src/libc/fmt/seprint.c b/sys/src/libc/fmt/seprint.c new file mode 100755 index 000000000..519c1aa61 --- /dev/null +++ b/sys/src/libc/fmt/seprint.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +char* +seprint(char *buf, char *e, char *fmt, ...) +{ + char *p; + va_list args; + + va_start(args, fmt); + p = vseprint(buf, e, fmt, args); + va_end(args); + return p; +} diff --git a/sys/src/libc/fmt/smprint.c b/sys/src/libc/fmt/smprint.c new file mode 100755 index 000000000..7be117c29 --- /dev/null +++ b/sys/src/libc/fmt/smprint.c @@ -0,0 +1,15 @@ +#include <u.h> +#include <libc.h> + +char* +smprint(char *fmt, ...) +{ + va_list args; + char *p; + + va_start(args, fmt); + p = vsmprint(fmt, args); + va_end(args); + setmalloctag(p, getcallerpc(&fmt)); + return p; +} diff --git a/sys/src/libc/fmt/snprint.c b/sys/src/libc/fmt/snprint.c new file mode 100755 index 000000000..8a4681392 --- /dev/null +++ b/sys/src/libc/fmt/snprint.c @@ -0,0 +1,15 @@ +#include <u.h> +#include <libc.h> + +int +snprint(char *buf, int len, char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vsnprint(buf, len, fmt, args); + va_end(args); + return n; +} + diff --git a/sys/src/libc/fmt/sprint.c b/sys/src/libc/fmt/sprint.c new file mode 100755 index 000000000..2da6d925e --- /dev/null +++ b/sys/src/libc/fmt/sprint.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +int +sprint(char *buf, char *fmt, ...) +{ + int n; + va_list args; + + va_start(args, fmt); + n = vsnprint(buf, 65536, fmt, args); /* big number, but sprint is deprecated anyway */ + va_end(args); + return n; +} diff --git a/sys/src/libc/fmt/vfprint.c b/sys/src/libc/fmt/vfprint.c new file mode 100755 index 000000000..63c9349f0 --- /dev/null +++ b/sys/src/libc/fmt/vfprint.c @@ -0,0 +1,34 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +/* + * generic routine for flushing a formatting buffer + * to a file descriptor + */ +int +_fmtFdFlush(Fmt *f) +{ + int n; + + n = (char*)f->to - (char*)f->start; + if(n && write((int)(uintptr)f->farg, f->start, n) != n) + return 0; + f->to = f->start; + return 1; +} + +int +vfprint(int fd, char *fmt, va_list args) +{ + Fmt f; + char buf[256]; + int n; + + fmtfdinit(&f, fd, buf, sizeof(buf)); + f.args = args; + n = dofmt(&f, fmt); + if(n > 0 && _fmtFdFlush(&f) == 0) + return -1; + return n; +} diff --git a/sys/src/libc/fmt/vseprint.c b/sys/src/libc/fmt/vseprint.c new file mode 100755 index 000000000..72d02f7fa --- /dev/null +++ b/sys/src/libc/fmt/vseprint.c @@ -0,0 +1,23 @@ +#include <u.h> +#include <libc.h> + +char* +vseprint(char *buf, char *e, char *fmt, va_list args) +{ + Fmt f; + + if(e <= buf) + return nil; + f.runes = 0; + f.start = buf; + f.to = buf; + f.stop = e - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + f.args = args; + dofmt(&f, fmt); + *(char*)f.to = '\0'; + return f.to; +} + diff --git a/sys/src/libc/fmt/vsmprint.c b/sys/src/libc/fmt/vsmprint.c new file mode 100755 index 000000000..d183a5826 --- /dev/null +++ b/sys/src/libc/fmt/vsmprint.c @@ -0,0 +1,70 @@ +#include <u.h> +#include <libc.h> +#include "fmtdef.h" + +static int +fmtStrFlush(Fmt *f) +{ + char *s; + int n; + + if(f->start == nil) + return 0; + n = (int)(uintptr)f->farg; + n *= 2; + s = f->start; + f->start = realloc(s, n); + if(f->start == nil){ + f->farg = nil; + f->to = nil; + f->stop = nil; + free(s); + return 0; + } + f->farg = (void*)n; + f->to = (char*)f->start + ((char*)f->to - s); + f->stop = (char*)f->start + n - 1; + return 1; +} + +int +fmtstrinit(Fmt *f) +{ + int n; + + memset(f, 0, sizeof *f); + f->runes = 0; + n = 32; + f->start = malloc(n); + if(f->start == nil) + return -1; + f->to = f->start; + f->stop = (char*)f->start + n - 1; + f->flush = fmtStrFlush; + f->farg = (void*)n; + f->nfmt = 0; + return 0; +} + +/* + * print into an allocated string buffer + */ +char* +vsmprint(char *fmt, va_list args) +{ + Fmt f; + int n; + + if(fmtstrinit(&f) < 0) + return nil; + f.args = args; + n = dofmt(&f, fmt); + if(f.start == nil) + return nil; + if(n < 0){ + free(f.start); + return nil; + } + *(char*)f.to = '\0'; + return f.start; +} diff --git a/sys/src/libc/fmt/vsnprint.c b/sys/src/libc/fmt/vsnprint.c new file mode 100755 index 000000000..bd2049684 --- /dev/null +++ b/sys/src/libc/fmt/vsnprint.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> + +int +vsnprint(char *buf, int len, char *fmt, va_list args) +{ + Fmt f; + + if(len <= 0) + return -1; + f.runes = 0; + f.start = buf; + f.to = buf; + f.stop = buf + len - 1; + f.flush = nil; + f.farg = nil; + f.nfmt = 0; + f.args = args; + dofmt(&f, fmt); + *(char*)f.to = '\0'; + return (char*)f.to - buf; +} 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); +} diff --git a/sys/src/libc/mkfile b/sys/src/libc/mkfile new file mode 100755 index 000000000..3634076f8 --- /dev/null +++ b/sys/src/libc/mkfile @@ -0,0 +1,51 @@ +</$objtype/mkfile + +PORTDIRS=9sys 9syscall fmt port +DIRS=$PORTDIRS $CPUS +OLDCPUS=68000 68020 sparc + +all install:V: + for(i in $PORTDIRS $objtype)@{ + echo $i + cd $i + mk $MKFLAGS install + } + +clean:V: + for(i in $DIRS)@{ + echo $i + cd $i + mk $MKFLAGS clean + } + +nuke:V: + for(i in $PORTDIRS $objtype)@{ + echo $i + cd $i + mk $MKFLAGS nuke + } + # do not nuke other objtypes + for(i in $CPUS)@{ + echo $i + cd $i + mk $MKFLAGS clean + } + +update:V: + for(i in $DIRS)@{ + echo $i + cd $i + mk $MKFLAGS update + } + update $UPDATEFLAGS /386/lib/libc.a + +installall:V: + for(objtype in $CPUS) mk $MKFLAGS install + +everything:V: + rm -f */*.[012456789kqvxz] + for(objtype in $CPUS $OLDCPUS)@{ + echo $objtype + mk $MKFLAGS install + } + rm -f */*.[012456789kqvxz] diff --git a/sys/src/libc/port/_assert.c b/sys/src/libc/port/_assert.c new file mode 100755 index 000000000..929e4c113 --- /dev/null +++ b/sys/src/libc/port/_assert.c @@ -0,0 +1,13 @@ +#include <u.h> +#include <libc.h> + +void (*__assert)(char*); + +void +_assert(char *s) +{ + if(__assert) + (*__assert)(s); + fprint(2, "assert failed: %s\n", s); + abort(); +} diff --git a/sys/src/libc/port/abs.c b/sys/src/libc/port/abs.c new file mode 100755 index 000000000..7e8adda55 --- /dev/null +++ b/sys/src/libc/port/abs.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> + +int +abs(int a) +{ + if(a < 0) + return -a; + return a; +} + +long +labs(long a) +{ + if(a < 0) + return -a; + return a; +} diff --git a/sys/src/libc/port/asin.c b/sys/src/libc/port/asin.c new file mode 100755 index 000000000..7cb1455ed --- /dev/null +++ b/sys/src/libc/port/asin.c @@ -0,0 +1,40 @@ +/* + * asin(arg) and acos(arg) return the arcsin, arccos, + * respectively of their arguments. + * + * Arctan is called after appropriate range reduction. + */ + +#include <u.h> +#include <libc.h> + +double +asin(double arg) +{ + double temp; + int sign; + + sign = 0; + if(arg < 0) { + arg = -arg; + sign++; + } + if(arg > 1) + return NaN(); + temp = sqrt(1 - arg*arg); + if(arg > 0.7) + temp = PIO2 - atan(temp/arg); + else + temp = atan(arg/temp); + if(sign) + temp = -temp; + return temp; +} + +double +acos(double arg) +{ + if(arg > 1 || arg < -1) + return NaN(); + return PIO2 - asin(arg); +} diff --git a/sys/src/libc/port/atan.c b/sys/src/libc/port/atan.c new file mode 100755 index 000000000..4de3a2218 --- /dev/null +++ b/sys/src/libc/port/atan.c @@ -0,0 +1,78 @@ +/* + floating-point arctangent + + atan returns the value of the arctangent of its + argument in the range [-pi/2,pi/2]. + + atan2 returns the arctangent of arg1/arg2 + in the range [-pi,pi]. + + there are no error returns. + + coefficients are #5077 from Hart & Cheney. (19.56D) +*/ + +#include <u.h> +#include <libc.h> + +#define sq2p1 2.414213562373095048802e0 +#define sq2m1 .414213562373095048802e0 +#define p4 .161536412982230228262e2 +#define p3 .26842548195503973794141e3 +#define p2 .11530293515404850115428136e4 +#define p1 .178040631643319697105464587e4 +#define p0 .89678597403663861959987488e3 +#define q4 .5895697050844462222791e2 +#define q3 .536265374031215315104235e3 +#define q2 .16667838148816337184521798e4 +#define q1 .207933497444540981287275926e4 +#define q0 .89678597403663861962481162e3 + + +/* + xatan evaluates a series valid in the + range [-0.414...,+0.414...]. (tan(pi/8)) + */ + +static +double +xatan(double arg) +{ + double argsq, value; + + argsq = arg*arg; + value = ((((p4*argsq + p3)*argsq + p2)*argsq + p1)*argsq + p0); + value = value/(((((argsq + q4)*argsq + q3)*argsq + q2)*argsq + q1)*argsq + q0); + return value*arg; +} + +/* + satan reduces its argument (known to be positive) + to the range [0,0.414...] and calls xatan. + */ + +static +double +satan(double arg) +{ + + if(arg < sq2m1) + return xatan(arg); + if(arg > sq2p1) + return PIO2 - xatan(1/arg); + return PIO2/2 + xatan((arg-1)/(arg+1)); +} + +/* + atan makes its argument positive and + calls the inner routine satan. + */ + +double +atan(double arg) +{ + + if(arg > 0) + return satan(arg); + return -satan(-arg); +} diff --git a/sys/src/libc/port/atan2.c b/sys/src/libc/port/atan2.c new file mode 100755 index 000000000..480eb4c67 --- /dev/null +++ b/sys/src/libc/port/atan2.c @@ -0,0 +1,24 @@ +#include <u.h> +#include <libc.h> +/* + atan2 discovers what quadrant the angle + is in and calls atan. +*/ + +double +atan2(double arg1, double arg2) +{ + + if(arg1+arg2 == arg1) { + if(arg1 >= 0) + return PIO2; + return -PIO2; + } + arg1 = atan(arg1/arg2); + if(arg2 < 0) { + if(arg1 <= 0) + return arg1 + PI; + return arg1 - PI; + } + return arg1; +} diff --git a/sys/src/libc/port/atexit.c b/sys/src/libc/port/atexit.c new file mode 100755 index 000000000..e9cb6c297 --- /dev/null +++ b/sys/src/libc/port/atexit.c @@ -0,0 +1,60 @@ +#include <u.h> +#include <libc.h> + +#define NEXIT 33 + +typedef struct Onex Onex; +struct Onex{ + void (*f)(void); + int pid; +}; + +static Lock onexlock; +Onex onex[NEXIT]; + +int +atexit(void (*f)(void)) +{ + int i; + + lock(&onexlock); + for(i=0; i<NEXIT; i++) + if(onex[i].f == 0) { + onex[i].pid = getpid(); + onex[i].f = f; + unlock(&onexlock); + return 1; + } + unlock(&onexlock); + return 0; +} + +void +atexitdont(void (*f)(void)) +{ + int i, pid; + + pid = getpid(); + for(i=0; i<NEXIT; i++) + if(onex[i].f == f && onex[i].pid == pid) + onex[i].f = 0; +} + +#pragma profile off + +void +exits(char *s) +{ + int i, pid; + void (*f)(void); + + pid = getpid(); + for(i = NEXIT-1; i >= 0; i--) + if((f = onex[i].f) && pid == onex[i].pid) { + onex[i].f = 0; + (*f)(); + } + _exits(s); +} + +#pragma profile on diff --git a/sys/src/libc/port/atnotify.c b/sys/src/libc/port/atnotify.c new file mode 100755 index 000000000..60e8ad0c0 --- /dev/null +++ b/sys/src/libc/port/atnotify.c @@ -0,0 +1,58 @@ +#include <u.h> +#include <libc.h> + +#define NFN 33 +static int (*onnot[NFN])(void*, char*); +static Lock onnotlock; + +static +void +notifier(void *v, char *s) +{ + int i; + + for(i=0; i<NFN; i++) + if(onnot[i] && ((*onnot[i])(v, s))){ + noted(NCONT); + return; + } + noted(NDFLT); +} + +int +atnotify(int (*f)(void*, char*), int in) +{ + int i, n, ret; + static int init; + + if(!init){ + notify(notifier); + init = 1; /* assign = */ + } + ret = 0; + lock(&onnotlock); + if(in){ + for(i=0; i<NFN; i++) + if(onnot[i] == 0) { + onnot[i] = f; + ret = 1; + break; + } + }else{ + n = 0; + for(i=0; i<NFN; i++) + if(onnot[i]){ + if(ret==0 && onnot[i]==f){ + onnot[i] = 0; + ret = 1; + }else + n++; + } + if(n == 0){ + init = 0; + notify(0); + } + } + unlock(&onnotlock); + return ret; +} diff --git a/sys/src/libc/port/atof.c b/sys/src/libc/port/atof.c new file mode 100755 index 000000000..ed8cbeeb8 --- /dev/null +++ b/sys/src/libc/port/atof.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +double +atof(char *cp) +{ + return strtod(cp, 0); +} diff --git a/sys/src/libc/port/atol.c b/sys/src/libc/port/atol.c new file mode 100755 index 000000000..6928da7bd --- /dev/null +++ b/sys/src/libc/port/atol.c @@ -0,0 +1,53 @@ +#include <u.h> +#include <libc.h> + +long +atol(char *s) +{ + long n; + int f, c; + + n = 0; + f = 0; + while(*s == ' ' || *s == '\t') + s++; + if(*s == '-' || *s == '+') { + if(*s++ == '-') + f = 1; + while(*s == ' ' || *s == '\t') + s++; + } + if(s[0]=='0' && s[1]) { + if(s[1]=='x' || s[1]=='X'){ + s += 2; + for(;;) { + c = *s; + if(c >= '0' && c <= '9') + n = n*16 + c - '0'; + else + if(c >= 'a' && c <= 'f') + n = n*16 + c - 'a' + 10; + else + if(c >= 'A' && c <= 'F') + n = n*16 + c - 'A' + 10; + else + break; + s++; + } + } else + while(*s >= '0' && *s <= '7') + n = n*8 + *s++ - '0'; + } else + while(*s >= '0' && *s <= '9') + n = n*10 + *s++ - '0'; + if(f) + n = -n; + return n; +} + +int +atoi(char *s) +{ + + return atol(s); +} diff --git a/sys/src/libc/port/atoll.c b/sys/src/libc/port/atoll.c new file mode 100755 index 000000000..b4497de59 --- /dev/null +++ b/sys/src/libc/port/atoll.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +vlong +atoll(char *s) +{ + return strtoll(s, nil, 0); +} diff --git a/sys/src/libc/port/charstod.c b/sys/src/libc/port/charstod.c new file mode 100755 index 000000000..0df775481 --- /dev/null +++ b/sys/src/libc/port/charstod.c @@ -0,0 +1,81 @@ +#include <u.h> +#include <libc.h> + +/* + * Reads a floating-point number by interpreting successive characters + * returned by (*f)(vp). The last call it makes to f terminates the + * scan, so is not a character in the number. It may therefore be + * necessary to back up the input stream up one byte after calling charstod. + */ + +#define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp) + +double +charstod(int(*f)(void*), void *vp) +{ + char str[400], *s, *e, *start; + int c; + + s = str; + e = str + sizeof str - 1; + c = (*f)(vp); + while(c == ' ' || c == '\t') + c = (*f)(vp); + if(c == '-' || c == '+'){ + ADVANCE; + } + start = s; + while(c >= '0' && c <= '9'){ + ADVANCE; + } + if(c == '.'){ + ADVANCE; + while(c >= '0' && c <= '9'){ + ADVANCE; + } + } + if(s > start && (c == 'e' || c == 'E')){ + ADVANCE; + if(c == '-' || c == '+'){ + ADVANCE; + } + while(c >= '0' && c <= '9'){ + ADVANCE; + } + }else if(s == start && (c == 'i' || c == 'I')){ + ADVANCE; + if(c != 'n' && c != 'N') + return NaN(); + ADVANCE; + if(c != 'f' && c != 'F') + return NaN(); + ADVANCE; + if(c != 'i' && c != 'I') + return NaN(); + ADVANCE; + if(c != 'n' && c != 'N') + return NaN(); + ADVANCE; + if(c != 'i' && c != 'I') + return NaN(); + ADVANCE; + if(c != 't' && c != 'T') + return NaN(); + ADVANCE; + if(c != 'y' && c != 'Y') + return NaN(); + ADVANCE; /* so caller can back up uniformly */ + USED(c); + }else if(s == str && (c == 'n' || c == 'N')){ + ADVANCE; + if(c != 'a' && c != 'A') + return NaN(); + ADVANCE; + if(c != 'n' && c != 'N') + return NaN(); + ADVANCE; /* so caller can back up uniformly */ + USED(c); + } + *s = 0; + return strtod(str, &s); +} diff --git a/sys/src/libc/port/cistrcmp.c b/sys/src/libc/port/cistrcmp.c new file mode 100755 index 000000000..a545615b7 --- /dev/null +++ b/sys/src/libc/port/cistrcmp.c @@ -0,0 +1,26 @@ +#include <u.h> +#include <libc.h> + +int +cistrcmp(char *s1, char *s2) +{ + int c1, c2; + + while(*s1){ + c1 = *(uchar*)s1++; + c2 = *(uchar*)s2++; + + if(c1 == c2) + continue; + + if(c1 >= 'A' && c1 <= 'Z') + c1 -= 'A' - 'a'; + + if(c2 >= 'A' && c2 <= 'Z') + c2 -= 'A' - 'a'; + + if(c1 != c2) + return c1 - c2; + } + return -*s2; +} diff --git a/sys/src/libc/port/cistrncmp.c b/sys/src/libc/port/cistrncmp.c new file mode 100755 index 000000000..8f24d411f --- /dev/null +++ b/sys/src/libc/port/cistrncmp.c @@ -0,0 +1,28 @@ +#include <u.h> +#include <libc.h> + +int +cistrncmp(char *s1, char *s2, int n) +{ + int c1, c2; + + while(*s1 && n-- > 0){ + c1 = *(uchar*)s1++; + c2 = *(uchar*)s2++; + + if(c1 == c2) + continue; + + if(c1 >= 'A' && c1 <= 'Z') + c1 -= 'A' - 'a'; + + if(c2 >= 'A' && c2 <= 'Z') + c2 -= 'A' - 'a'; + + if(c1 != c2) + return c1 - c2; + } + if(n <= 0) + return 0; + return -*s2; +} diff --git a/sys/src/libc/port/cistrstr.c b/sys/src/libc/port/cistrstr.c new file mode 100755 index 000000000..0a1132266 --- /dev/null +++ b/sys/src/libc/port/cistrstr.c @@ -0,0 +1,23 @@ +#include <u.h> +#include <libc.h> + +char* +cistrstr(char *s, char *sub) +{ + int c, csub, n; + + csub = *sub; + if(csub == '\0') + return s; + if(csub >= 'A' && csub <= 'Z') + csub -= 'A' - 'a'; + sub++; + n = strlen(sub); + for(; c = *s; s++){ + if(c >= 'A' && c <= 'Z') + c -= 'A' - 'a'; + if(c == csub && cistrncmp(s+1, sub, n) == 0) + return s; + } + return nil; +} diff --git a/sys/src/libc/port/cleanname.c b/sys/src/libc/port/cleanname.c new file mode 100755 index 000000000..1dae7bb84 --- /dev/null +++ b/sys/src/libc/port/cleanname.c @@ -0,0 +1,63 @@ +#include <u.h> +#include <libc.h> + +/* + * In place, rewrite name to compress multiple /, eliminate ., and process .. + */ +#define SEP(x) ((x)=='/' || (x) == 0) +char* +cleanname(char *name) +{ + char *p, *q, *dotdot; + int rooted, erasedprefix; + + rooted = name[0] == '/'; + erasedprefix = 0; + + /* + * invariants: + * p points at beginning of path element we're considering. + * q points just past the last path element we wrote (no slash). + * dotdot points just past the point where .. cannot backtrack + * any further (no slash). + */ + p = q = dotdot = name+rooted; + while(*p) { + if(p[0] == '/') /* null element */ + p++; + else if(p[0] == '.' && SEP(p[1])) { + if(p == name) + erasedprefix = 1; + p += 1; /* don't count the separator in case it is nul */ + } else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) { + p += 2; + if(q > dotdot) { /* can backtrack */ + while(--q > dotdot && *q != '/') + ; + } else if(!rooted) { /* /.. is / but ./../ is .. */ + if(q != name) + *q++ = '/'; + *q++ = '.'; + *q++ = '.'; + dotdot = q; + } + if(q == name) + erasedprefix = 1; /* erased entire path via dotdot */ + } else { /* real path element */ + if(q != name+rooted) + *q++ = '/'; + while((*q = *p) != '/' && *q != 0) + p++, q++; + } + } + if(q == name) /* empty string is really ``.'' */ + *q++ = '.'; + *q = '\0'; + if(erasedprefix && name[0] == '#'){ + /* this was not a #x device path originally - make it not one now */ + memmove(name+2, name, strlen(name)+1); + name[0] = '.'; + name[1] = '/'; + } + return name; +} diff --git a/sys/src/libc/port/crypt.c b/sys/src/libc/port/crypt.c new file mode 100755 index 000000000..0524c9422 --- /dev/null +++ b/sys/src/libc/port/crypt.c @@ -0,0 +1,68 @@ +/* + * Data Encryption Standard + * D.P.Mitchell 83/06/08. + * + * block_cipher(key, block, decrypting) + * + * these routines use the non-standard 7 byte format + * for DES keys. + */ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <libsec.h> + +/* + * destructively encrypt the buffer, which + * must be at least 8 characters long. + */ +int +encrypt(void *key, void *vbuf, int n) +{ + ulong ekey[32]; + uchar *buf; + int i, r; + + if(n < 8) + return 0; + key_setup(key, ekey); + buf = vbuf; + n--; + r = n % 7; + n /= 7; + for(i = 0; i < n; i++){ + block_cipher(ekey, buf, 0); + buf += 7; + } + if(r) + block_cipher(ekey, buf - 7 + r, 0); + return 1; +} + +/* + * destructively decrypt the buffer, which + * must be at least 8 characters long. + */ +int +decrypt(void *key, void *vbuf, int n) +{ + ulong ekey[128]; + uchar *buf; + int i, r; + + if(n < 8) + return 0; + key_setup(key, ekey); + buf = vbuf; + n--; + r = n % 7; + n /= 7; + buf += n * 7; + if(r) + block_cipher(ekey, buf - 7 + r, 1); + for(i = 0; i < n; i++){ + buf -= 7; + block_cipher(ekey, buf, 1); + } + return 1; +} diff --git a/sys/src/libc/port/ctype.c b/sys/src/libc/port/ctype.c new file mode 100755 index 000000000..cfe1ed48a --- /dev/null +++ b/sys/src/libc/port/ctype.c @@ -0,0 +1,25 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +uchar _ctype[256] = +{ +/* 0 1 2 3 4 5 6 7 */ + +/* 0*/ _C, _C, _C, _C, _C, _C, _C, _C, +/* 10*/ _C, _S|_C, _S|_C, _S|_C, _S|_C, _S|_C, _C, _C, +/* 20*/ _C, _C, _C, _C, _C, _C, _C, _C, +/* 30*/ _C, _C, _C, _C, _C, _C, _C, _C, +/* 40*/ _S|_B, _P, _P, _P, _P, _P, _P, _P, +/* 50*/ _P, _P, _P, _P, _P, _P, _P, _P, +/* 60*/ _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, _N|_X, +/* 70*/ _N|_X, _N|_X, _P, _P, _P, _P, _P, _P, +/*100*/ _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, +/*110*/ _U, _U, _U, _U, _U, _U, _U, _U, +/*120*/ _U, _U, _U, _U, _U, _U, _U, _U, +/*130*/ _U, _U, _U, _P, _P, _P, _P, _P, +/*140*/ _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, +/*150*/ _L, _L, _L, _L, _L, _L, _L, _L, +/*160*/ _L, _L, _L, _L, _L, _L, _L, _L, +/*170*/ _L, _L, _L, _P, _P, _P, _P, _C, +}; diff --git a/sys/src/libc/port/encodefmt.c b/sys/src/libc/port/encodefmt.c new file mode 100755 index 000000000..721a58c9f --- /dev/null +++ b/sys/src/libc/port/encodefmt.c @@ -0,0 +1,77 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +int +encodefmt(Fmt *f) +{ + char *out; + char *buf; + int len; + int ilen; + int rv; + uchar *b; + char *p; + char obuf[64]; // rsc optimization + + if(!(f->flags&FmtPrec) || f->prec < 1) + goto error; + + b = va_arg(f->args, uchar*); + if(b == 0) + return fmtstrcpy(f, "<nil>"); + + ilen = f->prec; + f->prec = 0; + f->flags &= ~FmtPrec; + switch(f->r){ + case '<': + len = (8*ilen+4)/5 + 3; + break; + case '[': + len = (8*ilen+5)/6 + 4; + break; + case 'H': + len = 2*ilen + 1; + break; + default: + goto error; + } + + if(len > sizeof(obuf)){ + buf = malloc(len); + if(buf == nil) + goto error; + } else + buf = obuf; + + // convert + out = buf; + switch(f->r){ + case '<': + rv = enc32(out, len, b, ilen); + break; + case '[': + rv = enc64(out, len, b, ilen); + break; + case 'H': + rv = enc16(out, len, b, ilen); + if(rv >= 0 && (f->flags & FmtLong)) + for(p = buf; *p; p++) + *p = tolower(*p); + break; + default: + rv = -1; + break; + } + if(rv < 0) + goto error; + + fmtstrcpy(f, buf); + if(buf != obuf) + free(buf); + return 0; + +error: + return fmtstrcpy(f, "<encodefmt>"); +} diff --git a/sys/src/libc/port/execl.c b/sys/src/libc/port/execl.c new file mode 100755 index 000000000..40574fe63 --- /dev/null +++ b/sys/src/libc/port/execl.c @@ -0,0 +1,9 @@ +#include <u.h> +#include <libc.h> + +int +execl(char *f, ...) +{ + + return exec(f, &f+1); +} diff --git a/sys/src/libc/port/exp.c b/sys/src/libc/port/exp.c new file mode 100755 index 000000000..0a3e9e444 --- /dev/null +++ b/sys/src/libc/port/exp.c @@ -0,0 +1,40 @@ +/* + exp returns the exponential function of its + floating-point argument. + + The coefficients are #1069 from Hart and Cheney. (22.35D) +*/ + +#include <u.h> +#include <libc.h> + +#define p0 .2080384346694663001443843411e7 +#define p1 .3028697169744036299076048876e5 +#define p2 .6061485330061080841615584556e2 +#define q0 .6002720360238832528230907598e7 +#define q1 .3277251518082914423057964422e6 +#define q2 .1749287689093076403844945335e4 +#define log2e 1.4426950408889634073599247 +#define sqrt2 1.4142135623730950488016887 +#define maxf 10000 + +double +exp(double arg) +{ + double fract, temp1, temp2, xsq; + int ent; + + if(arg == 0) + return 1; + if(arg < -maxf) + return 0; + if(arg > maxf) + return Inf(1); + arg *= log2e; + ent = floor(arg); + fract = (arg-ent) - 0.5; + xsq = fract*fract; + temp1 = ((p2*xsq+p1)*xsq+p0)*fract; + temp2 = ((xsq+q2)*xsq+q1)*xsq + q0; + return ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent); +} diff --git a/sys/src/libc/port/fabs.c b/sys/src/libc/port/fabs.c new file mode 100755 index 000000000..9e90a6786 --- /dev/null +++ b/sys/src/libc/port/fabs.c @@ -0,0 +1,11 @@ +#include <u.h> +#include <libc.h> + +double +fabs(double arg) +{ + + if(arg < 0) + return -arg; + return arg; +} diff --git a/sys/src/libc/port/floor.c b/sys/src/libc/port/floor.c new file mode 100755 index 000000000..e1ee76489 --- /dev/null +++ b/sys/src/libc/port/floor.c @@ -0,0 +1,27 @@ +#include <u.h> +#include <libc.h> +/* + * floor and ceil-- greatest integer <= arg + * (resp least >=) + */ + +double +floor(double d) +{ + double fract; + + if(d < 0) { + fract = modf(-d, &d); + if(fract != 0.0) + d += 1; + d = -d; + } else + modf(d, &d); + return d; +} + +double +ceil(double d) +{ + return -floor(-d); +} diff --git a/sys/src/libc/port/fmod.c b/sys/src/libc/port/fmod.c new file mode 100755 index 000000000..3b97a5b43 --- /dev/null +++ b/sys/src/libc/port/fmod.c @@ -0,0 +1,31 @@ +#include <u.h> +#include <libc.h> + +/* + * floating-point mod function without infinity or NaN checking + */ +double +fmod (double x, double y) +{ + int sign, yexp, rexp; + double r, yfr, rfr; + + if (y == 0) + return x; + if (y < 0) + y = -y; + yfr = frexp(y, &yexp); + sign = 0; + if(x < 0) { + r = -x; + sign++; + } else + r = x; + while(r >= y) { + rfr = frexp(r, &rexp); + r -= ldexp(y, rexp - yexp - (rfr < yfr)); + } + if(sign) + r = -r; + return r; +} diff --git a/sys/src/libc/port/frand.c b/sys/src/libc/port/frand.c new file mode 100755 index 000000000..e13e1d860 --- /dev/null +++ b/sys/src/libc/port/frand.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +#define MASK 0x7fffffffL +#define NORM (1.0/(1.0+MASK)) + +double +frand(void) +{ + double x; + + do { + x = lrand() * NORM; + x = (x + lrand()) * NORM; + } while(x >= 1); + return x; +} diff --git a/sys/src/libc/port/frexp.c b/sys/src/libc/port/frexp.c new file mode 100755 index 000000000..7809bd151 --- /dev/null +++ b/sys/src/libc/port/frexp.c @@ -0,0 +1,105 @@ +#include <u.h> +#include <libc.h> + +/* + * this is big/little endian non-portable + * it gets the endian from the FPdbleword + * union in u.h. + */ +#define MASK 0x7ffL +#define SHIFT 20 +#define BIAS 1022L + +double +frexp(double d, int *ep) +{ + FPdbleword x; + + if(d == 0) { + *ep = 0; + return 0; + } + x.x = d; + *ep = ((x.hi >> SHIFT) & MASK) - BIAS; + x.hi &= ~(MASK << SHIFT); + x.hi |= BIAS << SHIFT; + return x.x; +} + +double +ldexp(double d, int deltae) +{ + int e, bits; + FPdbleword x; + ulong z; + + if(d == 0) + return 0; + x.x = d; + e = (x.hi >> SHIFT) & MASK; + if(deltae >= 0 || e+deltae >= 1){ /* no underflow */ + e += deltae; + if(e >= MASK){ /* overflow */ + if(d < 0) + return Inf(-1); + return Inf(1); + } + }else{ /* underflow gracefully */ + deltae = -deltae; + /* need to shift d right deltae */ + if(e > 1){ /* shift e-1 by exponent manipulation */ + deltae -= e-1; + e = 1; + } + if(deltae > 0 && e==1){ /* shift 1 by switch from 1.fff to 0.1ff */ + deltae--; + e = 0; + x.lo >>= 1; + x.lo |= (x.hi&1)<<31; + z = x.hi & ((1<<SHIFT)-1); + x.hi &= ~((1<<SHIFT)-1); + x.hi |= (1<<(SHIFT-1)) | (z>>1); + } + while(deltae > 0){ /* shift bits down */ + bits = deltae; + if(bits > SHIFT) + bits = SHIFT; + x.lo >>= bits; + x.lo |= (x.hi&((1<<bits)-1)) << (32-bits); + z = x.hi & ((1<<SHIFT)-1); + x.hi &= ~((1<<SHIFT)-1); + x.hi |= z>>bits; + deltae -= bits; + } + } + x.hi &= ~(MASK << SHIFT); + x.hi |= (long)e << SHIFT; + return x.x; +} + +double +modf(double d, double *ip) +{ + FPdbleword x; + int e; + + if(d < 1) { + if(d < 0) { + x.x = modf(-d, ip); + *ip = -*ip; + return -x.x; + } + *ip = 0; + return d; + } + x.x = d; + e = ((x.hi >> SHIFT) & MASK) - BIAS; + if(e <= SHIFT+1) { + x.hi &= ~(0x1fffffL >> e); + x.lo = 0; + } else + if(e <= SHIFT+33) + x.lo &= ~(0x7fffffffL >> (e-SHIFT-2)); + *ip = x.x; + return d - x.x; +} diff --git a/sys/src/libc/port/getcallerpc.c b/sys/src/libc/port/getcallerpc.c new file mode 100755 index 000000000..f45f8c00c --- /dev/null +++ b/sys/src/libc/port/getcallerpc.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +uintptr +getcallerpc(void*) +{ + return 0; +} diff --git a/sys/src/libc/port/getfields.c b/sys/src/libc/port/getfields.c new file mode 100755 index 000000000..b12c0cc2b --- /dev/null +++ b/sys/src/libc/port/getfields.c @@ -0,0 +1,37 @@ +#include <u.h> +#include <libc.h> + +int +getfields(char *str, char **args, int max, int mflag, char *set) +{ + Rune r; + int nr, intok, narg; + + if(max <= 0) + return 0; + + narg = 0; + args[narg] = str; + if(!mflag) + narg++; + intok = 0; + for(;; str += nr) { + nr = chartorune(&r, str); + if(r == 0) + break; + if(utfrune(set, r)) { + if(narg >= max) + break; + *str = 0; + intok = 0; + args[narg] = str + nr; + if(!mflag) + narg++; + } else { + if(!intok && mflag) + narg++; + intok = 1; + } + } + return narg; +} diff --git a/sys/src/libc/port/getuser.c b/sys/src/libc/port/getuser.c new file mode 100755 index 000000000..a987244ee --- /dev/null +++ b/sys/src/libc/port/getuser.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> + +char * +getuser(void) +{ + static char user[64]; + int fd; + int n; + + fd = open("/dev/user", OREAD); + if(fd < 0) + return "none"; + n = read(fd, user, (sizeof user)-1); + close(fd); + if(n <= 0) + strcpy(user, "none"); + else + user[n] = 0; + return user; +} diff --git a/sys/src/libc/port/hangup.c b/sys/src/libc/port/hangup.c new file mode 100755 index 000000000..83d0735cb --- /dev/null +++ b/sys/src/libc/port/hangup.c @@ -0,0 +1,12 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +/* + * force a connection to hangup + */ +int +hangup(int ctl) +{ + return write(ctl, "hangup", sizeof("hangup")-1) != sizeof("hangup")-1; +} diff --git a/sys/src/libc/port/hypot.c b/sys/src/libc/port/hypot.c new file mode 100755 index 000000000..cb8a33341 --- /dev/null +++ b/sys/src/libc/port/hypot.c @@ -0,0 +1,41 @@ +/* + * hypot -- sqrt(p*p+q*q), but overflows only if the result does. + * See Cleve Moler and Donald Morrison, + * ``Replacing Square Roots by Pythagorean Sums,'' + * IBM Journal of Research and Development, + * Vol. 27, Number 6, pp. 577-581, Nov. 1983 + */ + +#include <u.h> +#include <libc.h> + +double +hypot(double p, double q) +{ + double r, s, pfac; + + if(p < 0) + p = -p; + if(q < 0) + q = -q; + if(p < q) { + r = p; + p = q; + q = r; + } + if(p == 0) + return 0; + pfac = p; + r = q = q/p; + p = 1; + for(;;) { + r *= r; + s = r+4; + if(s == 4) + return p*pfac; + r /= s; + p += 2*r*p; + q *= r; + r = q/p; + } +} diff --git a/sys/src/libc/port/lnrand.c b/sys/src/libc/port/lnrand.c new file mode 100755 index 000000000..5b648d08c --- /dev/null +++ b/sys/src/libc/port/lnrand.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> + +#define MASK 0x7fffffffL + +long +lnrand(long n) +{ + long slop, v; + + if(n < 0) + return n; + slop = MASK % n; + do + v = lrand(); + while(v <= slop); + return v % n; +} diff --git a/sys/src/libc/port/lock.c b/sys/src/libc/port/lock.c new file mode 100755 index 000000000..af07b9cc7 --- /dev/null +++ b/sys/src/libc/port/lock.c @@ -0,0 +1,41 @@ +#include <u.h> +#include <libc.h> + +void +lock(Lock *lk) +{ + int i; + + /* once fast */ + if(!_tas(&lk->val)) + return; + /* a thousand times pretty fast */ + for(i=0; i<1000; i++){ + if(!_tas(&lk->val)) + return; + sleep(0); + } + /* now nice and slow */ + for(i=0; i<1000; i++){ + if(!_tas(&lk->val)) + return; + sleep(100); + } + /* take your time */ + while(_tas(&lk->val)) + sleep(1000); +} + +int +canlock(Lock *lk) +{ + if(_tas(&lk->val)) + return 0; + return 1; +} + +void +unlock(Lock *lk) +{ + lk->val = 0; +} diff --git a/sys/src/libc/port/log.c b/sys/src/libc/port/log.c new file mode 100755 index 000000000..dd84b4cfc --- /dev/null +++ b/sys/src/libc/port/log.c @@ -0,0 +1,58 @@ +/* + log returns the natural logarithm of its floating + point argument. + + The coefficients are #2705 from Hart & Cheney. (19.38D) + + It calls frexp. +*/ + +#include <u.h> +#include <libc.h> + +#define log2 0.693147180559945309e0 +#define ln10o1 .4342944819032518276511 +#define sqrto2 0.707106781186547524e0 +#define p0 -.240139179559210510e2 +#define p1 0.309572928215376501e2 +#define p2 -.963769093377840513e1 +#define p3 0.421087371217979714e0 +#define q0 -.120069589779605255e2 +#define q1 0.194809660700889731e2 +#define q2 -.891110902798312337e1 + +double +log(double arg) +{ + double x, z, zsq, temp; + int exp; + + if(arg <= 0) + return NaN(); + x = frexp(arg, &exp); + while(x < 0.5) { + x *= 2; + exp--; + } + if(x < sqrto2) { + x *= 2; + exp--; + } + + z = (x-1) / (x+1); + zsq = z*z; + + temp = ((p3*zsq + p2)*zsq + p1)*zsq + p0; + temp = temp/(((zsq + q2)*zsq + q1)*zsq + q0); + temp = temp*z + exp*log2; + return temp; +} + +double +log10(double arg) +{ + + if(arg <= 0) + return NaN(); + return log(arg) * ln10o1; +} diff --git a/sys/src/libc/port/lrand.c b/sys/src/libc/port/lrand.c new file mode 100755 index 000000000..2ebb39622 --- /dev/null +++ b/sys/src/libc/port/lrand.c @@ -0,0 +1,83 @@ +#include <u.h> +#include <libc.h> + +/* + * algorithm by + * D. P. Mitchell & J. A. Reeds + */ + +#define LEN 607 +#define TAP 273 +#define MASK 0x7fffffffL +#define A 48271 +#define M 2147483647 +#define Q 44488 +#define R 3399 +#define NORM (1.0/(1.0+MASK)) + +static ulong rng_vec[LEN]; +static ulong* rng_tap = rng_vec; +static ulong* rng_feed = 0; +static Lock lk; + +static void +isrand(long seed) +{ + long lo, hi, x; + int i; + + rng_tap = rng_vec; + rng_feed = rng_vec+LEN-TAP; + seed = seed%M; + if(seed < 0) + seed += M; + if(seed == 0) + seed = 89482311; + x = seed; + /* + * Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1) + */ + for(i = -20; i < LEN; i++) { + hi = x / Q; + lo = x % Q; + x = A*lo - R*hi; + if(x < 0) + x += M; + if(i >= 0) + rng_vec[i] = x; + } +} + +void +srand(long seed) +{ + lock(&lk); + isrand(seed); + unlock(&lk); +} + +long +lrand(void) +{ + ulong x; + + lock(&lk); + + rng_tap--; + if(rng_tap < rng_vec) { + if(rng_feed == 0) { + isrand(1); + rng_tap--; + } + rng_tap += LEN; + } + rng_feed--; + if(rng_feed < rng_vec) + rng_feed += LEN; + x = (*rng_feed + *rng_tap) & MASK; + *rng_feed = x; + + unlock(&lk); + + return x; +} diff --git a/sys/src/libc/port/malloc.acid b/sys/src/libc/port/malloc.acid new file mode 100755 index 000000000..514bb8d98 --- /dev/null +++ b/sys/src/libc/port/malloc.acid @@ -0,0 +1,366 @@ +sizeof_1_ = 8; +aggr _1_ +{ + 'D' 0 lo; + 'D' 4 hi; +}; + +defn +_1_(addr) { + complex _1_ addr; + print(" lo ", addr.lo, "\n"); + print(" hi ", addr.hi, "\n"); +}; + +sizeofFPdbleword = 8; +aggr FPdbleword +{ + 'F' 0 x; + { + 'D' 0 lo; + 'D' 4 hi; + }; +}; + +defn +FPdbleword(addr) { + complex FPdbleword addr; + print(" x ", addr.x, "\n"); + print("_1_ {\n"); + _1_(addr+0); + print("}\n"); +}; + +UTFmax = 3; +Runesync = 128; +Runeself = 128; +Runeerror = 128; +sizeofFconv = 24; +aggr Fconv +{ + 'X' 0 out; + 'X' 4 eout; + 'D' 8 f1; + 'D' 12 f2; + 'D' 16 f3; + 'D' 20 chr; +}; + +defn +Fconv(addr) { + complex Fconv addr; + print(" out ", addr.out\X, "\n"); + print(" eout ", addr.eout\X, "\n"); + print(" f1 ", addr.f1, "\n"); + print(" f2 ", addr.f2, "\n"); + print(" f3 ", addr.f3, "\n"); + print(" chr ", addr.chr, "\n"); +}; + +sizeofTm = 40; +aggr Tm +{ + 'D' 0 sec; + 'D' 4 min; + 'D' 8 hour; + 'D' 12 mday; + 'D' 16 mon; + 'D' 20 year; + 'D' 24 wday; + 'D' 28 yday; + 'a' 32 zone; + 'D' 36 tzoff; +}; + +defn +Tm(addr) { + complex Tm addr; + print(" sec ", addr.sec, "\n"); + print(" min ", addr.min, "\n"); + print(" hour ", addr.hour, "\n"); + print(" mday ", addr.mday, "\n"); + print(" mon ", addr.mon, "\n"); + print(" year ", addr.year, "\n"); + print(" wday ", addr.wday, "\n"); + print(" yday ", addr.yday, "\n"); + print(" zone ", addr.zone, "\n"); + print(" tzoff ", addr.tzoff, "\n"); +}; + +PNPROC = 1; +PNGROUP = 2; +sizeofLock = 4; +aggr Lock +{ + 'D' 0 val; +}; + +defn +Lock(addr) { + complex Lock addr; + print(" val ", addr.val, "\n"); +}; + +sizeofQLp = 12; +aggr QLp +{ + 'D' 0 inuse; + 'A' QLp 4 next; + 'C' 8 state; +}; + +defn +QLp(addr) { + complex QLp addr; + print(" inuse ", addr.inuse, "\n"); + print(" next ", addr.next\X, "\n"); + print(" state ", addr.state, "\n"); +}; + +sizeofQLock = 16; +aggr QLock +{ + Lock 0 lock; + 'D' 4 locked; + 'A' QLp 8 $head; + 'A' QLp 12 $tail; +}; + +defn +QLock(addr) { + complex QLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" locked ", addr.locked, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRWLock = 20; +aggr RWLock +{ + Lock 0 lock; + 'D' 4 readers; + 'D' 8 writer; + 'A' QLp 12 $head; + 'A' QLp 16 $tail; +}; + +defn +RWLock(addr) { + complex RWLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" readers ", addr.readers, "\n"); + print(" writer ", addr.writer, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +RFNAMEG = 1; +RFENVG = 2; +RFFDG = 4; +RFNOTEG = 8; +RFPROC = 16; +RFMEM = 32; +RFNOWAIT = 64; +RFCNAMEG = 1024; +RFCENVG = 2048; +RFCFDG = 4096; +RFREND = 8192; +RFNOMNT = 16384; +sizeofQid = 16; +aggr Qid +{ + 'W' 0 path; + 'U' 8 vers; + 'b' 12 type; +}; + +defn +Qid(addr) { + complex Qid addr; + print(" path ", addr.path, "\n"); + print(" vers ", addr.vers, "\n"); + print(" type ", addr.type, "\n"); +}; + +sizeofDir = 60; +aggr Dir +{ + 'u' 0 type; + 'U' 4 dev; + Qid 8 qid; + 'U' 24 mode; + 'U' 28 atime; + 'U' 32 mtime; + 'V' 36 length; + 'X' 44 name; + 'X' 48 uid; + 'X' 52 gid; + 'X' 56 muid; +}; + +defn +Dir(addr) { + complex Dir addr; + print(" type ", addr.type, "\n"); + print(" dev ", addr.dev, "\n"); + print("Qid qid {\n"); + Qid(addr.qid); + print("}\n"); + print(" mode ", addr.mode, "\n"); + print(" atime ", addr.atime, "\n"); + print(" mtime ", addr.mtime, "\n"); + print(" length ", addr.length, "\n"); + print(" name ", addr.name\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" gid ", addr.gid\X, "\n"); + print(" muid ", addr.muid\X, "\n"); +}; + +sizeofWaitmsg = 20; +aggr Waitmsg +{ + 'D' 0 pid; + 'a' 4 time; + 'X' 16 msg; +}; + +defn +Waitmsg(addr) { + complex Waitmsg addr; + print(" pid ", addr.pid, "\n"); + print(" time ", addr.time, "\n"); + print(" msg ", addr.msg\X, "\n"); +}; + +sizeofIOchunk = 8; +aggr IOchunk +{ + 'X' 0 addr; + 'U' 4 len; +}; + +defn +IOchunk(addr) { + complex IOchunk addr; + print(" addr ", addr.addr\X, "\n"); + print(" len ", addr.len, "\n"); +}; + +sizeofPool = 88; +aggr Pool +{ + 'X' 0 name; + 'U' 4 maxsize; + 'U' 8 cursize; + 'U' 12 curfree; + 'U' 16 curalloc; + 'U' 20 minarena; + 'U' 24 quantum; + 'U' 28 minblock; + 'X' 32 freeroot; + 'X' 36 arenalist; + 'X' 40 alloc; + 'X' 44 merge; + 'X' 48 move; + 'D' 52 flags; + 'D' 56 nfree; + 'D' 60 lastcompact; + 'X' 64 lock; + 'X' 68 unlock; + 'X' 72 print; + 'X' 76 panic; + 'X' 80 logstack; + 'X' 84 private; +}; + +defn +Pool(addr) { + complex Pool addr; + print(" name ", addr.name\X, "\n"); + print(" maxsize ", addr.maxsize, "\n"); + print(" cursize ", addr.cursize, "\n"); + print(" curfree ", addr.curfree, "\n"); + print(" curalloc ", addr.curalloc, "\n"); + print(" minarena ", addr.minarena, "\n"); + print(" quantum ", addr.quantum, "\n"); + print(" minblock ", addr.minblock, "\n"); + print(" freeroot ", addr.freeroot\X, "\n"); + print(" arenalist ", addr.arenalist\X, "\n"); + print(" alloc ", addr.alloc\X, "\n"); + print(" merge ", addr.merge\X, "\n"); + print(" move ", addr.move\X, "\n"); + print(" flags ", addr.flags, "\n"); + print(" nfree ", addr.nfree, "\n"); + print(" lastcompact ", addr.lastcompact, "\n"); + print(" lock ", addr.lock\X, "\n"); + print(" unlock ", addr.unlock\X, "\n"); + print(" print ", addr.print\X, "\n"); + print(" panic ", addr.panic\X, "\n"); + print(" logstack ", addr.logstack\X, "\n"); + print(" private ", addr.private\X, "\n"); +}; + +sizeofTraverse = 20; +aggr Traverse +{ + 'X' 0 visit; + 'D' 4 maxvisit; + 'X' 8 a; + 'X' 12 b; + 'X' 16 prev; +}; + +defn +Traverse(addr) { + complex Traverse addr; + print(" visit ", addr.visit\X, "\n"); + print(" maxvisit ", addr.maxvisit, "\n"); + print(" a ", addr.a\X, "\n"); + print(" b ", addr.b\X, "\n"); + print(" prev ", addr.prev\X, "\n"); +}; + +complex Pool mainmem; +complex Pool imagmem; +POOL_ANTAGONISM = 1; +POOL_PARANOIA = 2; +POOL_VERBOSITY = 4; +POOL_DEBUGGING = 8; +POOL_LOGGING = 16; +POOL_TOLERANCE = 32; +sizeofPrivate = 8; +aggr Private +{ + Lock 0 lk; + 'D' 4 printfd; +}; + +defn +Private(addr) { + complex Private addr; + print("Lock lk {\n"); + Lock(addr.lk); + print("}\n"); + print(" printfd ", addr.printfd, "\n"); +}; + +complex Private sbrkmempriv; +complex Pool sbrkmem; +complex Pool mainmem; +complex Pool imagmem; +complex Pool plock:p; +complex Private plock:pv; +complex Pool punlock:p; +complex Private punlock:pv; +complex Pool pprint:p; +complex Private pprint:pv; +complex Pool ppanic:p; +complex Private ppanic:pv; +Npadlong = 2; +MallocOffset = 0; +ReallocOffset = 1; diff --git a/sys/src/libc/port/malloc.c b/sys/src/libc/port/malloc.c new file mode 100755 index 000000000..741316926 --- /dev/null +++ b/sys/src/libc/port/malloc.c @@ -0,0 +1,338 @@ +#include <u.h> +#include <libc.h> +#include <pool.h> +#include <tos.h> + +static void* sbrkalloc(ulong); +static int sbrkmerge(void*, void*); +static void plock(Pool*); +static void punlock(Pool*); +static void pprint(Pool*, char*, ...); +static void ppanic(Pool*, char*, ...); + +typedef struct Private Private; +struct Private { + Lock lk; + int pid; + int printfd; /* gets debugging output if set */ +}; + +Private sbrkmempriv; + +static Pool sbrkmem = { + .name= "sbrkmem", + .maxsize= (3840UL-1)*1024*1024, /* up to ~0xf0000000 */ + .minarena= 4*1024, + .quantum= 32, + .alloc= sbrkalloc, + .merge= sbrkmerge, + .flags= 0, + + .lock= plock, + .unlock= punlock, + .print= pprint, + .panic= ppanic, + .private= &sbrkmempriv, +}; +Pool *mainmem = &sbrkmem; +Pool *imagmem = &sbrkmem; + +/* + * we do minimal bookkeeping so we can tell pool + * whether two blocks are adjacent and thus mergeable. + */ +static void* +sbrkalloc(ulong n) +{ + ulong *x; + + n += 2*sizeof(ulong); /* two longs for us */ + x = sbrk(n); + if(x == (void*)-1) + return nil; + x[0] = (n+7)&~7; /* sbrk rounds size up to mult. of 8 */ + x[1] = 0xDeadBeef; + return x+2; +} + +static int +sbrkmerge(void *x, void *y) +{ + ulong *lx, *ly; + + lx = x; + if(lx[-1] != 0xDeadBeef) + abort(); + + if((uchar*)lx+lx[-2] == (uchar*)y) { + ly = y; + lx[-2] += ly[-2]; + return 1; + } + return 0; +} + +static void +plock(Pool *p) +{ + Private *pv; + pv = p->private; + lock(&pv->lk); + if(pv->pid != 0) + abort(); + pv->pid = _tos->pid; +} + +static void +punlock(Pool *p) +{ + Private *pv; + pv = p->private; + if(pv->pid != _tos->pid) + abort(); + pv->pid = 0; + unlock(&pv->lk); +} + +static int +checkenv(void) +{ + int n, fd; + char buf[20]; + fd = open("/env/MALLOCFD", OREAD); + if(fd < 0) + return -1; + if((n = read(fd, buf, sizeof buf)) < 0) { + close(fd); + return -1; + } + if(n >= sizeof buf) + n = sizeof(buf)-1; + buf[n] = 0; + n = atoi(buf); + if(n == 0) + n = -1; + return n; +} + +static void +pprint(Pool *p, char *fmt, ...) +{ + va_list v; + Private *pv; + + pv = p->private; + if(pv->printfd == 0) + pv->printfd = checkenv(); + + if(pv->printfd <= 0) + pv->printfd = 2; + + va_start(v, fmt); + vfprint(pv->printfd, fmt, v); + va_end(v); +} + +static char panicbuf[256]; +static void +ppanic(Pool *p, char *fmt, ...) +{ + va_list v; + int n; + char *msg; + Private *pv; + + pv = p->private; + assert(canlock(&pv->lk)==0); + + if(pv->printfd == 0) + pv->printfd = checkenv(); + if(pv->printfd <= 0) + pv->printfd = 2; + + msg = panicbuf; + va_start(v, fmt); + n = vseprint(msg, msg+sizeof panicbuf, fmt, v) - msg; + write(2, "panic: ", 7); + write(2, msg, n); + write(2, "\n", 1); + if(pv->printfd != 2){ + write(pv->printfd, "panic: ", 7); + write(pv->printfd, msg, n); + write(pv->printfd, "\n", 1); + } + va_end(v); +// unlock(&pv->lk); + abort(); +} + +/* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */ +/* - except the code for malloc(), which alternately doesn't clear or does. - */ + +/* + * Npadlong is the number of 32-bit longs to leave at the beginning of + * each allocated buffer for our own bookkeeping. We return to the callers + * a pointer that points immediately after our bookkeeping area. Incoming pointers + * must be decremented by that much, and outgoing pointers incremented. + * The malloc tag is stored at MallocOffset from the beginning of the block, + * and the realloc tag at ReallocOffset. The offsets are from the true beginning + * of the block, not the beginning the caller sees. + * + * The extra if(Npadlong != 0) in various places is a hint for the compiler to + * compile out function calls that would otherwise be no-ops. + */ + +/* non tracing + * +enum { + Npadlong = 0, + MallocOffset = 0, + ReallocOffset = 0, +}; + * + */ + +/* tracing */ +enum { + Npadlong = 2, + MallocOffset = 0, + ReallocOffset = 1 +}; + +void* +malloc(ulong size) +{ + void *v; + + v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); + if(Npadlong && v != nil) { + v = (ulong*)v+Npadlong; + setmalloctag(v, getcallerpc(&size)); + setrealloctag(v, 0); + } + return v; +} + +void* +mallocz(ulong size, int clr) +{ + void *v; + + v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); + if(Npadlong && v != nil){ + v = (ulong*)v+Npadlong; + setmalloctag(v, getcallerpc(&size)); + setrealloctag(v, 0); + } + if(clr && v != nil) + memset(v, 0, size); + return v; +} + +void* +mallocalign(ulong size, ulong align, long offset, ulong span) +{ + void *v; + + v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span); + if(Npadlong && v != nil){ + v = (ulong*)v+Npadlong; + setmalloctag(v, getcallerpc(&size)); + setrealloctag(v, 0); + } + return v; +} + +void +free(void *v) +{ + if(v != nil) + poolfree(mainmem, (ulong*)v-Npadlong); +} + +void* +realloc(void *v, ulong size) +{ + void *nv; + + if(size == 0){ + free(v); + return nil; + } + + if(v) + v = (ulong*)v-Npadlong; + size += Npadlong*sizeof(ulong); + + if(nv = poolrealloc(mainmem, v, size)){ + nv = (ulong*)nv+Npadlong; + setrealloctag(nv, getcallerpc(&v)); + if(v == nil) + setmalloctag(nv, getcallerpc(&v)); + } + return nv; +} + +ulong +msize(void *v) +{ + return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong); +} + +void* +calloc(ulong n, ulong szelem) +{ + void *v; + if(v = mallocz(n*szelem, 1)) + setmalloctag(v, getcallerpc(&n)); + return v; +} + +void +setmalloctag(void *v, ulong pc) +{ + ulong *u; + USED(v, pc); + if(Npadlong <= MallocOffset || v == nil) + return; + u = v; + u[-Npadlong+MallocOffset] = pc; +} + +void +setrealloctag(void *v, ulong pc) +{ + ulong *u; + USED(v, pc); + if(Npadlong <= ReallocOffset || v == nil) + return; + u = v; + u[-Npadlong+ReallocOffset] = pc; +} + +ulong +getmalloctag(void *v) +{ + USED(v); + if(Npadlong <= MallocOffset) + return ~0; + return ((ulong*)v)[-Npadlong+MallocOffset]; +} + +ulong +getrealloctag(void *v) +{ + USED(v); + if(Npadlong <= ReallocOffset) + return ((ulong*)v)[-Npadlong+ReallocOffset]; + return ~0; +} + +void* +malloctopoolblock(void *v) +{ + if(v == nil) + return nil; + + return &((ulong*)v)[-Npadlong]; +} diff --git a/sys/src/libc/port/memccpy.c b/sys/src/libc/port/memccpy.c new file mode 100755 index 000000000..9268ba72e --- /dev/null +++ b/sys/src/libc/port/memccpy.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> + +void* +memccpy(void *a1, void *a2, int c, ulong n) +{ + uchar *s1, *s2; + + s1 = a1; + s2 = a2; + c &= 0xFF; + while(n > 0) { + if((*s1++ = *s2++) == c) + return s1; + n--; + } + return 0; +} diff --git a/sys/src/libc/port/memchr.c b/sys/src/libc/port/memchr.c new file mode 100755 index 000000000..fb4b1d148 --- /dev/null +++ b/sys/src/libc/port/memchr.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +void* +memchr(void *ap, int c, ulong n) +{ + uchar *sp; + + sp = ap; + c &= 0xFF; + while(n > 0) { + if(*sp++ == c) + return sp-1; + n--; + } + return 0; +} diff --git a/sys/src/libc/port/memcmp.c b/sys/src/libc/port/memcmp.c new file mode 100755 index 000000000..211752b03 --- /dev/null +++ b/sys/src/libc/port/memcmp.c @@ -0,0 +1,23 @@ +#include <u.h> +#include <libc.h> + +int +memcmp(void *a1, void *a2, ulong n) +{ + uchar *s1, *s2; + uint c1, c2; + + s1 = a1; + s2 = a2; + while(n > 0) { + c1 = *s1++; + c2 = *s2++; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + n--; + } + return 0; +} diff --git a/sys/src/libc/port/memmove.c b/sys/src/libc/port/memmove.c new file mode 100755 index 000000000..16ef43277 --- /dev/null +++ b/sys/src/libc/port/memmove.c @@ -0,0 +1,35 @@ +#include <u.h> +#include <libc.h> + +void* +memmove(void *a1, void *a2, ulong n) +{ + char *s1, *s2; + + if((long)n < 0) + abort(); + s1 = a1; + s2 = a2; + if((s2 < s1) && (s2+n > s1)) + goto back; + while(n > 0) { + *s1++ = *s2++; + n--; + } + return a1; + +back: + s1 += n; + s2 += n; + while(n > 0) { + *--s1 = *--s2; + n--; + } + return a1; +} + +void* +memcpy(void *a1, void *a2, ulong n) +{ + return memmove(a1, a2, n); +} diff --git a/sys/src/libc/port/memset.c b/sys/src/libc/port/memset.c new file mode 100755 index 000000000..431d6bb30 --- /dev/null +++ b/sys/src/libc/port/memset.c @@ -0,0 +1,15 @@ +#include <u.h> +#include <libc.h> + +void* +memset(void *ap, int c, ulong n) +{ + char *p; + + p = ap; + while(n > 0) { + *p++ = c; + n--; + } + return ap; +} diff --git a/sys/src/libc/port/mkfile b/sys/src/libc/port/mkfile new file mode 100755 index 000000000..dc2d93694 --- /dev/null +++ b/sys/src/libc/port/mkfile @@ -0,0 +1,127 @@ +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +CFILES=\ + _assert.c\ + abs.c\ + asin.c\ + atan.c\ + atan2.c\ + atexit.c\ + atnotify.c\ + atof.c\ + atol.c\ + atoll.c\ + cistrcmp.c\ + cistrncmp.c\ + cistrstr.c\ + charstod.c\ + cleanname.c\ + crypt.c\ + ctype.c\ + encodefmt.c\ + execl.c\ + exp.c\ + fabs.c\ + floor.c\ + fmod.c\ + frand.c\ + frexp.c\ + getcallerpc.c\ + getfields.c\ + getuser.c\ + hangup.c\ + hypot.c\ + lnrand.c\ + lock.c\ + log.c\ + lrand.c\ + malloc.c\ + memccpy.c\ + memchr.c\ + memcmp.c\ + memmove.c\ + memset.c\ + mktemp.c\ + muldiv.c\ + nan.c\ + needsrcquote.c\ + netcrypt.c\ + netmkaddr.c\ + nrand.c\ + ntruerand.c\ + perror.c\ + pool.c\ + pow.c\ + pow10.c\ + profile.c\ + qsort.c\ + quote.c\ + rand.c\ + readn.c\ + rune.c\ + runestrcat.c\ + runestrchr.c\ + runestrcmp.c\ + runestrcpy.c\ + runestrecpy.c\ + runestrdup.c\ + runestrncat.c\ + runestrncmp.c\ + runestrncpy.c\ + runestrrchr.c\ + runestrlen.c\ + runestrstr.c\ + runetype.c\ + sin.c\ + sinh.c\ + sqrt.c\ + strcat.c\ + strchr.c\ + strcmp.c\ + strcpy.c\ + strecpy.c\ + strcspn.c\ + strdup.c\ + strlen.c\ + strncat.c\ + strncmp.c\ + strncpy.c\ + strpbrk.c\ + strrchr.c\ + strspn.c\ + strstr.c\ + strtod.c\ + strtok.c\ + strtol.c\ + strtoll.c\ + strtoul.c\ + strtoull.c\ + tan.c\ + tanh.c\ + tokenize.c\ + toupper.c\ + utfecpy.c\ + utflen.c\ + utfnlen.c\ + utfrune.c\ + utfrrune.c\ + utfutf.c\ + u16.c\ + u32.c\ + u64.c\ + +ALLOFILES=${CFILES:%.c=%.$O} + +# cull things in the per-machine directories from this list +OFILES= `{rc ./reduce $O $objtype $ALLOFILES} + +HFILES=/sys/include/libc.h + +UPDATE=mkfile\ + $HFILES\ + $CFILES\ + +</sys/src/cmd/mksyslib + +profile.$O: /sys/include/tos.h diff --git a/sys/src/libc/port/mktemp.c b/sys/src/libc/port/mktemp.c new file mode 100755 index 000000000..384d7fcf7 --- /dev/null +++ b/sys/src/libc/port/mktemp.c @@ -0,0 +1,31 @@ +#include <u.h> +#include <libc.h> + +char* +mktemp(char *as) +{ + char *s; + unsigned pid; + int i; + char err[ERRMAX]; + + pid = getpid(); + s = as; + while(*s++) + ; + s--; + while(*--s == 'X') { + *s = pid % 10 + '0'; + pid = pid/10; + } + s++; + i = 'a'; + while(access(as, 0) != -1) { + if (i == 'z') + return "/"; + *s = i++; + } + err[0] = '\0'; + errstr(err, sizeof err); /* clear the error */ + return as; +} diff --git a/sys/src/libc/port/muldiv.c b/sys/src/libc/port/muldiv.c new file mode 100755 index 000000000..c304daf6e --- /dev/null +++ b/sys/src/libc/port/muldiv.c @@ -0,0 +1,38 @@ +#include <u.h> +#include <libc.h> + +ulong +umuldiv(ulong a, ulong b, ulong c) +{ + double d; + + d = ((double)a * (double)b) / (double)c; + if(d >= 4294967296.) + abort(); + return d; +} + +long +muldiv(long a, long b, long c) +{ + int s; + long v; + + s = 0; + if(a < 0) { + s = !s; + a = -a; + } + if(b < 0) { + s = !s; + b = -b; + } + if(c < 0) { + s = !s; + c = -c; + } + v = umuldiv(a, b, c); + if(s) + v = -v; + return v; +} diff --git a/sys/src/libc/port/nan.c b/sys/src/libc/port/nan.c new file mode 100755 index 000000000..f5a4cec34 --- /dev/null +++ b/sys/src/libc/port/nan.c @@ -0,0 +1,54 @@ +#include <u.h> +#include <libc.h> + +#define NANEXP (2047<<20) +#define NANMASK (2047<<20) +#define NANSIGN (1<<31) + +double +NaN(void) +{ + FPdbleword a; + + a.hi = NANEXP; + a.lo = 1; + return a.x; +} + +int +isNaN(double d) +{ + FPdbleword a; + + a.x = d; + if((a.hi & NANMASK) != NANEXP) + return 0; + return !isInf(d, 0); +} + +double +Inf(int sign) +{ + FPdbleword a; + + a.hi = NANEXP; + a.lo = 0; + if(sign < 0) + a.hi |= NANSIGN; + return a.x; +} + +int +isInf(double d, int sign) +{ + FPdbleword a; + + a.x = d; + if(a.lo != 0) + return 0; + if(a.hi == NANEXP) + return sign >= 0; + if(a.hi == (NANEXP|NANSIGN)) + return sign <= 0; + return 0; +} diff --git a/sys/src/libc/port/needsrcquote.c b/sys/src/libc/port/needsrcquote.c new file mode 100755 index 000000000..f211ea1f9 --- /dev/null +++ b/sys/src/libc/port/needsrcquote.c @@ -0,0 +1,12 @@ +#include <u.h> +#include <libc.h> + +int +needsrcquote(int c) +{ + if(c <= ' ') + return 1; + if(utfrune("`^#*[]=|\\?${}()'<>&;", c)) + return 1; + return 0; +} diff --git a/sys/src/libc/port/netcrypt.c b/sys/src/libc/port/netcrypt.c new file mode 100755 index 000000000..08fa6761c --- /dev/null +++ b/sys/src/libc/port/netcrypt.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> + +int +netcrypt(void *key, void *chal) +{ + uchar buf[8], *p; + + strncpy((char*)buf, chal, 7); + buf[7] = '\0'; + for(p = buf; *p && *p != '\n'; p++) + ; + *p = '\0'; + encrypt(key, buf, 8); + sprint(chal, "%.2ux%.2ux%.2ux%.2ux", buf[0], buf[1], buf[2], buf[3]); + return 1; +} diff --git a/sys/src/libc/port/netmkaddr.c b/sys/src/libc/port/netmkaddr.c new file mode 100755 index 000000000..fd53f4684 --- /dev/null +++ b/sys/src/libc/port/netmkaddr.c @@ -0,0 +1,52 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +/* + * make an address, add the defaults + */ +char * +netmkaddr(char *linear, char *defnet, char *defsrv) +{ + static char addr[256]; + char *cp; + + /* + * dump network name + */ + cp = strchr(linear, '!'); + if(cp == 0){ + if(defnet==0){ + if(defsrv) + snprint(addr, sizeof(addr), "net!%s!%s", + linear, defsrv); + else + snprint(addr, sizeof(addr), "net!%s", linear); + } + else { + if(defsrv) + snprint(addr, sizeof(addr), "%s!%s!%s", defnet, + linear, defsrv); + else + snprint(addr, sizeof(addr), "%s!%s", defnet, + linear); + } + return addr; + } + + /* + * if there is already a service, use it + */ + cp = strchr(cp+1, '!'); + if(cp) + return linear; + + /* + * add default service + */ + if(defsrv == 0) + return linear; + snprint(addr, sizeof(addr), "%s!%s", linear, defsrv); + + return addr; +} diff --git a/sys/src/libc/port/nrand.c b/sys/src/libc/port/nrand.c new file mode 100755 index 000000000..31dbe27ff --- /dev/null +++ b/sys/src/libc/port/nrand.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> + +#define MASK 0x7fffffffL + +int +nrand(int n) +{ + long slop, v; + + if(n < 0) + return n; + if(n == 1) + return 0; + /* and if n == 0, you deserve what you get */ + slop = MASK % n; + do + v = lrand(); + while(v <= slop); + return v % n; +} diff --git a/sys/src/libc/port/ntruerand.c b/sys/src/libc/port/ntruerand.c new file mode 100755 index 000000000..248eda647 --- /dev/null +++ b/sys/src/libc/port/ntruerand.c @@ -0,0 +1,23 @@ +#include <u.h> +#include <libc.h> + +ulong +ntruerand(ulong n) +{ + ulong m, r; + + /* + * set m to the one less than the maximum multiple of n <= 2^32, + * so we want a random number <= m. + */ + if(n > (1UL<<31)) + m = n-1; + else + /* 2^32 - 2^32%n - 1 = (2^32 - 1) - (2*(2^31%n))%n */ + m = 0xFFFFFFFFUL - (2*((1UL<<31)%n))%n; + + while((r = truerand()) > m) + ; + + return r%n; +} diff --git a/sys/src/libc/port/perror.c b/sys/src/libc/port/perror.c new file mode 100755 index 000000000..c4c03c7bc --- /dev/null +++ b/sys/src/libc/port/perror.c @@ -0,0 +1,15 @@ +#include <u.h> +#include <libc.h> + +void +perror(char *s) +{ + char buf[ERRMAX]; + + buf[0] = '\0'; + errstr(buf, sizeof buf); + if(s && *s) + fprint(2, "%s: %s\n", s, buf); + else + fprint(2, "%s\n", buf); +} diff --git a/sys/src/libc/port/pool.acid b/sys/src/libc/port/pool.acid new file mode 100755 index 000000000..da58aa441 --- /dev/null +++ b/sys/src/libc/port/pool.acid @@ -0,0 +1,628 @@ +sizeof_1_ = 8; +aggr _1_ +{ + 'U' 0 lo; + 'U' 4 hi; +}; + +defn +_1_(addr) { + complex _1_ addr; + print(" lo ", addr.lo, "\n"); + print(" hi ", addr.hi, "\n"); +}; + +sizeofFPdbleword = 8; +aggr FPdbleword +{ + 'F' 0 x; + { + 'U' 0 lo; + 'U' 4 hi; + }; +}; + +defn +FPdbleword(addr) { + complex FPdbleword addr; + print(" x ", addr.x, "\n"); + print("_1_ {\n"); + _1_(addr+0); + print("}\n"); +}; + +UTFmax = 3; +Runesync = 128; +Runeself = 128; +Runeerror = 65533; +sizeofFmt = 48; +aggr Fmt +{ + 'b' 0 runes; + 'X' 4 start; + 'X' 8 to; + 'X' 12 stop; + 'X' 16 flush; + 'X' 20 farg; + 'D' 24 nfmt; + 'X' 28 args; + 'D' 32 r; + 'D' 36 width; + 'D' 40 prec; + 'U' 44 flags; +}; + +defn +Fmt(addr) { + complex Fmt addr; + print(" runes ", addr.runes, "\n"); + print(" start ", addr.start\X, "\n"); + print(" to ", addr.to\X, "\n"); + print(" stop ", addr.stop\X, "\n"); + print(" flush ", addr.flush\X, "\n"); + print(" farg ", addr.farg\X, "\n"); + print(" nfmt ", addr.nfmt, "\n"); + print(" args ", addr.args\X, "\n"); + print(" r ", addr.r, "\n"); + print(" width ", addr.width, "\n"); + print(" prec ", addr.prec, "\n"); + print(" flags ", addr.flags, "\n"); +}; + +FmtWidth = 1; +FmtLeft = 2; +FmtPrec = 4; +FmtSharp = 8; +FmtSpace = 16; +FmtSign = 32; +FmtZero = 64; +FmtUnsigned = 128; +FmtShort = 256; +FmtLong = 512; +FmtVLong = 1024; +FmtComma = 2048; +FmtByte = 4096; +FmtFlag = 8192; +sizeofTm = 40; +aggr Tm +{ + 'D' 0 sec; + 'D' 4 min; + 'D' 8 hour; + 'D' 12 mday; + 'D' 16 mon; + 'D' 20 year; + 'D' 24 wday; + 'D' 28 yday; + 'a' 32 zone; + 'D' 36 tzoff; +}; + +defn +Tm(addr) { + complex Tm addr; + print(" sec ", addr.sec, "\n"); + print(" min ", addr.min, "\n"); + print(" hour ", addr.hour, "\n"); + print(" mday ", addr.mday, "\n"); + print(" mon ", addr.mon, "\n"); + print(" year ", addr.year, "\n"); + print(" wday ", addr.wday, "\n"); + print(" yday ", addr.yday, "\n"); + print(" zone ", addr.zone, "\n"); + print(" tzoff ", addr.tzoff, "\n"); +}; + +PNPROC = 1; +PNGROUP = 2; +Profoff = 0; +Profuser = 1; +Profkernel = 2; +Proftime = 3; +Profsample = 4; +sizeofLock = 4; +aggr Lock +{ + 'D' 0 val; +}; + +defn +Lock(addr) { + complex Lock addr; + print(" val ", addr.val, "\n"); +}; + +sizeofQLp = 12; +aggr QLp +{ + 'D' 0 inuse; + 'A' QLp 4 next; + 'C' 8 state; +}; + +defn +QLp(addr) { + complex QLp addr; + print(" inuse ", addr.inuse, "\n"); + print(" next ", addr.next\X, "\n"); + print(" state ", addr.state, "\n"); +}; + +sizeofQLock = 16; +aggr QLock +{ + Lock 0 lock; + 'D' 4 locked; + 'A' QLp 8 $head; + 'A' QLp 12 $tail; +}; + +defn +QLock(addr) { + complex QLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" locked ", addr.locked, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRWLock = 20; +aggr RWLock +{ + Lock 0 lock; + 'D' 4 readers; + 'D' 8 writer; + 'A' QLp 12 $head; + 'A' QLp 16 $tail; +}; + +defn +RWLock(addr) { + complex RWLock addr; + print("Lock lock {\n"); + Lock(addr.lock); + print("}\n"); + print(" readers ", addr.readers, "\n"); + print(" writer ", addr.writer, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofRendez = 12; +aggr Rendez +{ + 'A' QLock 0 l; + 'A' QLp 4 $head; + 'A' QLp 8 $tail; +}; + +defn +Rendez(addr) { + complex Rendez addr; + print(" l ", addr.l\X, "\n"); + print(" $head ", addr.$head\X, "\n"); + print(" $tail ", addr.$tail\X, "\n"); +}; + +sizeofNetConnInfo = 36; +aggr NetConnInfo +{ + 'X' 0 dir; + 'X' 4 root; + 'X' 8 spec; + 'X' 12 lsys; + 'X' 16 lserv; + 'X' 20 rsys; + 'X' 24 rserv; + 'X' 28 laddr; + 'X' 32 raddr; +}; + +defn +NetConnInfo(addr) { + complex NetConnInfo addr; + print(" dir ", addr.dir\X, "\n"); + print(" root ", addr.root\X, "\n"); + print(" spec ", addr.spec\X, "\n"); + print(" lsys ", addr.lsys\X, "\n"); + print(" lserv ", addr.lserv\X, "\n"); + print(" rsys ", addr.rsys\X, "\n"); + print(" rserv ", addr.rserv\X, "\n"); + print(" laddr ", addr.laddr\X, "\n"); + print(" raddr ", addr.raddr\X, "\n"); +}; + +RFNAMEG = 1; +RFENVG = 2; +RFFDG = 4; +RFNOTEG = 8; +RFPROC = 16; +RFMEM = 32; +RFNOWAIT = 64; +RFCNAMEG = 1024; +RFCENVG = 2048; +RFCFDG = 4096; +RFREND = 8192; +RFNOMNT = 16384; +sizeofQid = 16; +aggr Qid +{ + 'W' 0 path; + 'U' 8 vers; + 'b' 12 type; +}; + +defn +Qid(addr) { + complex Qid addr; + print(" path ", addr.path, "\n"); + print(" vers ", addr.vers, "\n"); + print(" type ", addr.type, "\n"); +}; + +sizeofDir = 60; +aggr Dir +{ + 'u' 0 type; + 'U' 4 dev; + Qid 8 qid; + 'U' 24 mode; + 'U' 28 atime; + 'U' 32 mtime; + 'V' 36 length; + 'X' 44 name; + 'X' 48 uid; + 'X' 52 gid; + 'X' 56 muid; +}; + +defn +Dir(addr) { + complex Dir addr; + print(" type ", addr.type, "\n"); + print(" dev ", addr.dev, "\n"); + print("Qid qid {\n"); + Qid(addr.qid); + print("}\n"); + print(" mode ", addr.mode, "\n"); + print(" atime ", addr.atime, "\n"); + print(" mtime ", addr.mtime, "\n"); + print(" length ", addr.length, "\n"); + print(" name ", addr.name\X, "\n"); + print(" uid ", addr.uid\X, "\n"); + print(" gid ", addr.gid\X, "\n"); + print(" muid ", addr.muid\X, "\n"); +}; + +sizeofWaitmsg = 20; +aggr Waitmsg +{ + 'D' 0 pid; + 'a' 4 time; + 'X' 16 msg; +}; + +defn +Waitmsg(addr) { + complex Waitmsg addr; + print(" pid ", addr.pid, "\n"); + print(" time ", addr.time, "\n"); + print(" msg ", addr.msg\X, "\n"); +}; + +sizeofIOchunk = 8; +aggr IOchunk +{ + 'X' 0 addr; + 'U' 4 len; +}; + +defn +IOchunk(addr) { + complex IOchunk addr; + print(" addr ", addr.addr\X, "\n"); + print(" len ", addr.len, "\n"); +}; + +sizeofPool = 88; +aggr Pool +{ + 'X' 0 name; + 'U' 4 maxsize; + 'U' 8 cursize; + 'U' 12 curfree; + 'U' 16 curalloc; + 'U' 20 minarena; + 'U' 24 quantum; + 'U' 28 minblock; + 'X' 32 freeroot; + 'X' 36 arenalist; + 'X' 40 alloc; + 'X' 44 merge; + 'X' 48 move; + 'D' 52 flags; + 'D' 56 nfree; + 'D' 60 lastcompact; + 'X' 64 lock; + 'X' 68 unlock; + 'X' 72 print; + 'X' 76 panic; + 'X' 80 logstack; + 'X' 84 private; +}; + +defn +Pool(addr) { + complex Pool addr; + print(" name ", addr.name\X, "\n"); + print(" maxsize ", addr.maxsize, "\n"); + print(" cursize ", addr.cursize, "\n"); + print(" curfree ", addr.curfree, "\n"); + print(" curalloc ", addr.curalloc, "\n"); + print(" minarena ", addr.minarena, "\n"); + print(" quantum ", addr.quantum, "\n"); + print(" minblock ", addr.minblock, "\n"); + print(" freeroot ", addr.freeroot\X, "\n"); + print(" arenalist ", addr.arenalist\X, "\n"); + print(" alloc ", addr.alloc\X, "\n"); + print(" merge ", addr.merge\X, "\n"); + print(" move ", addr.move\X, "\n"); + print(" flags ", addr.flags, "\n"); + print(" nfree ", addr.nfree, "\n"); + print(" lastcompact ", addr.lastcompact, "\n"); + print(" lock ", addr.lock\X, "\n"); + print(" unlock ", addr.unlock\X, "\n"); + print(" print ", addr.print\X, "\n"); + print(" panic ", addr.panic\X, "\n"); + print(" logstack ", addr.logstack\X, "\n"); + print(" private ", addr.private\X, "\n"); +}; + +complex Pool mainmem; +complex Pool imagmem; +POOL_ANTAGONISM = 1; +POOL_PARANOIA = 2; +POOL_VERBOSITY = 4; +POOL_DEBUGGING = 8; +POOL_LOGGING = 16; +POOL_TOLERANCE = 32; +POOL_NOREUSE = 64; +sizeofBhdr = 8; +aggr Bhdr +{ + 'U' 0 magic; + 'U' 4 size; +}; + +defn +Bhdr(addr) { + complex Bhdr addr; + print(" magic ", addr.magic, "\n"); + print(" size ", addr.size, "\n"); +}; + +NOT_MAGIC = 3735943697; +DEAD_MAGIC = 3735936685; +TAIL_MAGIC0 = 190; +TAIL_MAGIC1 = 239; +sizeofBtail = 8; +aggr Btail +{ + 'b' 0 magic0; + 'a' 1 datasize; + 'b' 3 magic1; + 'U' 4 size; +}; + +defn +Btail(addr) { + complex Btail addr; + print(" magic0 ", addr.magic0, "\n"); + print(" datasize ", addr.datasize, "\n"); + print(" magic1 ", addr.magic1, "\n"); + print(" size ", addr.size, "\n"); +}; + +sizeofFree = 24; +aggr Free +{ + { + 'U' 0 magic; + 'U' 4 size; + }; + 'A' Free 8 left; + 'A' Free 12 right; + 'A' Free 16 next; + 'A' Free 20 prev; +}; + +defn +Free(addr) { + complex Free addr; + print("Bhdr {\n"); + Bhdr(addr+0); + print("}\n"); + print(" left ", addr.left\X, "\n"); + print(" right ", addr.right\X, "\n"); + print(" next ", addr.next\X, "\n"); + print(" prev ", addr.prev\X, "\n"); +}; + +FREE_MAGIC = 3126770193; +sizeofAlloc = 8; +aggr Alloc +{ + { + 'U' 0 magic; + 'U' 4 size; + }; +}; + +defn +Alloc(addr) { + complex Alloc addr; + print("Bhdr {\n"); + Bhdr(addr+0); + print("}\n"); +}; + +ALLOC_MAGIC = 168889353; +UNALLOC_MAGIC = 3400535327; +sizeofArena = 24; +aggr Arena +{ + { + 'U' 0 magic; + 'U' 4 size; + }; + 'A' Arena 8 aup; + 'A' Arena 12 down; + 'U' 16 asize; + 'U' 20 pad; +}; + +defn +Arena(addr) { + complex Arena addr; + print("Bhdr {\n"); + Bhdr(addr+0); + print("}\n"); + print(" aup ", addr.aup\X, "\n"); + print(" down ", addr.down\X, "\n"); + print(" asize ", addr.asize, "\n"); + print(" pad ", addr.pad, "\n"); +}; + +ARENA_MAGIC = 3231835599; +ARENATAIL_MAGIC = 3965590029; +ALIGN_MAGIC = 2716979649; +MINBLOCKSIZE = 32; +complex Free checklist:t; +complex Free checklist:q; +complex Free checktree:t; +complex Free ltreewalk:t; +complex Free treelookup:t; +complex Free treeinsert:tree; +complex Free treeinsert:node; +complex Free treeinsert:loc; +complex Free treeinsert:repl; +complex Free treedelete:tree; +complex Free treedelete:node; +complex Free treedelete:loc; +complex Free treedelete:lsucc; +complex Free treedelete:succ; +complex Free treelookupgt:t; +complex Free treelookupgt:lastgood; +complex Free listadd:list; +complex Free listadd:node; +complex Free listdelete:list; +complex Free listdelete:node; +complex Pool pooladd:p; +complex Alloc pooladd:anode; +complex Free pooladd:lst; +complex Free pooladd:olst; +complex Free pooladd:node; +complex Free pooladd:parent; +complex Pool pooldel:p; +complex Free pooldel:node; +complex Free pooldel:lst; +complex Free pooldel:olst; +complex Free pooldel:parent; +complex Pool dsize2bsize:p; +complex Pool bsize2asize:p; +complex Pool blockmerge:pool; +complex Bhdr blockmerge:a; +complex Bhdr blockmerge:b; +complex Btail blockmerge:t; +complex Bhdr blocksetsize:b; +complex Btail blocksetsize:t; +complex Alloc getdsize:b; +complex Btail getdsize:t; +complex Pool blocksetdsize:p; +complex Alloc blocksetdsize:b; +complex Btail blocksetdsize:t; +complex Pool trim:p; +complex Alloc trim:b; +complex Alloc trim:frag; +complex Pool freefromfront:p; +complex Alloc freefromfront:b; +complex Alloc freefromfront:bb; +complex Arena arenasetsize:a; +complex Bhdr arenasetsize:atail; +complex Pool poolnewarena:p; +complex Arena poolnewarena:a; +complex Arena poolnewarena:ap; +complex Arena poolnewarena:lastap; +complex Alloc poolnewarena:b; +complex Pool blockgrow:p; +complex Bhdr blockgrow:b; +complex Alloc blockgrow:a; +complex Bhdr blockgrow:bnxt; +complex Alloc blockgrow:a; +complex Pool arenamerge:p; +complex Arena arenamerge:bot; +complex Arena arenamerge:top; +complex Bhdr arenamerge:bbot; +complex Bhdr arenamerge:btop; +complex Btail arenamerge:t; +complex Pool dumpblock:p; +complex Bhdr dumpblock:b; +complex Pool printblock:p; +complex Bhdr printblock:b; +complex Pool panicblock:p; +complex Bhdr panicblock:b; +complex Pool blockcheck:p; +complex Bhdr blockcheck:b; +complex Alloc blockcheck:a; +complex Btail blockcheck:t; +FLOATING_MAGIC = 3419130827; +complex Pool arenacompact:p; +complex Arena arenacompact:a; +complex Bhdr arenacompact:b; +complex Bhdr arenacompact:wb; +complex Bhdr arenacompact:eb; +complex Bhdr arenacompact:nxt; +complex Pool poolcompactl:pool; +complex Arena poolcompactl:a; +complex Pool B2D:p; +complex Alloc B2D:a; +complex Pool D2B:p; +complex Alloc D2B:a; +complex Pool poolallocl:p; +complex Free poolallocl:fb; +complex Alloc poolallocl:ab; +complex Pool poolreallocl:p; +complex Alloc poolreallocl:a; +complex Bhdr poolreallocl:left; +complex Bhdr poolreallocl:right; +complex Bhdr poolreallocl:newb; +complex Btail poolreallocl:t; +complex Pool poolallocalignl:p; +complex Alloc poolallocalignl:b; +complex Pool poolfreel:p; +complex Alloc poolfreel:ab; +complex Bhdr poolfreel:back; +complex Bhdr poolfreel:fwd; +complex Pool poolalloc:p; +complex Pool poolallocalign:p; +complex Pool poolcompact:p; +complex Pool poolrealloc:p; +complex Pool poolfree:p; +complex Pool poolmsize:p; +complex Alloc poolmsize:b; +complex Pool poolcheckarena:p; +complex Arena poolcheckarena:a; +complex Bhdr poolcheckarena:b; +complex Bhdr poolcheckarena:atail; +complex Pool poolcheckl:p; +complex Arena poolcheckl:a; +complex Pool poolcheck:p; +complex Pool poolblockcheck:p; +complex Pool pooldumpl:p; +complex Arena pooldumpl:a; +complex Pool pooldump:p; +complex Pool pooldumparena:p; +complex Arena pooldumparena:a; +complex Bhdr pooldumparena:b; diff --git a/sys/src/libc/port/pool.c b/sys/src/libc/port/pool.c new file mode 100755 index 000000000..915fca3f1 --- /dev/null +++ b/sys/src/libc/port/pool.c @@ -0,0 +1,1466 @@ +/* + * This allocator takes blocks from a coarser allocator (p->alloc) and + * uses them as arenas. + * + * An arena is split into a sequence of blocks of variable size. The + * blocks begin with a Bhdr that denotes the length (including the Bhdr) + * of the block. An arena begins with an Arena header block (Arena, + * ARENA_MAGIC) and ends with a Bhdr block with magic ARENATAIL_MAGIC and + * size 0. Intermediate blocks are either allocated or free. At the end + * of each intermediate block is a Btail, which contains information + * about where the block starts. This is useful for walking backwards. + * + * Free blocks (Free*) have a magic value of FREE_MAGIC in their Bhdr + * headers. They are kept in a binary tree (p->freeroot) traversible by + * walking ->left and ->right. Each node of the binary tree is a pointer + * to a circular doubly-linked list (next, prev) of blocks of identical + * size. Blocks are added to this ``tree of lists'' by pooladd(), and + * removed by pooldel(). + * + * When freed, adjacent blocks are coalesced to create larger blocks when + * possible. + * + * Allocated blocks (Alloc*) have one of two magic values: ALLOC_MAGIC or + * UNALLOC_MAGIC. When blocks are released from the pool, they have + * magic value UNALLOC_MAGIC. Once the block has been trimmed by trim() + * and the amount of user-requested data has been recorded in the + * datasize field of the tail, the magic value is changed to ALLOC_MAGIC. + * All blocks returned to callers should be of type ALLOC_MAGIC, as + * should all blocks passed to us by callers. The amount of data the user + * asked us for can be found by subtracting the short in tail->datasize + * from header->size. Further, the up to at most four bytes between the + * end of the user-requested data block and the actual Btail structure are + * marked with a magic value, which is checked to detect user overflow. + * + * The arenas returned by p->alloc are kept in a doubly-linked list + * (p->arenalist) running through the arena headers, sorted by descending + * base address (prev, next). When a new arena is allocated, we attempt + * to merge it with its two neighbors via p->merge. + */ + +#include <u.h> +#include <libc.h> +#include <pool.h> + +typedef struct Alloc Alloc; +typedef struct Arena Arena; +typedef struct Bhdr Bhdr; +typedef struct Btail Btail; +typedef struct Free Free; + +struct Bhdr { + ulong magic; + ulong size; +}; +enum { + NOT_MAGIC = 0xdeadfa11, + DEAD_MAGIC = 0xdeaddead, +}; +#define B2NB(b) ((Bhdr*)((uchar*)(b)+(b)->size)) + +#define SHORT(x) (((x)[0] << 8) | (x)[1]) +#define PSHORT(p, x) \ + (((uchar*)(p))[0] = ((x)>>8)&0xFF, \ + ((uchar*)(p))[1] = (x)&0xFF) + +enum { + TAIL_MAGIC0 = 0xBE, + TAIL_MAGIC1 = 0xEF +}; +struct Btail { + uchar magic0; + uchar datasize[2]; + uchar magic1; + ulong size; /* same as Bhdr->size */ +}; +#define B2T(b) ((Btail*)((uchar*)(b)+(b)->size-sizeof(Btail))) +#define B2PT(b) ((Btail*)((uchar*)(b)-sizeof(Btail))) +#define T2HDR(t) ((Bhdr*)((uchar*)(t)+sizeof(Btail)-(t)->size)) +struct Free { + Bhdr; + Free* left; + Free* right; + Free* next; + Free* prev; +}; +enum { + FREE_MAGIC = 0xBA5EBA11, +}; + +/* + * the point of the notused fields is to make 8c differentiate + * between Bhdr and Allocblk, and between Kempt and Unkempt. + */ +struct Alloc { + Bhdr; +}; +enum { + ALLOC_MAGIC = 0x0A110C09, + UNALLOC_MAGIC = 0xCAB00D1E+1, +}; + +struct Arena { + Bhdr; + Arena* aup; + Arena* down; + ulong asize; + ulong pad; /* to a multiple of 8 bytes */ +}; +enum { + ARENA_MAGIC = 0xC0A1E5CE+1, + ARENATAIL_MAGIC = 0xEC5E1A0C+1, +}; +#define A2TB(a) ((Bhdr*)((uchar*)(a)+(a)->asize-sizeof(Bhdr))) +#define A2B(a) B2NB(a) + +enum { + ALIGN_MAGIC = 0xA1F1D1C1, +}; + +enum { + MINBLOCKSIZE = sizeof(Free)+sizeof(Btail) +}; + +static uchar datamagic[] = { 0xFE, 0xF1, 0xF0, 0xFA }; + +#define Poison (void*)0xCafeBabe + +#define _B2D(a) ((void*)((uchar*)a+sizeof(Bhdr))) +#define _D2B(v) ((Alloc*)((uchar*)v-sizeof(Bhdr))) + +// static void* _B2D(void*); +// static void* _D2B(void*); +static void* B2D(Pool*, Alloc*); +static Alloc* D2B(Pool*, void*); +static Arena* arenamerge(Pool*, Arena*, Arena*); +static void blockcheck(Pool*, Bhdr*); +static Alloc* blockmerge(Pool*, Bhdr*, Bhdr*); +static Alloc* blocksetdsize(Pool*, Alloc*, ulong); +static Bhdr* blocksetsize(Bhdr*, ulong); +static ulong bsize2asize(Pool*, ulong); +static ulong dsize2bsize(Pool*, ulong); +static ulong getdsize(Alloc*); +static Alloc* trim(Pool*, Alloc*, ulong); +static Free* listadd(Free*, Free*); +static Free* listdelete(Free*, Free*); +static void logstack(Pool*); +static Free** ltreewalk(Free**, ulong); +static void memmark(void*, int, ulong); +static Free* pooladd(Pool*, Alloc*); +static void* poolallocl(Pool*, ulong); +static void poolcheckl(Pool*); +static void poolcheckarena(Pool*, Arena*); +static int poolcompactl(Pool*); +static Alloc* pooldel(Pool*, Free*); +static void pooldumpl(Pool*); +static void pooldumparena(Pool*, Arena*); +static void poolfreel(Pool*, void*); +static void poolnewarena(Pool*, ulong); +static void* poolreallocl(Pool*, void*, ulong); +static Free* treedelete(Free*, Free*); +static Free* treeinsert(Free*, Free*); +static Free* treelookup(Free*, ulong); +static Free* treelookupgt(Free*, ulong); + +/* + * Debugging + * + * Antagonism causes blocks to always be filled with garbage if their + * contents are undefined. This tickles both programs and the library. + * It's a linear time hit but not so noticeable during nondegenerate use. + * It would be worth leaving in except that it negates the benefits of the + * kernel's demand-paging. The tail magic and end-of-data magic + * provide most of the user-visible benefit that antagonism does anyway. + * + * Paranoia causes the library to recheck the entire pool on each lock + * or unlock. A failed check on unlock means we tripped over ourselves, + * while a failed check on lock tends to implicate the user. Paranoia has + * the potential to slow things down a fair amount for pools with large + * numbers of allocated blocks. It completely negates all benefits won + * by the binary tree. Turning on paranoia in the kernel makes it painfully + * slow. + * + * Verbosity induces the dumping of the pool via p->print at each lock operation. + * By default, only one line is logged for each alloc, free, and realloc. + */ + +/* the if(!x);else avoids ``dangling else'' problems */ +#define antagonism if(!(p->flags & POOL_ANTAGONISM)){}else +#define paranoia if(!(p->flags & POOL_PARANOIA)){}else +#define verbosity if(!(p->flags & POOL_VERBOSITY)){}else + +#define DPRINT if(!(p->flags & POOL_DEBUGGING)){}else p->print +#define LOG if(!(p->flags & POOL_LOGGING)){}else p->print + +/* + * Tree walking + */ + +static void +checklist(Free *t) +{ + Free *q; + + for(q=t->next; q!=t; q=q->next){ + assert(q->size == t->size); + assert(q->next==nil || q->next->prev==q); + assert(q->prev==nil || q->prev->next==q); + // assert(q->left==nil); + // assert(q->right==nil); + assert(q->magic==FREE_MAGIC); + } +} + +static void +checktree(Free *t, int a, int b) +{ + assert(t->magic==FREE_MAGIC); + assert(a < t->size && t->size < b); + assert(t->next==nil || t->next->prev==t); + assert(t->prev==nil || t->prev->next==t); + checklist(t); + if(t->left) + checktree(t->left, a, t->size); + if(t->right) + checktree(t->right, t->size, b); + +} + +/* ltreewalk: return address of pointer to node of size == size */ +static Free** +ltreewalk(Free **t, ulong size) +{ + assert(t != nil /* ltreewalk */); + + for(;;) { + if(*t == nil) + return t; + + assert((*t)->magic == FREE_MAGIC); + + if(size == (*t)->size) + return t; + if(size < (*t)->size) + t = &(*t)->left; + else + t = &(*t)->right; + } +} + +/* treelookup: find node in tree with size == size */ +static Free* +treelookup(Free *t, ulong size) +{ + return *ltreewalk(&t, size); +} + +/* treeinsert: insert node into tree */ +static Free* +treeinsert(Free *tree, Free *node) +{ + Free **loc, *repl; + + assert(node != nil /* treeinsert */); + + loc = ltreewalk(&tree, node->size); + if(*loc == nil) { + node->left = nil; + node->right = nil; + } else { /* replace existing node */ + repl = *loc; + node->left = repl->left; + node->right = repl->right; + } + *loc = node; + return tree; +} + +/* treedelete: remove node from tree */ +static Free* +treedelete(Free *tree, Free *node) +{ + Free **loc, **lsucc, *succ; + + assert(node != nil /* treedelete */); + + loc = ltreewalk(&tree, node->size); + assert(*loc == node); + + if(node->left == nil) + *loc = node->right; + else if(node->right == nil) + *loc = node->left; + else { + /* have two children, use inorder successor as replacement */ + for(lsucc = &node->right; (*lsucc)->left; lsucc = &(*lsucc)->left) + ; + succ = *lsucc; + *lsucc = succ->right; + succ->left = node->left; + succ->right = node->right; + *loc = succ; + } + + node->left = node->right = Poison; + return tree; +} + +/* treelookupgt: find smallest node in tree with size >= size */ +static Free* +treelookupgt(Free *t, ulong size) +{ + Free *lastgood; /* last node we saw that was big enough */ + + lastgood = nil; + for(;;) { + if(t == nil) + return lastgood; + if(size == t->size) + return t; + if(size < t->size) { + lastgood = t; + t = t->left; + } else + t = t->right; + } +} + +/* + * List maintenance + */ + +/* listadd: add a node to a doubly linked list */ +static Free* +listadd(Free *list, Free *node) +{ + if(list == nil) { + node->next = node; + node->prev = node; + return node; + } + + node->prev = list->prev; + node->next = list; + + node->prev->next = node; + node->next->prev = node; + + return list; +} + +/* listdelete: remove node from a doubly linked list */ +static Free* +listdelete(Free *list, Free *node) +{ + if(node->next == node) { /* singular list */ + node->prev = node->next = Poison; + return nil; + } + + node->next->prev = node->prev; + node->prev->next = node->next; + + if(list == node) + list = node->next; + + node->prev = node->next = Poison; + return list; +} + +/* + * Pool maintenance + */ + +/* pooladd: add anode to the free pool */ +static Free* +pooladd(Pool *p, Alloc *anode) +{ + Free *lst, *olst; + Free *node; + Free **parent; + + antagonism { + memmark(_B2D(anode), 0xF7, anode->size-sizeof(Bhdr)-sizeof(Btail)); + } + + node = (Free*)anode; + node->magic = FREE_MAGIC; + parent = ltreewalk(&p->freeroot, node->size); + olst = *parent; + lst = listadd(olst, node); + if(olst != lst) /* need to update tree */ + *parent = treeinsert(*parent, lst); + p->curfree += node->size; + return node; +} + +/* pooldel: remove node from the free pool */ +static Alloc* +pooldel(Pool *p, Free *node) +{ + Free *lst, *olst; + Free **parent; + + parent = ltreewalk(&p->freeroot, node->size); + olst = *parent; + assert(olst != nil /* pooldel */); + + lst = listdelete(olst, node); + if(lst == nil) + *parent = treedelete(*parent, olst); + else if(lst != olst) + *parent = treeinsert(*parent, lst); + + node->left = node->right = Poison; + p->curfree -= node->size; + + antagonism { + memmark(_B2D(node), 0xF9, node->size-sizeof(Bhdr)-sizeof(Btail)); + } + + node->magic = UNALLOC_MAGIC; + return (Alloc*)node; +} + +/* + * Block maintenance + */ +/* block allocation */ +static ulong +dsize2bsize(Pool *p, ulong sz) +{ + sz += sizeof(Bhdr)+sizeof(Btail); + if(sz < p->minblock) + sz = p->minblock; + if(sz < MINBLOCKSIZE) + sz = MINBLOCKSIZE; + sz = (sz+p->quantum-1)&~(p->quantum-1); + return sz; +} + +static ulong +bsize2asize(Pool *p, ulong sz) +{ + sz += sizeof(Arena)+sizeof(Btail); + if(sz < p->minarena) + sz = p->minarena; + sz = (sz+p->quantum)&~(p->quantum-1); + return sz; +} + +/* blockmerge: merge a and b, known to be adjacent */ +/* both are removed from pool if necessary. */ +static Alloc* +blockmerge(Pool *pool, Bhdr *a, Bhdr *b) +{ + Btail *t; + + assert(B2NB(a) == b); + + if(a->magic == FREE_MAGIC) + pooldel(pool, (Free*)a); + if(b->magic == FREE_MAGIC) + pooldel(pool, (Free*)b); + + t = B2T(a); + t->size = (ulong)Poison; + t->magic0 = NOT_MAGIC; + t->magic1 = NOT_MAGIC; + PSHORT(t->datasize, NOT_MAGIC); + + a->size += b->size; + t = B2T(a); + t->size = a->size; + PSHORT(t->datasize, 0xFFFF); + + b->size = NOT_MAGIC; + b->magic = NOT_MAGIC; + + a->magic = UNALLOC_MAGIC; + return (Alloc*)a; +} + +/* blocksetsize: set the total size of a block, fixing tail pointers */ +static Bhdr* +blocksetsize(Bhdr *b, ulong bsize) +{ + Btail *t; + + assert(b->magic != FREE_MAGIC /* blocksetsize */); + + b->size = bsize; + t = B2T(b); + t->size = b->size; + t->magic0 = TAIL_MAGIC0; + t->magic1 = TAIL_MAGIC1; + return b; +} + +/* getdsize: return the requested data size for an allocated block */ +static ulong +getdsize(Alloc *b) +{ + Btail *t; + t = B2T(b); + return b->size - SHORT(t->datasize); +} + +/* blocksetdsize: set the user data size of a block */ +static Alloc* +blocksetdsize(Pool *p, Alloc *b, ulong dsize) +{ + Btail *t; + uchar *q, *eq; + + assert(b->size >= dsize2bsize(p, dsize)); + assert(b->size - dsize < 0x10000); + + t = B2T(b); + PSHORT(t->datasize, b->size - dsize); + + q=(uchar*)_B2D(b)+dsize; + eq = (uchar*)t; + if(eq > q+4) + eq = q+4; + for(; q<eq; q++) + *q = datamagic[((ulong)(uintptr)q)%nelem(datamagic)]; + + return b; +} + +/* trim: trim a block down to what is needed to hold dsize bytes of user data */ +static Alloc* +trim(Pool *p, Alloc *b, ulong dsize) +{ + ulong extra, bsize; + Alloc *frag; + + bsize = dsize2bsize(p, dsize); + extra = b->size - bsize; + if(b->size - dsize >= 0x10000 || + (extra >= bsize>>2 && extra >= MINBLOCKSIZE && extra >= p->minblock)) { + blocksetsize(b, bsize); + frag = (Alloc*) B2NB(b); + + antagonism { + memmark(frag, 0xF1, extra); + } + + frag->magic = UNALLOC_MAGIC; + blocksetsize(frag, extra); + pooladd(p, frag); + } + + b->magic = ALLOC_MAGIC; + blocksetdsize(p, b, dsize); + return b; +} + +static Alloc* +freefromfront(Pool *p, Alloc *b, ulong skip) +{ + Alloc *bb; + + skip = skip&~(p->quantum-1); + if(skip >= 0x1000 || (skip >= b->size>>2 && skip >= MINBLOCKSIZE && skip >= p->minblock)){ + bb = (Alloc*)((uchar*)b+skip); + blocksetsize(bb, b->size-skip); + bb->magic = UNALLOC_MAGIC; + blocksetsize(b, skip); + b->magic = UNALLOC_MAGIC; + pooladd(p, b); + return bb; + } + return b; +} + +/* + * Arena maintenance + */ + +/* arenasetsize: set arena size, updating tail */ +static void +arenasetsize(Arena *a, ulong asize) +{ + Bhdr *atail; + + a->asize = asize; + atail = A2TB(a); + atail->magic = ARENATAIL_MAGIC; + atail->size = 0; +} + +/* poolnewarena: allocate new arena */ +static void +poolnewarena(Pool *p, ulong asize) +{ + Arena *a; + Arena *ap, *lastap; + Alloc *b; + + LOG(p, "newarena %lud\n", asize); + if(p->cursize+asize > p->maxsize) { + if(poolcompactl(p) == 0){ + LOG(p, "pool too big: %lud+%lud > %lud\n", + p->cursize, asize, p->maxsize); + werrstr("memory pool too large"); + } + return; + } + + if((a = p->alloc(asize)) == nil) { + /* assume errstr set by p->alloc */ + return; + } + + p->cursize += asize; + + /* arena hdr */ + a->magic = ARENA_MAGIC; + blocksetsize(a, sizeof(Arena)); + arenasetsize(a, asize); + blockcheck(p, a); + + /* create one large block in arena */ + b = (Alloc*)A2B(a); + b->magic = UNALLOC_MAGIC; + blocksetsize(b, (uchar*)A2TB(a)-(uchar*)b); + blockcheck(p, b); + pooladd(p, b); + blockcheck(p, b); + + /* sort arena into descending sorted arena list */ + for(lastap=nil, ap=p->arenalist; ap > a; lastap=ap, ap=ap->down) + ; + + if(a->down = ap) /* assign = */ + a->down->aup = a; + + if(a->aup = lastap) /* assign = */ + a->aup->down = a; + else + p->arenalist = a; + + /* merge with surrounding arenas if possible */ + /* must do a with up before down with a (think about it) */ + if(a->aup) + arenamerge(p, a, a->aup); + if(a->down) + arenamerge(p, a->down, a); +} + +/* blockresize: grow a block to encompass space past its end, possibly by */ +/* trimming it into two different blocks. */ +static void +blockgrow(Pool *p, Bhdr *b, ulong nsize) +{ + if(b->magic == FREE_MAGIC) { + Alloc *a; + Bhdr *bnxt; + a = pooldel(p, (Free*)b); + blockcheck(p, a); + blocksetsize(a, nsize); + blockcheck(p, a); + bnxt = B2NB(a); + if(bnxt->magic == FREE_MAGIC) + a = blockmerge(p, a, bnxt); + blockcheck(p, a); + pooladd(p, a); + } else { + Alloc *a; + ulong dsize; + + a = (Alloc*)b; + dsize = getdsize(a); + blocksetsize(a, nsize); + trim(p, a, dsize); + } +} + +/* arenamerge: attempt to coalesce to arenas that might be adjacent */ +static Arena* +arenamerge(Pool *p, Arena *bot, Arena *top) +{ + Bhdr *bbot, *btop; + Btail *t; + + blockcheck(p, bot); + blockcheck(p, top); + assert(bot->aup == top && top > bot); + + if(p->merge == nil || p->merge(bot, top) == 0) + return nil; + + /* remove top from list */ + if(bot->aup = top->aup) /* assign = */ + bot->aup->down = bot; + else + p->arenalist = bot; + + /* save ptrs to last block in bot, first block in top */ + t = B2PT(A2TB(bot)); + bbot = T2HDR(t); + btop = A2B(top); + blockcheck(p, bbot); + blockcheck(p, btop); + + /* grow bottom arena to encompass top */ + arenasetsize(bot, top->asize + ((uchar*)top - (uchar*)bot)); + + /* grow bottom block to encompass space between arenas */ + blockgrow(p, bbot, (uchar*)btop-(uchar*)bbot); + blockcheck(p, bbot); + return bot; +} + +/* dumpblock: print block's vital stats */ +static void +dumpblock(Pool *p, Bhdr *b) +{ + ulong *dp; + ulong dsize; + uchar *cp; + + dp = (ulong*)b; + p->print(p, "pool %s block %p\nhdr %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\n", + p->name, b, dp[0], dp[1], dp[2], dp[3], dp[4], dp[5], dp[6]); + + dp = (ulong*)B2T(b); + p->print(p, "tail %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux | %.8lux %.8lux\n", + dp[-6], dp[-5], dp[-4], dp[-3], dp[-2], dp[-1], dp[0], dp[1]); + + if(b->magic == ALLOC_MAGIC){ + dsize = getdsize((Alloc*)b); + if(dsize >= b->size) /* user data size corrupt */ + return; + + cp = (uchar*)_B2D(b)+dsize; + p->print(p, "user data "); + p->print(p, "%.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux", + cp[-8], cp[-7], cp[-6], cp[-5], cp[-4], cp[-3], cp[-2], cp[-1]); + p->print(p, " | %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } +} + +static void +printblock(Pool *p, Bhdr *b, char *msg) +{ + p->print(p, "%s\n", msg); + dumpblock(p, b); +} + +static void +panicblock(Pool *p, Bhdr *b, char *msg) +{ + p->print(p, "%s\n", msg); + dumpblock(p, b); + p->panic(p, "pool panic"); +} + +/* blockcheck: ensure a block consistent with our expectations */ +/* should only be called when holding pool lock */ +static void +blockcheck(Pool *p, Bhdr *b) +{ + Alloc *a; + Btail *t; + int i, n; + uchar *q, *bq, *eq; + ulong dsize; + + switch(b->magic) { + default: + panicblock(p, b, "bad magic"); + case FREE_MAGIC: + case UNALLOC_MAGIC: + t = B2T(b); + if(t->magic0 != TAIL_MAGIC0 || t->magic1 != TAIL_MAGIC1) + panicblock(p, b, "corrupt tail magic"); + if(T2HDR(t) != b) + panicblock(p, b, "corrupt tail ptr"); + break; + case DEAD_MAGIC: + t = B2T(b); + if(t->magic0 != TAIL_MAGIC0 || t->magic1 != TAIL_MAGIC1) + panicblock(p, b, "corrupt tail magic"); + if(T2HDR(t) != b) + panicblock(p, b, "corrupt tail ptr"); + n = getdsize((Alloc*)b); + q = _B2D(b); + q += 8; + for(i=8; i<n; i++) + if(*q++ != 0xDA) + panicblock(p, b, "dangling pointer write"); + break; + case ARENA_MAGIC: + b = A2TB((Arena*)b); + if(b->magic != ARENATAIL_MAGIC) + panicblock(p, b, "bad arena size"); + /* fall through */ + case ARENATAIL_MAGIC: + if(b->size != 0) + panicblock(p, b, "bad arena tail size"); + break; + case ALLOC_MAGIC: + a = (Alloc*)b; + t = B2T(b); + dsize = getdsize(a); + bq = (uchar*)_B2D(a)+dsize; + eq = (uchar*)t; + + if(t->magic0 != TAIL_MAGIC0){ + /* if someone wrote exactly one byte over and it was a NUL, we sometimes only complain. */ + if((p->flags & POOL_TOLERANCE) && bq == eq && t->magic0 == 0) + printblock(p, b, "mem user overflow (magic0)"); + else + panicblock(p, b, "corrupt tail magic0"); + } + + if(t->magic1 != TAIL_MAGIC1) + panicblock(p, b, "corrupt tail magic1"); + if(T2HDR(t) != b) + panicblock(p, b, "corrupt tail ptr"); + + if(dsize2bsize(p, dsize) > a->size) + panicblock(p, b, "too much block data"); + + if(eq > bq+4) + eq = bq+4; + for(q=bq; q<eq; q++){ + if(*q != datamagic[((uintptr)q)%nelem(datamagic)]){ + if(q == bq && *q == 0 && (p->flags & POOL_TOLERANCE)){ + printblock(p, b, "mem user overflow"); + continue; + } + panicblock(p, b, "mem user overflow"); + } + } + break; + } +} + +/* + * compact an arena by shifting all the free blocks to the end. + * assumes pool lock is held. + */ +enum { + FLOATING_MAGIC = 0xCBCBCBCB, /* temporarily neither allocated nor in the free tree */ +}; + +static int +arenacompact(Pool *p, Arena *a) +{ + Bhdr *b, *wb, *eb, *nxt; + int compacted; + + if(p->move == nil) + p->panic(p, "don't call me when pool->move is nil\n"); + + poolcheckarena(p, a); + eb = A2TB(a); + compacted = 0; + for(b=wb=A2B(a); b && b < eb; b=nxt) { + nxt = B2NB(b); + switch(b->magic) { + case FREE_MAGIC: + pooldel(p, (Free*)b); + b->magic = FLOATING_MAGIC; + break; + case ALLOC_MAGIC: + if(wb != b) { + memmove(wb, b, b->size); + p->move(_B2D(b), _B2D(wb)); + compacted = 1; + } + wb = B2NB(wb); + break; + } + } + + /* + * the only free data is now at the end of the arena, pointed + * at by wb. all we need to do is set its size and get out. + */ + if(wb < eb) { + wb->magic = UNALLOC_MAGIC; + blocksetsize(wb, (uchar*)eb-(uchar*)wb); + pooladd(p, (Alloc*)wb); + } + + return compacted; +} + +/* + * compact a pool by compacting each individual arena. + * 'twould be nice to shift blocks from one arena to the + * next but it's a pain to code. + */ +static int +poolcompactl(Pool *pool) +{ + Arena *a; + int compacted; + + if(pool->move == nil || pool->lastcompact == pool->nfree) + return 0; + + pool->lastcompact = pool->nfree; + compacted = 0; + for(a=pool->arenalist; a; a=a->down) + compacted |= arenacompact(pool, a); + return compacted; +} + +/* +static int +poolcompactl(Pool*) +{ + return 0; +} +*/ + +/* + * Actual allocators + */ + +/* +static void* +_B2D(void *a) +{ + return (uchar*)a+sizeof(Bhdr); +} +*/ + +static void* +B2D(Pool *p, Alloc *a) +{ + if(a->magic != ALLOC_MAGIC) + p->panic(p, "B2D called on unworthy block"); + return _B2D(a); +} + +/* +static void* +_D2B(void *v) +{ + Alloc *a; + a = (Alloc*)((uchar*)v-sizeof(Bhdr)); + return a; +} +*/ + +static Alloc* +D2B(Pool *p, void *v) +{ + Alloc *a; + ulong *u; + + if((uintptr)v&(sizeof(ulong)-1)) + v = (char*)v - ((uintptr)v&(sizeof(ulong)-1)); + u = v; + while(u[-1] == ALIGN_MAGIC) + u--; + a = _D2B(u); + if(a->magic != ALLOC_MAGIC) + p->panic(p, "D2B called on non-block %p (double-free?)", v); + return a; +} + +/* poolallocl: attempt to allocate block to hold dsize user bytes; assumes lock held */ +static void* +poolallocl(Pool *p, ulong dsize) +{ + ulong bsize; + Free *fb; + Alloc *ab; + + if(dsize >= 0x80000000UL){ /* for sanity, overflow */ + werrstr("invalid allocation size"); + return nil; + } + + bsize = dsize2bsize(p, dsize); + + fb = treelookupgt(p->freeroot, bsize); + if(fb == nil) { + poolnewarena(p, bsize2asize(p, bsize)); + if((fb = treelookupgt(p->freeroot, bsize)) == nil) { + /* assume poolnewarena failed and set %r */ + return nil; + } + } + + ab = trim(p, pooldel(p, fb), dsize); + p->curalloc += ab->size; + antagonism { + memset(B2D(p, ab), 0xDF, dsize); + } + return B2D(p, ab); +} + +/* poolreallocl: attempt to grow v to ndsize bytes; assumes lock held */ +static void* +poolreallocl(Pool *p, void *v, ulong ndsize) +{ + Alloc *a; + Bhdr *left, *right, *newb; + Btail *t; + ulong nbsize; + ulong odsize; + ulong obsize; + void *nv; + + if(v == nil) /* for ANSI */ + return poolallocl(p, ndsize); + if(ndsize == 0) { + poolfreel(p, v); + return nil; + } + a = D2B(p, v); + blockcheck(p, a); + odsize = getdsize(a); + obsize = a->size; + + /* can reuse the same block? */ + nbsize = dsize2bsize(p, ndsize); + if(nbsize <= a->size) { + Returnblock: + if(v != _B2D(a)) + memmove(_B2D(a), v, odsize); + a = trim(p, a, ndsize); + p->curalloc -= obsize; + p->curalloc += a->size; + v = B2D(p, a); + return v; + } + + /* can merge with surrounding blocks? */ + right = B2NB(a); + if(right->magic == FREE_MAGIC && a->size+right->size >= nbsize) { + a = blockmerge(p, a, right); + goto Returnblock; + } + + t = B2PT(a); + left = T2HDR(t); + if(left->magic == FREE_MAGIC && left->size+a->size >= nbsize) { + a = blockmerge(p, left, a); + goto Returnblock; + } + + if(left->magic == FREE_MAGIC && right->magic == FREE_MAGIC + && left->size+a->size+right->size >= nbsize) { + a = blockmerge(p, blockmerge(p, left, a), right); + goto Returnblock; + } + + if((nv = poolallocl(p, ndsize)) == nil) + return nil; + + /* maybe the new block is next to us; if so, merge */ + left = T2HDR(B2PT(a)); + right = B2NB(a); + newb = D2B(p, nv); + if(left == newb || right == newb) { + if(left == newb || left->magic == FREE_MAGIC) + a = blockmerge(p, left, a); + if(right == newb || right->magic == FREE_MAGIC) + a = blockmerge(p, a, right); + assert(a->size >= nbsize); + goto Returnblock; + } + + /* enough cleverness */ + memmove(nv, v, odsize); + antagonism { + memset((char*)nv+odsize, 0xDE, ndsize-odsize); + } + poolfreel(p, v); + return nv; +} + +static void* +alignptr(void *v, ulong align, long offset) +{ + char *c; + ulong off; + + c = v; + if(align){ + off = (uintptr)c%align; + if(off != offset){ + c += offset - off; + if(off > offset) + c += align; + } + } + return c; +} + +/* poolspanallocl: allocate as described below; assumes pool locked */ +static void* +poolallocalignl(Pool *p, ulong dsize, ulong align, long offset, ulong span) +{ + ulong asize; + void *v; + char *c; + ulong *u; + int skip; + Alloc *b; + + /* + * allocate block + * dsize bytes + * addr == offset (modulo align) + * does not cross span-byte block boundary + * + * to satisfy alignment, just allocate an extra + * align bytes and then shift appropriately. + * + * to satisfy span, try once and see if we're + * lucky. the second time, allocate 2x asize + * so that we definitely get one not crossing + * the boundary. + */ + if(align){ + if(offset < 0) + offset = align - ((-offset)%align); + else + offset %= align; + } + asize = dsize+align; + v = poolallocl(p, asize); + if(v == nil) + return nil; + if(span && (uintptr)v/span != ((uintptr)v+asize)/span){ + /* try again */ + poolfreel(p, v); + v = poolallocl(p, 2*asize); + if(v == nil) + return nil; + } + + /* + * figure out what pointer we want to return + */ + c = alignptr(v, align, offset); + if(span && (uintptr)c/span != (uintptr)(c+dsize-1)/span){ + c += span - (uintptr)c%span; + c = alignptr(c, align, offset); + if((uintptr)c/span != (uintptr)(c+dsize-1)/span){ + poolfreel(p, v); + werrstr("cannot satisfy dsize %lud span %lud with align %lud+%ld", dsize, span, align, offset); + return nil; + } + } + skip = c - (char*)v; + + /* + * free up the skip bytes before that pointer + * or mark it as unavailable. + */ + b = _D2B(v); + b = freefromfront(p, b, skip); + v = _B2D(b); + skip = c - (char*)v; + if(c > (char*)v){ + u = v; + while(c >= (char*)u+sizeof(ulong)) + *u++ = ALIGN_MAGIC; + } + trim(p, b, skip+dsize); + assert(D2B(p, c) == b); + antagonism { + memset(c, 0xDD, dsize); + } + return c; +} + +/* poolfree: free block obtained from poolalloc; assumes lock held */ +static void +poolfreel(Pool *p, void *v) +{ + Alloc *ab; + Bhdr *back, *fwd; + + if(v == nil) /* for ANSI */ + return; + + ab = D2B(p, v); + blockcheck(p, ab); + + if(p->flags&POOL_NOREUSE){ + int n; + + ab->magic = DEAD_MAGIC; + n = getdsize(ab)-8; + if(n > 0) + memset((uchar*)v+8, 0xDA, n); + return; + } + + p->nfree++; + p->curalloc -= ab->size; + back = T2HDR(B2PT(ab)); + if(back->magic == FREE_MAGIC) + ab = blockmerge(p, back, ab); + + fwd = B2NB(ab); + if(fwd->magic == FREE_MAGIC) + ab = blockmerge(p, ab, fwd); + + pooladd(p, ab); +} + +void* +poolalloc(Pool *p, ulong n) +{ + void *v; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + v = poolallocl(p, n); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolalloc %p %lud = %p\n", p, n, v); + p->unlock(p); + return v; +} + +void* +poolallocalign(Pool *p, ulong n, ulong align, long offset, ulong span) +{ + void *v; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + v = poolallocalignl(p, n, align, offset, span); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolalignspanalloc %p %lud %lud %lud %ld = %p\n", p, n, align, span, offset, v); + p->unlock(p); + return v; +} + +int +poolcompact(Pool *p) +{ + int rv; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + rv = poolcompactl(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + LOG(p, "poolcompact %p\n", p); + p->unlock(p); + return rv; +} + +void* +poolrealloc(Pool *p, void *v, ulong n) +{ + void *nv; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + nv = poolreallocl(p, v, n); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolrealloc %p %p %ld = %p\n", p, v, n, nv); + p->unlock(p); + return nv; +} + +void +poolfree(Pool *p, void *v) +{ + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + poolfreel(p, v); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolfree %p %p\n", p, v); + p->unlock(p); +} + +/* + * Return the real size of a block, and let the user use it. + */ +ulong +poolmsize(Pool *p, void *v) +{ + Alloc *b; + ulong dsize; + + p->lock(p); + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(v == nil) /* consistency with other braindead ANSI-ness */ + dsize = 0; + else { + b = D2B(p, v); + dsize = (b->size&~(p->quantum-1)) - sizeof(Bhdr) - sizeof(Btail); + assert(dsize >= getdsize(b)); + blocksetdsize(p, b, dsize); + } + paranoia { + poolcheckl(p); + } + verbosity { + pooldumpl(p); + } + if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); + LOG(p, "poolmsize %p %p = %ld\n", p, v, dsize); + p->unlock(p); + return dsize; +} + +/* + * Debugging + */ + +static void +poolcheckarena(Pool *p, Arena *a) +{ + Bhdr *b; + Bhdr *atail; + + atail = A2TB(a); + for(b=a; b->magic != ARENATAIL_MAGIC && b<atail; b=B2NB(b)) + blockcheck(p, b); + blockcheck(p, b); + if(b != atail) + p->panic(p, "found wrong tail"); +} + +static void +poolcheckl(Pool *p) +{ + Arena *a; + + for(a=p->arenalist; a; a=a->down) + poolcheckarena(p, a); + if(p->freeroot) + checktree(p->freeroot, 0, 1<<30); +} + +void +poolcheck(Pool *p) +{ + p->lock(p); + poolcheckl(p); + p->unlock(p); +} + +void +poolblockcheck(Pool *p, void *v) +{ + if(v == nil) + return; + + p->lock(p); + blockcheck(p, D2B(p, v)); + p->unlock(p); +} + +static void +pooldumpl(Pool *p) +{ + Arena *a; + + p->print(p, "pool %p %s\n", p, p->name); + for(a=p->arenalist; a; a=a->down) + pooldumparena(p, a); +} + +void +pooldump(Pool *p) +{ + p->lock(p); + pooldumpl(p); + p->unlock(p); +} + +static void +pooldumparena(Pool *p, Arena *a) +{ + Bhdr *b; + + for(b=a; b->magic != ARENATAIL_MAGIC; b=B2NB(b)) + p->print(p, "(%p %.8lux %lud)", b, b->magic, b->size); + p->print(p, "\n"); +} + +/* + * mark the memory in such a way that we know who marked it + * (via the signature) and we know where the marking started. + */ +static void +memmark(void *v, int sig, ulong size) +{ + uchar *p, *ep; + ulong *lp, *elp; + lp = v; + elp = lp+size/4; + while(lp < elp) + *lp++ = (sig<<24) ^ ((uintptr)lp-(uintptr)v); + p = (uchar*)lp; + ep = (uchar*)v+size; + while(p<ep) + *p++ = sig; +} diff --git a/sys/src/libc/port/pow.c b/sys/src/libc/port/pow.c new file mode 100755 index 000000000..0a5a0b5cd --- /dev/null +++ b/sys/src/libc/port/pow.c @@ -0,0 +1,69 @@ +#include <u.h> +#include <libc.h> + +double +pow(double x, double y) /* return x ^ y (exponentiation) */ +{ + double xy, y1, ye; + long i; + int ex, ey, flip; + + if(y == 0.0) + return 1.0; + + flip = 0; + if(y < 0.){ + y = -y; + flip = 1; + } + y1 = modf(y, &ye); + if(y1 != 0.0){ + if(x <= 0.) + goto zreturn; + if(y1 > 0.5) { + y1 -= 1.; + ye += 1.; + } + xy = exp(y1 * log(x)); + }else + xy = 1.0; + if(ye > 0x7FFFFFFF){ /* should be ~0UL but compiler can't convert double to ulong */ + if(x <= 0.){ + zreturn: + if(x==0. && !flip) + return 0.; + return NaN(); + } + if(flip){ + if(y == .5) + return 1./sqrt(x); + y = -y; + }else if(y == .5) + return sqrt(x); + return exp(y * log(x)); + } + x = frexp(x, &ex); + ey = 0; + i = ye; + if(i) + for(;;){ + if(i & 1){ + xy *= x; + ey += ex; + } + i >>= 1; + if(i == 0) + break; + x *= x; + ex <<= 1; + if(x < .5){ + x += x; + ex -= 1; + } + } + if(flip){ + xy = 1. / xy; + ey = -ey; + } + return ldexp(xy, ey); +} diff --git a/sys/src/libc/port/pow10.c b/sys/src/libc/port/pow10.c new file mode 100755 index 000000000..7e09f3cc4 --- /dev/null +++ b/sys/src/libc/port/pow10.c @@ -0,0 +1,49 @@ +#include <u.h> +#include <libc.h> + +/* + * this table might overflow 127-bit exponent representations. + * in that case, truncate it after 1.0e38. + * it is important to get all one can from this + * routine since it is used in atof to scale numbers. + * the presumption is that C converts fp numbers better + * than multipication of lower powers of 10. + */ +static +double tab[] = +{ + 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, + 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, + 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, + 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, + 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49, + 1.0e50, 1.0e51, 1.0e52, 1.0e53, 1.0e54, 1.0e55, 1.0e56, 1.0e57, 1.0e58, 1.0e59, + 1.0e60, 1.0e61, 1.0e62, 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, + 1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79, + 1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, + 1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99, + 1.0e100,1.0e101,1.0e102,1.0e103,1.0e104,1.0e105,1.0e106,1.0e107,1.0e108,1.0e109, + 1.0e110,1.0e111,1.0e112,1.0e113,1.0e114,1.0e115,1.0e116,1.0e117,1.0e118,1.0e119, + 1.0e120,1.0e121,1.0e122,1.0e123,1.0e124,1.0e125,1.0e126,1.0e127,1.0e128,1.0e129, + 1.0e130,1.0e131,1.0e132,1.0e133,1.0e134,1.0e135,1.0e136,1.0e137,1.0e138,1.0e139, + 1.0e140,1.0e141,1.0e142,1.0e143,1.0e144,1.0e145,1.0e146,1.0e147,1.0e148,1.0e149, + 1.0e150,1.0e151,1.0e152,1.0e153,1.0e154,1.0e155,1.0e156,1.0e157,1.0e158,1.0e159, +}; + +double +pow10(int n) +{ + int m; + + if(n < 0) { + n = -n; + if(n < sizeof(tab)/sizeof(tab[0])) + return 1/tab[n]; + m = n/2; + return 1/(pow10(m) * pow10(n-m)); + } + if(n < sizeof(tab)/sizeof(tab[0])) + return tab[n]; + m = n/2; + return pow10(m) * pow10(n-m); +} diff --git a/sys/src/libc/port/profile.c b/sys/src/libc/port/profile.c new file mode 100755 index 000000000..5647e3bf1 --- /dev/null +++ b/sys/src/libc/port/profile.c @@ -0,0 +1,280 @@ +#include <u.h> +#include <libc.h> +#include <tos.h> + +extern long _callpc(void**); +extern long _savearg(void); + +static ulong khz; +static ulong perr; +static int havecycles; + +typedef struct Plink Plink; +struct Plink +{ + Plink *old; + Plink *down; + Plink *link; + long pc; + long count; + vlong time; +}; + +#pragma profile off + +ulong +_profin(void) +{ + void *dummy; + long pc; + Plink *pp, *p; + ulong arg; + vlong t; + + arg = _savearg(); + pc = _callpc(&dummy); + pp = _tos->prof.pp; + if(pp == 0 || (_tos->prof.pid && _tos->pid != _tos->prof.pid)) + return arg; + + for(p=pp->down; p; p=p->link) + if(p->pc == pc) + goto out; + p = _tos->prof.next + 1; + if(p >= _tos->prof.last) { + _tos->prof.pp = 0; + perr++; + return arg; + } + _tos->prof.next = p; + p->link = pp->down; + pp->down = p; + p->pc = pc; + p->old = pp; + p->down = 0; + p->count = 0; + p->time = 0LL; + +out: + _tos->prof.pp = p; + p->count++; + switch(_tos->prof.what){ + case Profkernel: + p->time = p->time - _tos->pcycles; + goto proftime; + case Profuser: + /* Add kernel cycles on proc entry */ + p->time = p->time + _tos->kcycles; + /* fall through */ + case Proftime: + proftime: /* Subtract cycle counter on proc entry */ + cycles((uvlong*)&t); + p->time = p->time - t; + break; + case Profsample: + p->time = p->time - _tos->clock; + break; + } + return arg; /* disgusting linkage */ +} + +ulong +_profout(void) +{ + Plink *p; + ulong arg; + vlong t; + + arg = _savearg(); + p = _tos->prof.pp; + if (p == nil || (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid)) + return arg; /* Not our process */ + switch(_tos->prof.what){ + case Profkernel: /* Add proc cycles on proc entry */ + p->time = p->time + _tos->pcycles; + goto proftime; + case Profuser: /* Subtract kernel cycles on proc entry */ + p->time = p->time - _tos->kcycles; + /* fall through */ + case Proftime: + proftime: /* Add cycle counter on proc entry */ + cycles((uvlong*)&t); + p->time = p->time + t; + break; + case Profsample: + p->time = p->time + _tos->clock; + break; + } + _tos->prof.pp = p->old; + return arg; +} + +void +_profdump(void) +{ + int f; + long n; + Plink *p; + char *vp; + char filename[64]; + + if (_tos->prof.what == 0) + return; /* No profiling */ + if (_tos->prof.pid != 0 && _tos->pid != _tos->prof.pid) + return; /* Not our process */ + if(perr) + fprint(2, "%lud Prof errors\n", perr); + _tos->prof.pp = nil; + if (_tos->prof.pid) + snprint(filename, sizeof filename - 1, "prof.%ld", _tos->prof.pid); + else + snprint(filename, sizeof filename - 1, "prof.out"); + f = create(filename, 1, 0666); + if(f < 0) { + perror("create prof.out"); + return; + } + _tos->prof.pid = ~0; /* make sure data gets dumped once */ + switch(_tos->prof.what){ + case Profkernel: + cycles((uvlong*)&_tos->prof.first->time); + _tos->prof.first->time = _tos->prof.first->time + _tos->pcycles; + break; + case Profuser: + cycles((uvlong*)&_tos->prof.first->time); + _tos->prof.first->time = _tos->prof.first->time - _tos->kcycles; + break; + case Proftime: + cycles((uvlong*)&_tos->prof.first->time); + break; + case Profsample: + _tos->prof.first->time = _tos->clock; + break; + } + vp = (char*)_tos->prof.first; + + for(p = _tos->prof.first; p <= _tos->prof.next; p++) { + + /* + * short down + */ + n = 0xffff; + if(p->down) + n = p->down - _tos->prof.first; + vp[0] = n>>8; + vp[1] = n; + + /* + * short right + */ + n = 0xffff; + if(p->link) + n = p->link - _tos->prof.first; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + + /* + * long pc + */ + n = p->pc; + vp[0] = n>>24; + vp[1] = n>>16; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + + /* + * long count + */ + n = p->count; + vp[0] = n>>24; + vp[1] = n>>16; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + + /* + * vlong time + */ + if (havecycles){ + n = (vlong)(p->time / (vlong)khz); + }else + n = p->time; + + vp[0] = n>>24; + vp[1] = n>>16; + vp[2] = n>>8; + vp[3] = n; + vp += 4; + } + write(f, (char*)_tos->prof.first, vp - (char*)_tos->prof.first); + close(f); +} + +void +_profinit(int entries, int what) +{ + if (_tos->prof.what == 0) + return; /* Profiling not linked in */ + _tos->prof.pp = nil; + _tos->prof.first = mallocz(entries*sizeof(Plink),1); + _tos->prof.last = _tos->prof.first + entries; + _tos->prof.next = _tos->prof.first; + _tos->prof.pid = _tos->pid; + _tos->prof.what = what; + _tos->clock = 1; +} + +void +_profmain(void) +{ + char ename[50]; + int n, f; + + n = 2000; + if (_tos->cyclefreq != 0LL){ + khz = _tos->cyclefreq / 1000; /* Report times in milliseconds */ + havecycles = 1; + } + f = open("/env/profsize", OREAD); + if(f >= 0) { + memset(ename, 0, sizeof(ename)); + read(f, ename, sizeof(ename)-1); + close(f); + n = atol(ename); + } + _tos->prof.what = Profuser; + f = open("/env/proftype", OREAD); + if(f >= 0) { + memset(ename, 0, sizeof(ename)); + read(f, ename, sizeof(ename)-1); + close(f); + if (strcmp(ename, "user") == 0) + _tos->prof.what = Profuser; + else if (strcmp(ename, "kernel") == 0) + _tos->prof.what = Profkernel; + else if (strcmp(ename, "elapsed") == 0 || strcmp(ename, "time") == 0) + _tos->prof.what = Proftime; + else if (strcmp(ename, "sample") == 0) + _tos->prof.what = Profsample; + } + _tos->prof.first = sbrk(n*sizeof(Plink)); + _tos->prof.last = sbrk(0); + _tos->prof.next = _tos->prof.first; + _tos->prof.pp = nil; + _tos->prof.pid = _tos->pid; + atexit(_profdump); + _tos->clock = 1; +} + +void prof(void (*fn)(void*), void *arg, int entries, int what) +{ + _profinit(entries, what); + _tos->prof.pp = _tos->prof.next; + fn(arg); + _profdump(); +} + +#pragma profile on + diff --git a/sys/src/libc/port/qsort.c b/sys/src/libc/port/qsort.c new file mode 100755 index 000000000..91c768c77 --- /dev/null +++ b/sys/src/libc/port/qsort.c @@ -0,0 +1,124 @@ +/* + * qsort -- simple quicksort + */ + +#include <u.h> + +typedef +struct +{ + int (*cmp)(void*, void*); + void (*swap)(char*, char*, long); + long es; +} Sort; + +static void +swapb(char *i, char *j, long es) +{ + char c; + + do { + c = *i; + *i++ = *j; + *j++ = c; + es--; + } while(es != 0); + +} + +static void +swapi(char *ii, char *ij, long es) +{ + long *i, *j, c; + + i = (long*)ii; + j = (long*)ij; + do { + c = *i; + *i++ = *j; + *j++ = c; + es -= sizeof(long); + } while(es != 0); +} + +static char* +pivot(char *a, long n, Sort *p) +{ + long j; + char *pi, *pj, *pk; + + j = n/6 * p->es; + pi = a + j; /* 1/6 */ + j += j; + pj = pi + j; /* 1/2 */ + pk = pj + j; /* 5/6 */ + if(p->cmp(pi, pj) < 0) { + if(p->cmp(pi, pk) < 0) { + if(p->cmp(pj, pk) < 0) + return pj; + return pk; + } + return pi; + } + if(p->cmp(pj, pk) < 0) { + if(p->cmp(pi, pk) < 0) + return pi; + return pk; + } + return pj; +} + +static void +qsorts(char *a, long n, Sort *p) +{ + long j, es; + char *pi, *pj, *pn; + + es = p->es; + while(n > 1) { + if(n > 10) { + pi = pivot(a, n, p); + } else + pi = a + (n>>1)*es; + + p->swap(a, pi, es); + pi = a; + pn = a + n*es; + pj = pn; + for(;;) { + do + pi += es; + while(pi < pn && p->cmp(pi, a) < 0); + do + pj -= es; + while(pj > a && p->cmp(pj, a) > 0); + if(pj < pi) + break; + p->swap(pi, pj, es); + } + p->swap(a, pj, es); + j = (pj - a) / es; + + n = n-j-1; + if(j >= n) { + qsorts(a, j, p); + a += (j+1)*es; + } else { + qsorts(a + (j+1)*es, n, p); + n = j; + } + } +} + +void +qsort(void *va, long n, long es, int (*cmp)(void*, void*)) +{ + Sort s; + + s.cmp = cmp; + s.es = es; + s.swap = swapi; + if(((uintptr)va | es) % sizeof(long)) + s.swap = swapb; + qsorts((char*)va, n, &s); +} diff --git a/sys/src/libc/port/quote.c b/sys/src/libc/port/quote.c new file mode 100755 index 000000000..99f70084c --- /dev/null +++ b/sys/src/libc/port/quote.c @@ -0,0 +1,135 @@ +#include <u.h> +#include <libc.h> + +int (*doquote)(int); + +extern int _needsquotes(char*, int*); +extern int _runeneedsquotes(Rune*, int*); + +char* +unquotestrdup(char *s) +{ + char *t, *ret; + int quoting; + + ret = s = strdup(s); /* return unquoted copy */ + if(ret == nil) + return ret; + quoting = 0; + t = s; /* s is output string, t is input string */ + while(*t!='\0' && (quoting || (*t!=' ' && *t!='\t'))){ + if(*t != '\''){ + *s++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s++ = *t++; + } + if(t != s) + memmove(s, t, strlen(t)+1); + return ret; +} + +Rune* +unquoterunestrdup(Rune *s) +{ + Rune *t, *ret; + int quoting; + + ret = s = runestrdup(s); /* return unquoted copy */ + if(ret == nil) + return ret; + quoting = 0; + t = s; /* s is output string, t is input string */ + while(*t!='\0' && (quoting || (*t!=' ' && *t!='\t'))){ + if(*t != '\''){ + *s++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s++ = *t++; + } + if(t != s) + memmove(s, t, (runestrlen(t)+1)*sizeof(Rune)); + return ret; +} + +char* +quotestrdup(char *s) +{ + char *t, *u, *ret; + int quotelen; + Rune r; + + if(_needsquotes(s, "elen) == 0) + return strdup(s); + + ret = malloc(quotelen+1); + if(ret == nil) + return nil; + u = ret; + *u++ = '\''; + for(t=s; *t; t++){ + r = *t; + if(r == L'\'') + *u++ = r; /* double the quote */ + *u++ = r; + } + *u++ = '\''; + *u = '\0'; + return ret; +} + +Rune* +quoterunestrdup(Rune *s) +{ + Rune *t, *u, *ret; + int quotelen; + Rune r; + + if(_runeneedsquotes(s, "elen) == 0) + return runestrdup(s); + + ret = malloc((quotelen+1)*sizeof(Rune)); + if(ret == nil) + return nil; + u = ret; + *u++ = '\''; + for(t=s; *t; t++){ + r = *t; + if(r == L'\'') + *u++ = r; /* double the quote */ + *u++ = r; + } + *u++ = '\''; + *u = '\0'; + return ret; +} diff --git a/sys/src/libc/port/rand.c b/sys/src/libc/port/rand.c new file mode 100755 index 000000000..366e9e967 --- /dev/null +++ b/sys/src/libc/port/rand.c @@ -0,0 +1,8 @@ +#include <u.h> +#include <libc.h> + +int +rand(void) +{ + return lrand() & 0x7fff; +} diff --git a/sys/src/libc/port/readn.c b/sys/src/libc/port/readn.c new file mode 100755 index 000000000..629dfd9ed --- /dev/null +++ b/sys/src/libc/port/readn.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> + +long +readn(int f, void *av, long n) +{ + char *a; + long m, t; + + a = av; + t = 0; + while(t < n){ + m = read(f, a+t, n-t); + if(m <= 0){ + if(t == 0) + return m; + break; + } + t += m; + } + return t; +} diff --git a/sys/src/libc/port/reduce b/sys/src/libc/port/reduce new file mode 100755 index 000000000..584f8b9ab --- /dev/null +++ b/sys/src/libc/port/reduce @@ -0,0 +1,16 @@ +O=$1 +shift +objtype=$1 +shift + +ls -p ../$objtype/*.[cs] >[2]/dev/null | sed 's/..$//;s/^/^/' > /tmp/reduce.$pid +# +# if empty directory, just return the input files +# +if (! ~ $status '|') { + echo $* + rm /tmp/reduce.$pid + exit 0 +} +echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' ' +rm /tmp/reduce.$pid diff --git a/sys/src/libc/port/rune.c b/sys/src/libc/port/rune.c new file mode 100755 index 000000000..b62da9e66 --- /dev/null +++ b/sys/src/libc/port/rune.c @@ -0,0 +1,162 @@ +#include <u.h> +#include <libc.h> + +enum +{ + Bit1 = 7, + Bitx = 6, + Bit2 = 5, + Bit3 = 4, + Bit4 = 3, + + T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ + Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ + T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ + T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ + T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + + Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ + Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ + Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ + + Maskx = (1<<Bitx)-1, /* 0011 1111 */ + Testx = Maskx ^ 0xFF, /* 1100 0000 */ + + Bad = Runeerror, +}; + +int +chartorune(Rune *rune, char *str) +{ + int c, c1, c2; + long l; + + /* + * one character sequence + * 00000-0007F => T1 + */ + c = *(uchar*)str; + if(c < Tx) { + *rune = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + c1 = *(uchar*)(str+1) ^ Tx; + if(c1 & Testx) + goto bad; + if(c < T3) { + if(c < T2) + goto bad; + l = ((c << Bitx) | c1) & Rune2; + if(l <= Rune1) + goto bad; + *rune = l; + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + c2 = *(uchar*)(str+2) ^ Tx; + if(c2 & Testx) + goto bad; + if(c < T4) { + l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; + if(l <= Rune2) + goto bad; + *rune = l; + return 3; + } + + /* + * bad decoding + */ +bad: + *rune = Bad; + return 1; +} + +int +runetochar(char *str, Rune *rune) +{ + long c; + + /* + * one character sequence + * 00000-0007F => 00-7F + */ + c = *rune; + if(c <= Rune1) { + str[0] = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + if(c <= Rune2) { + str[0] = T2 | (c >> 1*Bitx); + str[1] = Tx | (c & Maskx); + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; +} + +int +runelen(long c) +{ + Rune rune; + char str[10]; + + rune = c; + return runetochar(str, &rune); +} + +int +runenlen(Rune *r, int nrune) +{ + int nb, c; + + nb = 0; + while(nrune--) { + c = *r++; + if(c <= Rune1) + nb++; + else + if(c <= Rune2) + nb += 2; + else + nb += 3; + } + return nb; +} + +int +fullrune(char *str, int n) +{ + int c; + + if(n > 0) { + c = *(uchar*)str; + if(c < Tx) + return 1; + if(n > 1) + if(c < T3 || n > 2) + return 1; + } + return 0; +} diff --git a/sys/src/libc/port/runestrcat.c b/sys/src/libc/port/runestrcat.c new file mode 100755 index 000000000..4c8363067 --- /dev/null +++ b/sys/src/libc/port/runestrcat.c @@ -0,0 +1,10 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrcat(Rune *s1, Rune *s2) +{ + + runestrcpy(runestrchr(s1, 0), s2); + return s1; +} diff --git a/sys/src/libc/port/runestrchr.c b/sys/src/libc/port/runestrchr.c new file mode 100755 index 000000000..af7fc4e88 --- /dev/null +++ b/sys/src/libc/port/runestrchr.c @@ -0,0 +1,20 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrchr(Rune *s, Rune c) +{ + Rune c0 = c; + Rune c1; + + if(c == 0) { + while(*s++) + ; + return s-1; + } + + while(c1 = *s++) + if(c1 == c0) + return s-1; + return 0; +} diff --git a/sys/src/libc/port/runestrcmp.c b/sys/src/libc/port/runestrcmp.c new file mode 100755 index 000000000..e3bda3738 --- /dev/null +++ b/sys/src/libc/port/runestrcmp.c @@ -0,0 +1,20 @@ +#include <u.h> +#include <libc.h> + +int +runestrcmp(Rune *s1, Rune *s2) +{ + Rune c1, c2; + + for(;;) { + c1 = *s1++; + c2 = *s2++; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + return 0; + } +} diff --git a/sys/src/libc/port/runestrcpy.c b/sys/src/libc/port/runestrcpy.c new file mode 100755 index 000000000..efddc0734 --- /dev/null +++ b/sys/src/libc/port/runestrcpy.c @@ -0,0 +1,13 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrcpy(Rune *s1, Rune *s2) +{ + Rune *os1; + + os1 = s1; + while(*s1++ = *s2++) + ; + return os1; +} diff --git a/sys/src/libc/port/runestrdup.c b/sys/src/libc/port/runestrdup.c new file mode 100755 index 000000000..f66b430b6 --- /dev/null +++ b/sys/src/libc/port/runestrdup.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrdup(Rune *s) +{ + Rune *ns; + + ns = malloc(sizeof(Rune)*(runestrlen(s) + 1)); + if(ns == 0) + return 0; + + return runestrcpy(ns, s); +} diff --git a/sys/src/libc/port/runestrecpy.c b/sys/src/libc/port/runestrecpy.c new file mode 100755 index 000000000..d3ca81044 --- /dev/null +++ b/sys/src/libc/port/runestrecpy.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrecpy(Rune *s1, Rune *es1, Rune *s2) +{ + if(s1 >= es1) + return s1; + + while(*s1++ = *s2++){ + if(s1 == es1){ + *--s1 = '\0'; + break; + } + } + return s1; +} diff --git a/sys/src/libc/port/runestrlen.c b/sys/src/libc/port/runestrlen.c new file mode 100755 index 000000000..2bf4a4eb6 --- /dev/null +++ b/sys/src/libc/port/runestrlen.c @@ -0,0 +1,9 @@ +#include <u.h> +#include <libc.h> + +long +runestrlen(Rune *s) +{ + + return runestrchr(s, 0) - s; +} diff --git a/sys/src/libc/port/runestrncat.c b/sys/src/libc/port/runestrncat.c new file mode 100755 index 000000000..9d6ee46a6 --- /dev/null +++ b/sys/src/libc/port/runestrncat.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrncat(Rune *s1, Rune *s2, long n) +{ + Rune *os1; + + os1 = s1; + s1 = runestrchr(s1, 0); + while(*s1++ = *s2++) + if(--n < 0) { + s1[-1] = 0; + break; + } + return os1; +} diff --git a/sys/src/libc/port/runestrncmp.c b/sys/src/libc/port/runestrncmp.c new file mode 100755 index 000000000..5e566fa0c --- /dev/null +++ b/sys/src/libc/port/runestrncmp.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> + +int +runestrncmp(Rune *s1, Rune *s2, long n) +{ + Rune c1, c2; + + while(n > 0) { + c1 = *s1++; + c2 = *s2++; + n--; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + break; + } + return 0; +} diff --git a/sys/src/libc/port/runestrncpy.c b/sys/src/libc/port/runestrncpy.c new file mode 100755 index 000000000..7e84e33f7 --- /dev/null +++ b/sys/src/libc/port/runestrncpy.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrncpy(Rune *s1, Rune *s2, long n) +{ + int i; + Rune *os1; + + os1 = s1; + for(i = 0; i < n; i++) + if((*s1++ = *s2++) == 0) { + while(++i < n) + *s1++ = 0; + return os1; + } + return os1; +} diff --git a/sys/src/libc/port/runestrrchr.c b/sys/src/libc/port/runestrrchr.c new file mode 100755 index 000000000..4c8074ba0 --- /dev/null +++ b/sys/src/libc/port/runestrrchr.c @@ -0,0 +1,15 @@ +#include <u.h> +#include <libc.h> + +Rune* +runestrrchr(Rune *s, Rune c) +{ + Rune *r; + + if(c == 0) + return runestrchr(s, 0); + r = 0; + while(s = runestrchr(s, c)) + r = s++; + return r; +} diff --git a/sys/src/libc/port/runestrstr.c b/sys/src/libc/port/runestrstr.c new file mode 100755 index 000000000..b7f6964b2 --- /dev/null +++ b/sys/src/libc/port/runestrstr.c @@ -0,0 +1,29 @@ +#include <u.h> +#include <libc.h> + +/* + * Return pointer to first occurrence of s2 in s1, + * 0 if none + */ +Rune* +runestrstr(Rune *s1, Rune *s2) +{ + Rune *p, *pa, *pb; + int c0, c; + + c0 = *s2; + if(c0 == 0) + return s1; + s2++; + for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) { + pa = p; + for(pb=s2;; pb++) { + c = *pb; + if(c == 0) + return p; + if(c != *++pa) + break; + } + } + return 0; +} diff --git a/sys/src/libc/port/runetype.c b/sys/src/libc/port/runetype.c new file mode 100755 index 000000000..f7ec1bb98 --- /dev/null +++ b/sys/src/libc/port/runetype.c @@ -0,0 +1,1181 @@ +#include <u.h> +#include <libc.h> + +/* + * alpha ranges - + * only covers ranges not in lower||upper + */ +static +Rune _alpha2[] = +{ + 0x00d8, 0x00f6, /* Ø - ö */ + 0x00f8, 0x01f5, /* ø - ǵ */ + 0x0250, 0x02a8, /* ɐ - ʨ */ + 0x038e, 0x03a1, /* Ύ - Ρ */ + 0x03a3, 0x03ce, /* Σ - ώ */ + 0x03d0, 0x03d6, /* ϐ - ϖ */ + 0x03e2, 0x03f3, /* Ϣ - ϳ */ + 0x0490, 0x04c4, /* Ґ - ӄ */ + 0x0561, 0x0587, /* ա - և */ + 0x05d0, 0x05ea, /* א - ת */ + 0x05f0, 0x05f2, /* װ - ײ */ + 0x0621, 0x063a, /* ء - غ */ + 0x0640, 0x064a, /* ـ - ي */ + 0x0671, 0x06b7, /* ٱ - ڷ */ + 0x06ba, 0x06be, /* ں - ھ */ + 0x06c0, 0x06ce, /* ۀ - ێ */ + 0x06d0, 0x06d3, /* ې - ۓ */ + 0x0905, 0x0939, /* अ - ह */ + 0x0958, 0x0961, /* क़ - ॡ */ + 0x0985, 0x098c, /* অ - ঌ */ + 0x098f, 0x0990, /* এ - ঐ */ + 0x0993, 0x09a8, /* ও - ন */ + 0x09aa, 0x09b0, /* প - র */ + 0x09b6, 0x09b9, /* শ - হ */ + 0x09dc, 0x09dd, /* ড় - ঢ় */ + 0x09df, 0x09e1, /* য় - ৡ */ + 0x09f0, 0x09f1, /* ৰ - ৱ */ + 0x0a05, 0x0a0a, /* ਅ - ਊ */ + 0x0a0f, 0x0a10, /* ਏ - ਐ */ + 0x0a13, 0x0a28, /* ਓ - ਨ */ + 0x0a2a, 0x0a30, /* ਪ - ਰ */ + 0x0a32, 0x0a33, /* ਲ - ਲ਼ */ + 0x0a35, 0x0a36, /* ਵ - ਸ਼ */ + 0x0a38, 0x0a39, /* ਸ - ਹ */ + 0x0a59, 0x0a5c, /* ਖ਼ - ੜ */ + 0x0a85, 0x0a8b, /* અ - ઋ */ + 0x0a8f, 0x0a91, /* એ - ઑ */ + 0x0a93, 0x0aa8, /* ઓ - ન */ + 0x0aaa, 0x0ab0, /* પ - ર */ + 0x0ab2, 0x0ab3, /* લ - ળ */ + 0x0ab5, 0x0ab9, /* વ - હ */ + 0x0b05, 0x0b0c, /* ଅ - ଌ */ + 0x0b0f, 0x0b10, /* ଏ - ଐ */ + 0x0b13, 0x0b28, /* ଓ - ନ */ + 0x0b2a, 0x0b30, /* ପ - ର */ + 0x0b32, 0x0b33, /* ଲ - ଳ */ + 0x0b36, 0x0b39, /* ଶ - ହ */ + 0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */ + 0x0b5f, 0x0b61, /* ୟ - ୡ */ + 0x0b85, 0x0b8a, /* அ - ஊ */ + 0x0b8e, 0x0b90, /* எ - ஐ */ + 0x0b92, 0x0b95, /* ஒ - க */ + 0x0b99, 0x0b9a, /* ங - ச */ + 0x0b9e, 0x0b9f, /* ஞ - ட */ + 0x0ba3, 0x0ba4, /* ண - த */ + 0x0ba8, 0x0baa, /* ந - ப */ + 0x0bae, 0x0bb5, /* ம - வ */ + 0x0bb7, 0x0bb9, /* ஷ - ஹ */ + 0x0c05, 0x0c0c, /* అ - ఌ */ + 0x0c0e, 0x0c10, /* ఎ - ఐ */ + 0x0c12, 0x0c28, /* ఒ - న */ + 0x0c2a, 0x0c33, /* ప - ళ */ + 0x0c35, 0x0c39, /* వ - హ */ + 0x0c60, 0x0c61, /* ౠ - ౡ */ + 0x0c85, 0x0c8c, /* ಅ - ಌ */ + 0x0c8e, 0x0c90, /* ಎ - ಐ */ + 0x0c92, 0x0ca8, /* ಒ - ನ */ + 0x0caa, 0x0cb3, /* ಪ - ಳ */ + 0x0cb5, 0x0cb9, /* ವ - ಹ */ + 0x0ce0, 0x0ce1, /* ೠ - ೡ */ + 0x0d05, 0x0d0c, /* അ - ഌ */ + 0x0d0e, 0x0d10, /* എ - ഐ */ + 0x0d12, 0x0d28, /* ഒ - ന */ + 0x0d2a, 0x0d39, /* പ - ഹ */ + 0x0d60, 0x0d61, /* ൠ - ൡ */ + 0x0e01, 0x0e30, /* ก - ะ */ + 0x0e32, 0x0e33, /* า - ำ */ + 0x0e40, 0x0e46, /* เ - ๆ */ + 0x0e5a, 0x0e5b, /* ๚ - ๛ */ + 0x0e81, 0x0e82, /* ກ - ຂ */ + 0x0e87, 0x0e88, /* ງ - ຈ */ + 0x0e94, 0x0e97, /* ດ - ທ */ + 0x0e99, 0x0e9f, /* ນ - ຟ */ + 0x0ea1, 0x0ea3, /* ມ - ຣ */ + 0x0eaa, 0x0eab, /* ສ - ຫ */ + 0x0ead, 0x0eae, /* ອ - ຮ */ + 0x0eb2, 0x0eb3, /* າ - ຳ */ + 0x0ec0, 0x0ec4, /* ເ - ໄ */ + 0x0edc, 0x0edd, /* ໜ - ໝ */ + 0x0f18, 0x0f19, /* ༘ - ༙ */ + 0x0f40, 0x0f47, /* ཀ - ཇ */ + 0x0f49, 0x0f69, /* ཉ - ཀྵ */ + 0x10d0, 0x10f6, /* ა - ჶ */ + 0x1100, 0x1159, /* ᄀ - ᅙ */ + 0x115f, 0x11a2, /* ᅟ - ᆢ */ + 0x11a8, 0x11f9, /* ᆨ - ᇹ */ + 0x1e00, 0x1e9b, /* Ḁ - ẛ */ + 0x1f50, 0x1f57, /* ὐ - ὗ */ + 0x1f80, 0x1fb4, /* ᾀ - ᾴ */ + 0x1fb6, 0x1fbc, /* ᾶ - ᾼ */ + 0x1fc2, 0x1fc4, /* ῂ - ῄ */ + 0x1fc6, 0x1fcc, /* ῆ - ῌ */ + 0x1fd0, 0x1fd3, /* ῐ - ΐ */ + 0x1fd6, 0x1fdb, /* ῖ - Ί */ + 0x1fe0, 0x1fec, /* ῠ - Ῥ */ + 0x1ff2, 0x1ff4, /* ῲ - ῴ */ + 0x1ff6, 0x1ffc, /* ῶ - ῼ */ + 0x210a, 0x2113, /* ℊ - ℓ */ + 0x2115, 0x211d, /* ℕ - ℝ */ + 0x2120, 0x2122, /* ℠ - ™ */ + 0x212a, 0x2131, /* K - ℱ */ + 0x2133, 0x2138, /* ℳ - ℸ */ + 0x3041, 0x3094, /* ぁ - ゔ */ + 0x30a1, 0x30fa, /* ァ - ヺ */ + 0x3105, 0x312c, /* ㄅ - ㄬ */ + 0x3131, 0x318e, /* ㄱ - ㆎ */ + 0x3192, 0x319f, /* ㆒ - ㆟ */ + 0x3260, 0x327b, /* ㉠ - ㉻ */ + 0x328a, 0x32b0, /* ㊊ - ㊰ */ + 0x32d0, 0x32fe, /* ㋐ - ㋾ */ + 0x3300, 0x3357, /* ㌀ - ㍗ */ + 0x3371, 0x3376, /* ㍱ - ㍶ */ + 0x337b, 0x3394, /* ㍻ - ㎔ */ + 0x3399, 0x339e, /* ㎙ - ㎞ */ + 0x33a9, 0x33ad, /* ㎩ - ㎭ */ + 0x33b0, 0x33c1, /* ㎰ - ㏁ */ + 0x33c3, 0x33c5, /* ㏃ - ㏅ */ + 0x33c7, 0x33d7, /* ㏇ - ㏗ */ + 0x33d9, 0x33dd, /* ㏙ - ㏝ */ + 0x4e00, 0x9fff, /* 一 - 鿿 */ + 0xac00, 0xd7a3, /* 가 - 힣 */ + 0xf900, 0xfb06, /* 豈 - st */ + 0xfb13, 0xfb17, /* ﬓ - ﬗ */ + 0xfb1f, 0xfb28, /* ײַ - ﬨ */ + 0xfb2a, 0xfb36, /* שׁ - זּ */ + 0xfb38, 0xfb3c, /* טּ - לּ */ + 0xfb40, 0xfb41, /* נּ - סּ */ + 0xfb43, 0xfb44, /* ףּ - פּ */ + 0xfb46, 0xfbb1, /* צּ - ﮱ */ + 0xfbd3, 0xfd3d, /* ﯓ - ﴽ */ + 0xfd50, 0xfd8f, /* ﵐ - ﶏ */ + 0xfd92, 0xfdc7, /* ﶒ - ﷇ */ + 0xfdf0, 0xfdf9, /* ﷰ - ﷹ */ + 0xfe70, 0xfe72, /* ﹰ - ﹲ */ + 0xfe76, 0xfefc, /* ﹶ - ﻼ */ + 0xff66, 0xff6f, /* ヲ - ッ */ + 0xff71, 0xff9d, /* ア - ン */ + 0xffa0, 0xffbe, /* ᅠ - ᄒ */ + 0xffc2, 0xffc7, /* ᅡ - ᅦ */ + 0xffca, 0xffcf, /* ᅧ - ᅬ */ + 0xffd2, 0xffd7, /* ᅭ - ᅲ */ + 0xffda, 0xffdc, /* ᅳ - ᅵ */ +}; + +/* + * alpha singlets - + * only covers ranges not in lower||upper + */ +static +Rune _alpha1[] = +{ + 0x00aa, /* ª */ + 0x00b5, /* µ */ + 0x00ba, /* º */ + 0x03da, /* Ϛ */ + 0x03dc, /* Ϝ */ + 0x03de, /* Ϟ */ + 0x03e0, /* Ϡ */ + 0x06d5, /* ە */ + 0x09b2, /* ল */ + 0x0a5e, /* ਫ਼ */ + 0x0a8d, /* ઍ */ + 0x0ae0, /* ૠ */ + 0x0b9c, /* ஜ */ + 0x0cde, /* ೞ */ + 0x0e4f, /* ๏ */ + 0x0e84, /* ຄ */ + 0x0e8a, /* ຊ */ + 0x0e8d, /* ຍ */ + 0x0ea5, /* ລ */ + 0x0ea7, /* ວ */ + 0x0eb0, /* ະ */ + 0x0ebd, /* ຽ */ + 0x1fbe, /* ι */ + 0x207f, /* ⁿ */ + 0x20a8, /* ₨ */ + 0x2102, /* ℂ */ + 0x2107, /* ℇ */ + 0x2124, /* ℤ */ + 0x2126, /* Ω */ + 0x2128, /* ℨ */ + 0xfb3e, /* מּ */ + 0xfe74, /* ﹴ */ +}; + +/* + * space ranges + */ +static +Rune _space2[] = +{ + 0x0009, 0x000a, /* tab and newline */ + 0x0020, 0x0020, /* space */ + 0x0085, 0x0085, + 0x00a0, 0x00a0, /* */ + 0x1680, 0x1680, + 0x180e, 0x180e, + 0x2000, 0x200b, /* - */ + 0x2028, 0x2029, /*
-
*/ + 0x202f, 0x202f, + 0x205f, 0x205f, + 0x3000, 0x3000, /* */ + 0xfeff, 0xfeff, /* */ +}; + +/* + * lower case ranges + * 3rd col is conversion excess 500 + */ +static +Rune _toupper2[] = +{ + 0x0061, 0x007a, 468, /* a-z A-Z */ + 0x00e0, 0x00f6, 468, /* à-ö À-Ö */ + 0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */ + 0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */ + 0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */ + 0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */ + 0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */ + 0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */ + 0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */ + 0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */ + 0x0430, 0x044f, 468, /* а-я А-Я */ + 0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */ + 0x045e, 0x045f, 420, /* ў-џ Ў-Џ */ + 0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */ + 0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */ + 0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */ + 0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */ + 0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */ + 0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */ + 0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */ + 0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */ + 0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */ + 0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */ + 0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */ + 0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */ + 0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */ + 0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */ + 0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */ + 0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */ + 0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */ + 0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */ + 0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */ + 0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */ + 0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */ + 0xff41, 0xff5a, 468, /* a-z A-Z */ +}; + +/* + * lower case singlets + * 2nd col is conversion excess 500 + */ +static +Rune _toupper1[] = +{ + 0x00ff, 621, /* ÿ Ÿ */ + 0x0101, 499, /* ā Ā */ + 0x0103, 499, /* ă Ă */ + 0x0105, 499, /* ą Ą */ + 0x0107, 499, /* ć Ć */ + 0x0109, 499, /* ĉ Ĉ */ + 0x010b, 499, /* ċ Ċ */ + 0x010d, 499, /* č Č */ + 0x010f, 499, /* ď Ď */ + 0x0111, 499, /* đ Đ */ + 0x0113, 499, /* ē Ē */ + 0x0115, 499, /* ĕ Ĕ */ + 0x0117, 499, /* ė Ė */ + 0x0119, 499, /* ę Ę */ + 0x011b, 499, /* ě Ě */ + 0x011d, 499, /* ĝ Ĝ */ + 0x011f, 499, /* ğ Ğ */ + 0x0121, 499, /* ġ Ġ */ + 0x0123, 499, /* ģ Ģ */ + 0x0125, 499, /* ĥ Ĥ */ + 0x0127, 499, /* ħ Ħ */ + 0x0129, 499, /* ĩ Ĩ */ + 0x012b, 499, /* ī Ī */ + 0x012d, 499, /* ĭ Ĭ */ + 0x012f, 499, /* į Į */ + 0x0131, 268, /* ı I */ + 0x0133, 499, /* ij IJ */ + 0x0135, 499, /* ĵ Ĵ */ + 0x0137, 499, /* ķ Ķ */ + 0x013a, 499, /* ĺ Ĺ */ + 0x013c, 499, /* ļ Ļ */ + 0x013e, 499, /* ľ Ľ */ + 0x0140, 499, /* ŀ Ŀ */ + 0x0142, 499, /* ł Ł */ + 0x0144, 499, /* ń Ń */ + 0x0146, 499, /* ņ Ņ */ + 0x0148, 499, /* ň Ň */ + 0x014b, 499, /* ŋ Ŋ */ + 0x014d, 499, /* ō Ō */ + 0x014f, 499, /* ŏ Ŏ */ + 0x0151, 499, /* ő Ő */ + 0x0153, 499, /* œ Œ */ + 0x0155, 499, /* ŕ Ŕ */ + 0x0157, 499, /* ŗ Ŗ */ + 0x0159, 499, /* ř Ř */ + 0x015b, 499, /* ś Ś */ + 0x015d, 499, /* ŝ Ŝ */ + 0x015f, 499, /* ş Ş */ + 0x0161, 499, /* š Š */ + 0x0163, 499, /* ţ Ţ */ + 0x0165, 499, /* ť Ť */ + 0x0167, 499, /* ŧ Ŧ */ + 0x0169, 499, /* ũ Ũ */ + 0x016b, 499, /* ū Ū */ + 0x016d, 499, /* ŭ Ŭ */ + 0x016f, 499, /* ů Ů */ + 0x0171, 499, /* ű Ű */ + 0x0173, 499, /* ų Ų */ + 0x0175, 499, /* ŵ Ŵ */ + 0x0177, 499, /* ŷ Ŷ */ + 0x017a, 499, /* ź Ź */ + 0x017c, 499, /* ż Ż */ + 0x017e, 499, /* ž Ž */ + 0x017f, 200, /* ſ S */ + 0x0183, 499, /* ƃ Ƃ */ + 0x0185, 499, /* ƅ Ƅ */ + 0x0188, 499, /* ƈ Ƈ */ + 0x018c, 499, /* ƌ Ƌ */ + 0x0192, 499, /* ƒ Ƒ */ + 0x0199, 499, /* ƙ Ƙ */ + 0x01a1, 499, /* ơ Ơ */ + 0x01a3, 499, /* ƣ Ƣ */ + 0x01a5, 499, /* ƥ Ƥ */ + 0x01a8, 499, /* ƨ Ƨ */ + 0x01ad, 499, /* ƭ Ƭ */ + 0x01b0, 499, /* ư Ư */ + 0x01b4, 499, /* ƴ Ƴ */ + 0x01b6, 499, /* ƶ Ƶ */ + 0x01b9, 499, /* ƹ Ƹ */ + 0x01bd, 499, /* ƽ Ƽ */ + 0x01c5, 499, /* Dž DŽ */ + 0x01c6, 498, /* dž DŽ */ + 0x01c8, 499, /* Lj LJ */ + 0x01c9, 498, /* lj LJ */ + 0x01cb, 499, /* Nj NJ */ + 0x01cc, 498, /* nj NJ */ + 0x01ce, 499, /* ǎ Ǎ */ + 0x01d0, 499, /* ǐ Ǐ */ + 0x01d2, 499, /* ǒ Ǒ */ + 0x01d4, 499, /* ǔ Ǔ */ + 0x01d6, 499, /* ǖ Ǖ */ + 0x01d8, 499, /* ǘ Ǘ */ + 0x01da, 499, /* ǚ Ǚ */ + 0x01dc, 499, /* ǜ Ǜ */ + 0x01df, 499, /* ǟ Ǟ */ + 0x01e1, 499, /* ǡ Ǡ */ + 0x01e3, 499, /* ǣ Ǣ */ + 0x01e5, 499, /* ǥ Ǥ */ + 0x01e7, 499, /* ǧ Ǧ */ + 0x01e9, 499, /* ǩ Ǩ */ + 0x01eb, 499, /* ǫ Ǫ */ + 0x01ed, 499, /* ǭ Ǭ */ + 0x01ef, 499, /* ǯ Ǯ */ + 0x01f2, 499, /* Dz DZ */ + 0x01f3, 498, /* dz DZ */ + 0x01f5, 499, /* ǵ Ǵ */ + 0x01fb, 499, /* ǻ Ǻ */ + 0x01fd, 499, /* ǽ Ǽ */ + 0x01ff, 499, /* ǿ Ǿ */ + 0x0201, 499, /* ȁ Ȁ */ + 0x0203, 499, /* ȃ Ȃ */ + 0x0205, 499, /* ȅ Ȅ */ + 0x0207, 499, /* ȇ Ȇ */ + 0x0209, 499, /* ȉ Ȉ */ + 0x020b, 499, /* ȋ Ȋ */ + 0x020d, 499, /* ȍ Ȍ */ + 0x020f, 499, /* ȏ Ȏ */ + 0x0211, 499, /* ȑ Ȑ */ + 0x0213, 499, /* ȓ Ȓ */ + 0x0215, 499, /* ȕ Ȕ */ + 0x0217, 499, /* ȗ Ȗ */ + 0x0253, 290, /* ɓ Ɓ */ + 0x0254, 294, /* ɔ Ɔ */ + 0x025b, 297, /* ɛ Ɛ */ + 0x0260, 295, /* ɠ Ɠ */ + 0x0263, 293, /* ɣ Ɣ */ + 0x0268, 291, /* ɨ Ɨ */ + 0x0269, 289, /* ɩ Ɩ */ + 0x026f, 289, /* ɯ Ɯ */ + 0x0272, 287, /* ɲ Ɲ */ + 0x0283, 282, /* ʃ Ʃ */ + 0x0288, 282, /* ʈ Ʈ */ + 0x0292, 281, /* ʒ Ʒ */ + 0x03ac, 462, /* ά Ά */ + 0x03cc, 436, /* ό Ό */ + 0x03d0, 438, /* ϐ Β */ + 0x03d1, 443, /* ϑ Θ */ + 0x03d5, 453, /* ϕ Φ */ + 0x03d6, 446, /* ϖ Π */ + 0x03e3, 499, /* ϣ Ϣ */ + 0x03e5, 499, /* ϥ Ϥ */ + 0x03e7, 499, /* ϧ Ϧ */ + 0x03e9, 499, /* ϩ Ϩ */ + 0x03eb, 499, /* ϫ Ϫ */ + 0x03ed, 499, /* ϭ Ϭ */ + 0x03ef, 499, /* ϯ Ϯ */ + 0x03f0, 414, /* ϰ Κ */ + 0x03f1, 420, /* ϱ Ρ */ + 0x0461, 499, /* ѡ Ѡ */ + 0x0463, 499, /* ѣ Ѣ */ + 0x0465, 499, /* ѥ Ѥ */ + 0x0467, 499, /* ѧ Ѧ */ + 0x0469, 499, /* ѩ Ѩ */ + 0x046b, 499, /* ѫ Ѫ */ + 0x046d, 499, /* ѭ Ѭ */ + 0x046f, 499, /* ѯ Ѯ */ + 0x0471, 499, /* ѱ Ѱ */ + 0x0473, 499, /* ѳ Ѳ */ + 0x0475, 499, /* ѵ Ѵ */ + 0x0477, 499, /* ѷ Ѷ */ + 0x0479, 499, /* ѹ Ѹ */ + 0x047b, 499, /* ѻ Ѻ */ + 0x047d, 499, /* ѽ Ѽ */ + 0x047f, 499, /* ѿ Ѿ */ + 0x0481, 499, /* ҁ Ҁ */ + 0x0491, 499, /* ґ Ґ */ + 0x0493, 499, /* ғ Ғ */ + 0x0495, 499, /* ҕ Ҕ */ + 0x0497, 499, /* җ Җ */ + 0x0499, 499, /* ҙ Ҙ */ + 0x049b, 499, /* қ Қ */ + 0x049d, 499, /* ҝ Ҝ */ + 0x049f, 499, /* ҟ Ҟ */ + 0x04a1, 499, /* ҡ Ҡ */ + 0x04a3, 499, /* ң Ң */ + 0x04a5, 499, /* ҥ Ҥ */ + 0x04a7, 499, /* ҧ Ҧ */ + 0x04a9, 499, /* ҩ Ҩ */ + 0x04ab, 499, /* ҫ Ҫ */ + 0x04ad, 499, /* ҭ Ҭ */ + 0x04af, 499, /* ү Ү */ + 0x04b1, 499, /* ұ Ұ */ + 0x04b3, 499, /* ҳ Ҳ */ + 0x04b5, 499, /* ҵ Ҵ */ + 0x04b7, 499, /* ҷ Ҷ */ + 0x04b9, 499, /* ҹ Ҹ */ + 0x04bb, 499, /* һ Һ */ + 0x04bd, 499, /* ҽ Ҽ */ + 0x04bf, 499, /* ҿ Ҿ */ + 0x04c2, 499, /* ӂ Ӂ */ + 0x04c4, 499, /* ӄ Ӄ */ + 0x04c8, 499, /* ӈ Ӈ */ + 0x04cc, 499, /* ӌ Ӌ */ + 0x04d1, 499, /* ӑ Ӑ */ + 0x04d3, 499, /* ӓ Ӓ */ + 0x04d5, 499, /* ӕ Ӕ */ + 0x04d7, 499, /* ӗ Ӗ */ + 0x04d9, 499, /* ә Ә */ + 0x04db, 499, /* ӛ Ӛ */ + 0x04dd, 499, /* ӝ Ӝ */ + 0x04df, 499, /* ӟ Ӟ */ + 0x04e1, 499, /* ӡ Ӡ */ + 0x04e3, 499, /* ӣ Ӣ */ + 0x04e5, 499, /* ӥ Ӥ */ + 0x04e7, 499, /* ӧ Ӧ */ + 0x04e9, 499, /* ө Ө */ + 0x04eb, 499, /* ӫ Ӫ */ + 0x04ef, 499, /* ӯ Ӯ */ + 0x04f1, 499, /* ӱ Ӱ */ + 0x04f3, 499, /* ӳ Ӳ */ + 0x04f5, 499, /* ӵ Ӵ */ + 0x04f9, 499, /* ӹ Ӹ */ + 0x1e01, 499, /* ḁ Ḁ */ + 0x1e03, 499, /* ḃ Ḃ */ + 0x1e05, 499, /* ḅ Ḅ */ + 0x1e07, 499, /* ḇ Ḇ */ + 0x1e09, 499, /* ḉ Ḉ */ + 0x1e0b, 499, /* ḋ Ḋ */ + 0x1e0d, 499, /* ḍ Ḍ */ + 0x1e0f, 499, /* ḏ Ḏ */ + 0x1e11, 499, /* ḑ Ḑ */ + 0x1e13, 499, /* ḓ Ḓ */ + 0x1e15, 499, /* ḕ Ḕ */ + 0x1e17, 499, /* ḗ Ḗ */ + 0x1e19, 499, /* ḙ Ḙ */ + 0x1e1b, 499, /* ḛ Ḛ */ + 0x1e1d, 499, /* ḝ Ḝ */ + 0x1e1f, 499, /* ḟ Ḟ */ + 0x1e21, 499, /* ḡ Ḡ */ + 0x1e23, 499, /* ḣ Ḣ */ + 0x1e25, 499, /* ḥ Ḥ */ + 0x1e27, 499, /* ḧ Ḧ */ + 0x1e29, 499, /* ḩ Ḩ */ + 0x1e2b, 499, /* ḫ Ḫ */ + 0x1e2d, 499, /* ḭ Ḭ */ + 0x1e2f, 499, /* ḯ Ḯ */ + 0x1e31, 499, /* ḱ Ḱ */ + 0x1e33, 499, /* ḳ Ḳ */ + 0x1e35, 499, /* ḵ Ḵ */ + 0x1e37, 499, /* ḷ Ḷ */ + 0x1e39, 499, /* ḹ Ḹ */ + 0x1e3b, 499, /* ḻ Ḻ */ + 0x1e3d, 499, /* ḽ Ḽ */ + 0x1e3f, 499, /* ḿ Ḿ */ + 0x1e41, 499, /* ṁ Ṁ */ + 0x1e43, 499, /* ṃ Ṃ */ + 0x1e45, 499, /* ṅ Ṅ */ + 0x1e47, 499, /* ṇ Ṇ */ + 0x1e49, 499, /* ṉ Ṉ */ + 0x1e4b, 499, /* ṋ Ṋ */ + 0x1e4d, 499, /* ṍ Ṍ */ + 0x1e4f, 499, /* ṏ Ṏ */ + 0x1e51, 499, /* ṑ Ṑ */ + 0x1e53, 499, /* ṓ Ṓ */ + 0x1e55, 499, /* ṕ Ṕ */ + 0x1e57, 499, /* ṗ Ṗ */ + 0x1e59, 499, /* ṙ Ṙ */ + 0x1e5b, 499, /* ṛ Ṛ */ + 0x1e5d, 499, /* ṝ Ṝ */ + 0x1e5f, 499, /* ṟ Ṟ */ + 0x1e61, 499, /* ṡ Ṡ */ + 0x1e63, 499, /* ṣ Ṣ */ + 0x1e65, 499, /* ṥ Ṥ */ + 0x1e67, 499, /* ṧ Ṧ */ + 0x1e69, 499, /* ṩ Ṩ */ + 0x1e6b, 499, /* ṫ Ṫ */ + 0x1e6d, 499, /* ṭ Ṭ */ + 0x1e6f, 499, /* ṯ Ṯ */ + 0x1e71, 499, /* ṱ Ṱ */ + 0x1e73, 499, /* ṳ Ṳ */ + 0x1e75, 499, /* ṵ Ṵ */ + 0x1e77, 499, /* ṷ Ṷ */ + 0x1e79, 499, /* ṹ Ṹ */ + 0x1e7b, 499, /* ṻ Ṻ */ + 0x1e7d, 499, /* ṽ Ṽ */ + 0x1e7f, 499, /* ṿ Ṿ */ + 0x1e81, 499, /* ẁ Ẁ */ + 0x1e83, 499, /* ẃ Ẃ */ + 0x1e85, 499, /* ẅ Ẅ */ + 0x1e87, 499, /* ẇ Ẇ */ + 0x1e89, 499, /* ẉ Ẉ */ + 0x1e8b, 499, /* ẋ Ẋ */ + 0x1e8d, 499, /* ẍ Ẍ */ + 0x1e8f, 499, /* ẏ Ẏ */ + 0x1e91, 499, /* ẑ Ẑ */ + 0x1e93, 499, /* ẓ Ẓ */ + 0x1e95, 499, /* ẕ Ẕ */ + 0x1ea1, 499, /* ạ Ạ */ + 0x1ea3, 499, /* ả Ả */ + 0x1ea5, 499, /* ấ Ấ */ + 0x1ea7, 499, /* ầ Ầ */ + 0x1ea9, 499, /* ẩ Ẩ */ + 0x1eab, 499, /* ẫ Ẫ */ + 0x1ead, 499, /* ậ Ậ */ + 0x1eaf, 499, /* ắ Ắ */ + 0x1eb1, 499, /* ằ Ằ */ + 0x1eb3, 499, /* ẳ Ẳ */ + 0x1eb5, 499, /* ẵ Ẵ */ + 0x1eb7, 499, /* ặ Ặ */ + 0x1eb9, 499, /* ẹ Ẹ */ + 0x1ebb, 499, /* ẻ Ẻ */ + 0x1ebd, 499, /* ẽ Ẽ */ + 0x1ebf, 499, /* ế Ế */ + 0x1ec1, 499, /* ề Ề */ + 0x1ec3, 499, /* ể Ể */ + 0x1ec5, 499, /* ễ Ễ */ + 0x1ec7, 499, /* ệ Ệ */ + 0x1ec9, 499, /* ỉ Ỉ */ + 0x1ecb, 499, /* ị Ị */ + 0x1ecd, 499, /* ọ Ọ */ + 0x1ecf, 499, /* ỏ Ỏ */ + 0x1ed1, 499, /* ố Ố */ + 0x1ed3, 499, /* ồ Ồ */ + 0x1ed5, 499, /* ổ Ổ */ + 0x1ed7, 499, /* ỗ Ỗ */ + 0x1ed9, 499, /* ộ Ộ */ + 0x1edb, 499, /* ớ Ớ */ + 0x1edd, 499, /* ờ Ờ */ + 0x1edf, 499, /* ở Ở */ + 0x1ee1, 499, /* ỡ Ỡ */ + 0x1ee3, 499, /* ợ Ợ */ + 0x1ee5, 499, /* ụ Ụ */ + 0x1ee7, 499, /* ủ Ủ */ + 0x1ee9, 499, /* ứ Ứ */ + 0x1eeb, 499, /* ừ Ừ */ + 0x1eed, 499, /* ử Ử */ + 0x1eef, 499, /* ữ Ữ */ + 0x1ef1, 499, /* ự Ự */ + 0x1ef3, 499, /* ỳ Ỳ */ + 0x1ef5, 499, /* ỵ Ỵ */ + 0x1ef7, 499, /* ỷ Ỷ */ + 0x1ef9, 499, /* ỹ Ỹ */ + 0x1f51, 508, /* ὑ Ὑ */ + 0x1f53, 508, /* ὓ Ὓ */ + 0x1f55, 508, /* ὕ Ὕ */ + 0x1f57, 508, /* ὗ Ὗ */ + 0x1fb3, 509, /* ᾳ ᾼ */ + 0x1fc3, 509, /* ῃ ῌ */ + 0x1fe5, 507, /* ῥ Ῥ */ + 0x1ff3, 509, /* ῳ ῼ */ +}; + +static Rune __isdigitr[] = { + 0x0030, 0x0039, + 0x0660, 0x0669, + 0x06f0, 0x06f9, + 0x07c0, 0x07c9, + 0x0966, 0x096f, + 0x09e6, 0x09ef, + 0x0a66, 0x0a6f, + 0x0ae6, 0x0aef, + 0x0b66, 0x0b6f, + 0x0be6, 0x0bef, + 0x0c66, 0x0c6f, + 0x0ce6, 0x0cef, + 0x0d66, 0x0d6f, + 0x0e50, 0x0e59, + 0x0ed0, 0x0ed9, + 0x0f20, 0x0f29, + 0x1040, 0x1049, + 0x17e0, 0x17e9, + 0x1810, 0x1819, + 0x1946, 0x194f, + 0x19d0, 0x19d9, + 0x1b50, 0x1b59, + 0xff10, 0xff19, + 0x104a0, 0x104a9, + 0x1d7ce, 0x1d7ff, +}; + +/* + * upper case ranges + * 3rd col is conversion excess 500 + */ +static +Rune _tolower2[] = +{ + 0x0041, 0x005a, 532, /* A-Z a-z */ + 0x00c0, 0x00d6, 532, /* À-Ö à-ö */ + 0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */ + 0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */ + 0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */ + 0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */ + 0x0388, 0x038a, 537, /* Έ-Ί έ-ί */ + 0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */ + 0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */ + 0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */ + 0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */ + 0x040e, 0x040f, 580, /* Ў-Џ ў-џ */ + 0x0410, 0x042f, 532, /* А-Я а-я */ + 0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */ + 0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */ + 0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */ + 0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */ + 0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */ + 0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */ + 0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */ + 0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */ + 0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */ + 0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */ + 0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */ + 0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */ + 0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */ + 0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */ + 0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */ + 0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */ + 0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */ + 0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */ + 0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */ + 0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */ + 0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */ + 0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */ + 0xff21, 0xff3a, 532, /* A-Z a-z */ +}; + +/* + * upper case singlets + * 2nd col is conversion excess 500 + */ +static +Rune _tolower1[] = +{ + 0x0100, 501, /* Ā ā */ + 0x0102, 501, /* Ă ă */ + 0x0104, 501, /* Ą ą */ + 0x0106, 501, /* Ć ć */ + 0x0108, 501, /* Ĉ ĉ */ + 0x010a, 501, /* Ċ ċ */ + 0x010c, 501, /* Č č */ + 0x010e, 501, /* Ď ď */ + 0x0110, 501, /* Đ đ */ + 0x0112, 501, /* Ē ē */ + 0x0114, 501, /* Ĕ ĕ */ + 0x0116, 501, /* Ė ė */ + 0x0118, 501, /* Ę ę */ + 0x011a, 501, /* Ě ě */ + 0x011c, 501, /* Ĝ ĝ */ + 0x011e, 501, /* Ğ ğ */ + 0x0120, 501, /* Ġ ġ */ + 0x0122, 501, /* Ģ ģ */ + 0x0124, 501, /* Ĥ ĥ */ + 0x0126, 501, /* Ħ ħ */ + 0x0128, 501, /* Ĩ ĩ */ + 0x012a, 501, /* Ī ī */ + 0x012c, 501, /* Ĭ ĭ */ + 0x012e, 501, /* Į į */ + 0x0130, 301, /* İ i */ + 0x0132, 501, /* IJ ij */ + 0x0134, 501, /* Ĵ ĵ */ + 0x0136, 501, /* Ķ ķ */ + 0x0139, 501, /* Ĺ ĺ */ + 0x013b, 501, /* Ļ ļ */ + 0x013d, 501, /* Ľ ľ */ + 0x013f, 501, /* Ŀ ŀ */ + 0x0141, 501, /* Ł ł */ + 0x0143, 501, /* Ń ń */ + 0x0145, 501, /* Ņ ņ */ + 0x0147, 501, /* Ň ň */ + 0x014a, 501, /* Ŋ ŋ */ + 0x014c, 501, /* Ō ō */ + 0x014e, 501, /* Ŏ ŏ */ + 0x0150, 501, /* Ő ő */ + 0x0152, 501, /* Œ œ */ + 0x0154, 501, /* Ŕ ŕ */ + 0x0156, 501, /* Ŗ ŗ */ + 0x0158, 501, /* Ř ř */ + 0x015a, 501, /* Ś ś */ + 0x015c, 501, /* Ŝ ŝ */ + 0x015e, 501, /* Ş ş */ + 0x0160, 501, /* Š š */ + 0x0162, 501, /* Ţ ţ */ + 0x0164, 501, /* Ť ť */ + 0x0166, 501, /* Ŧ ŧ */ + 0x0168, 501, /* Ũ ũ */ + 0x016a, 501, /* Ū ū */ + 0x016c, 501, /* Ŭ ŭ */ + 0x016e, 501, /* Ů ů */ + 0x0170, 501, /* Ű ű */ + 0x0172, 501, /* Ų ų */ + 0x0174, 501, /* Ŵ ŵ */ + 0x0176, 501, /* Ŷ ŷ */ + 0x0178, 379, /* Ÿ ÿ */ + 0x0179, 501, /* Ź ź */ + 0x017b, 501, /* Ż ż */ + 0x017d, 501, /* Ž ž */ + 0x0181, 710, /* Ɓ ɓ */ + 0x0182, 501, /* Ƃ ƃ */ + 0x0184, 501, /* Ƅ ƅ */ + 0x0186, 706, /* Ɔ ɔ */ + 0x0187, 501, /* Ƈ ƈ */ + 0x018b, 501, /* Ƌ ƌ */ + 0x0190, 703, /* Ɛ ɛ */ + 0x0191, 501, /* Ƒ ƒ */ + 0x0193, 705, /* Ɠ ɠ */ + 0x0194, 707, /* Ɣ ɣ */ + 0x0196, 711, /* Ɩ ɩ */ + 0x0197, 709, /* Ɨ ɨ */ + 0x0198, 501, /* Ƙ ƙ */ + 0x019c, 711, /* Ɯ ɯ */ + 0x019d, 713, /* Ɲ ɲ */ + 0x01a0, 501, /* Ơ ơ */ + 0x01a2, 501, /* Ƣ ƣ */ + 0x01a4, 501, /* Ƥ ƥ */ + 0x01a7, 501, /* Ƨ ƨ */ + 0x01a9, 718, /* Ʃ ʃ */ + 0x01ac, 501, /* Ƭ ƭ */ + 0x01ae, 718, /* Ʈ ʈ */ + 0x01af, 501, /* Ư ư */ + 0x01b3, 501, /* Ƴ ƴ */ + 0x01b5, 501, /* Ƶ ƶ */ + 0x01b7, 719, /* Ʒ ʒ */ + 0x01b8, 501, /* Ƹ ƹ */ + 0x01bc, 501, /* Ƽ ƽ */ + 0x01c4, 502, /* DŽ dž */ + 0x01c5, 501, /* Dž dž */ + 0x01c7, 502, /* LJ lj */ + 0x01c8, 501, /* Lj lj */ + 0x01ca, 502, /* NJ nj */ + 0x01cb, 501, /* Nj nj */ + 0x01cd, 501, /* Ǎ ǎ */ + 0x01cf, 501, /* Ǐ ǐ */ + 0x01d1, 501, /* Ǒ ǒ */ + 0x01d3, 501, /* Ǔ ǔ */ + 0x01d5, 501, /* Ǖ ǖ */ + 0x01d7, 501, /* Ǘ ǘ */ + 0x01d9, 501, /* Ǚ ǚ */ + 0x01db, 501, /* Ǜ ǜ */ + 0x01de, 501, /* Ǟ ǟ */ + 0x01e0, 501, /* Ǡ ǡ */ + 0x01e2, 501, /* Ǣ ǣ */ + 0x01e4, 501, /* Ǥ ǥ */ + 0x01e6, 501, /* Ǧ ǧ */ + 0x01e8, 501, /* Ǩ ǩ */ + 0x01ea, 501, /* Ǫ ǫ */ + 0x01ec, 501, /* Ǭ ǭ */ + 0x01ee, 501, /* Ǯ ǯ */ + 0x01f1, 502, /* DZ dz */ + 0x01f2, 501, /* Dz dz */ + 0x01f4, 501, /* Ǵ ǵ */ + 0x01fa, 501, /* Ǻ ǻ */ + 0x01fc, 501, /* Ǽ ǽ */ + 0x01fe, 501, /* Ǿ ǿ */ + 0x0200, 501, /* Ȁ ȁ */ + 0x0202, 501, /* Ȃ ȃ */ + 0x0204, 501, /* Ȅ ȅ */ + 0x0206, 501, /* Ȇ ȇ */ + 0x0208, 501, /* Ȉ ȉ */ + 0x020a, 501, /* Ȋ ȋ */ + 0x020c, 501, /* Ȍ ȍ */ + 0x020e, 501, /* Ȏ ȏ */ + 0x0210, 501, /* Ȑ ȑ */ + 0x0212, 501, /* Ȓ ȓ */ + 0x0214, 501, /* Ȕ ȕ */ + 0x0216, 501, /* Ȗ ȗ */ + 0x0386, 538, /* Ά ά */ + 0x038c, 564, /* Ό ό */ + 0x03e2, 501, /* Ϣ ϣ */ + 0x03e4, 501, /* Ϥ ϥ */ + 0x03e6, 501, /* Ϧ ϧ */ + 0x03e8, 501, /* Ϩ ϩ */ + 0x03ea, 501, /* Ϫ ϫ */ + 0x03ec, 501, /* Ϭ ϭ */ + 0x03ee, 501, /* Ϯ ϯ */ + 0x0460, 501, /* Ѡ ѡ */ + 0x0462, 501, /* Ѣ ѣ */ + 0x0464, 501, /* Ѥ ѥ */ + 0x0466, 501, /* Ѧ ѧ */ + 0x0468, 501, /* Ѩ ѩ */ + 0x046a, 501, /* Ѫ ѫ */ + 0x046c, 501, /* Ѭ ѭ */ + 0x046e, 501, /* Ѯ ѯ */ + 0x0470, 501, /* Ѱ ѱ */ + 0x0472, 501, /* Ѳ ѳ */ + 0x0474, 501, /* Ѵ ѵ */ + 0x0476, 501, /* Ѷ ѷ */ + 0x0478, 501, /* Ѹ ѹ */ + 0x047a, 501, /* Ѻ ѻ */ + 0x047c, 501, /* Ѽ ѽ */ + 0x047e, 501, /* Ѿ ѿ */ + 0x0480, 501, /* Ҁ ҁ */ + 0x0490, 501, /* Ґ ґ */ + 0x0492, 501, /* Ғ ғ */ + 0x0494, 501, /* Ҕ ҕ */ + 0x0496, 501, /* Җ җ */ + 0x0498, 501, /* Ҙ ҙ */ + 0x049a, 501, /* Қ қ */ + 0x049c, 501, /* Ҝ ҝ */ + 0x049e, 501, /* Ҟ ҟ */ + 0x04a0, 501, /* Ҡ ҡ */ + 0x04a2, 501, /* Ң ң */ + 0x04a4, 501, /* Ҥ ҥ */ + 0x04a6, 501, /* Ҧ ҧ */ + 0x04a8, 501, /* Ҩ ҩ */ + 0x04aa, 501, /* Ҫ ҫ */ + 0x04ac, 501, /* Ҭ ҭ */ + 0x04ae, 501, /* Ү ү */ + 0x04b0, 501, /* Ұ ұ */ + 0x04b2, 501, /* Ҳ ҳ */ + 0x04b4, 501, /* Ҵ ҵ */ + 0x04b6, 501, /* Ҷ ҷ */ + 0x04b8, 501, /* Ҹ ҹ */ + 0x04ba, 501, /* Һ һ */ + 0x04bc, 501, /* Ҽ ҽ */ + 0x04be, 501, /* Ҿ ҿ */ + 0x04c1, 501, /* Ӂ ӂ */ + 0x04c3, 501, /* Ӄ ӄ */ + 0x04c7, 501, /* Ӈ ӈ */ + 0x04cb, 501, /* Ӌ ӌ */ + 0x04d0, 501, /* Ӑ ӑ */ + 0x04d2, 501, /* Ӓ ӓ */ + 0x04d4, 501, /* Ӕ ӕ */ + 0x04d6, 501, /* Ӗ ӗ */ + 0x04d8, 501, /* Ә ә */ + 0x04da, 501, /* Ӛ ӛ */ + 0x04dc, 501, /* Ӝ ӝ */ + 0x04de, 501, /* Ӟ ӟ */ + 0x04e0, 501, /* Ӡ ӡ */ + 0x04e2, 501, /* Ӣ ӣ */ + 0x04e4, 501, /* Ӥ ӥ */ + 0x04e6, 501, /* Ӧ ӧ */ + 0x04e8, 501, /* Ө ө */ + 0x04ea, 501, /* Ӫ ӫ */ + 0x04ee, 501, /* Ӯ ӯ */ + 0x04f0, 501, /* Ӱ ӱ */ + 0x04f2, 501, /* Ӳ ӳ */ + 0x04f4, 501, /* Ӵ ӵ */ + 0x04f8, 501, /* Ӹ ӹ */ + 0x1e00, 501, /* Ḁ ḁ */ + 0x1e02, 501, /* Ḃ ḃ */ + 0x1e04, 501, /* Ḅ ḅ */ + 0x1e06, 501, /* Ḇ ḇ */ + 0x1e08, 501, /* Ḉ ḉ */ + 0x1e0a, 501, /* Ḋ ḋ */ + 0x1e0c, 501, /* Ḍ ḍ */ + 0x1e0e, 501, /* Ḏ ḏ */ + 0x1e10, 501, /* Ḑ ḑ */ + 0x1e12, 501, /* Ḓ ḓ */ + 0x1e14, 501, /* Ḕ ḕ */ + 0x1e16, 501, /* Ḗ ḗ */ + 0x1e18, 501, /* Ḙ ḙ */ + 0x1e1a, 501, /* Ḛ ḛ */ + 0x1e1c, 501, /* Ḝ ḝ */ + 0x1e1e, 501, /* Ḟ ḟ */ + 0x1e20, 501, /* Ḡ ḡ */ + 0x1e22, 501, /* Ḣ ḣ */ + 0x1e24, 501, /* Ḥ ḥ */ + 0x1e26, 501, /* Ḧ ḧ */ + 0x1e28, 501, /* Ḩ ḩ */ + 0x1e2a, 501, /* Ḫ ḫ */ + 0x1e2c, 501, /* Ḭ ḭ */ + 0x1e2e, 501, /* Ḯ ḯ */ + 0x1e30, 501, /* Ḱ ḱ */ + 0x1e32, 501, /* Ḳ ḳ */ + 0x1e34, 501, /* Ḵ ḵ */ + 0x1e36, 501, /* Ḷ ḷ */ + 0x1e38, 501, /* Ḹ ḹ */ + 0x1e3a, 501, /* Ḻ ḻ */ + 0x1e3c, 501, /* Ḽ ḽ */ + 0x1e3e, 501, /* Ḿ ḿ */ + 0x1e40, 501, /* Ṁ ṁ */ + 0x1e42, 501, /* Ṃ ṃ */ + 0x1e44, 501, /* Ṅ ṅ */ + 0x1e46, 501, /* Ṇ ṇ */ + 0x1e48, 501, /* Ṉ ṉ */ + 0x1e4a, 501, /* Ṋ ṋ */ + 0x1e4c, 501, /* Ṍ ṍ */ + 0x1e4e, 501, /* Ṏ ṏ */ + 0x1e50, 501, /* Ṑ ṑ */ + 0x1e52, 501, /* Ṓ ṓ */ + 0x1e54, 501, /* Ṕ ṕ */ + 0x1e56, 501, /* Ṗ ṗ */ + 0x1e58, 501, /* Ṙ ṙ */ + 0x1e5a, 501, /* Ṛ ṛ */ + 0x1e5c, 501, /* Ṝ ṝ */ + 0x1e5e, 501, /* Ṟ ṟ */ + 0x1e60, 501, /* Ṡ ṡ */ + 0x1e62, 501, /* Ṣ ṣ */ + 0x1e64, 501, /* Ṥ ṥ */ + 0x1e66, 501, /* Ṧ ṧ */ + 0x1e68, 501, /* Ṩ ṩ */ + 0x1e6a, 501, /* Ṫ ṫ */ + 0x1e6c, 501, /* Ṭ ṭ */ + 0x1e6e, 501, /* Ṯ ṯ */ + 0x1e70, 501, /* Ṱ ṱ */ + 0x1e72, 501, /* Ṳ ṳ */ + 0x1e74, 501, /* Ṵ ṵ */ + 0x1e76, 501, /* Ṷ ṷ */ + 0x1e78, 501, /* Ṹ ṹ */ + 0x1e7a, 501, /* Ṻ ṻ */ + 0x1e7c, 501, /* Ṽ ṽ */ + 0x1e7e, 501, /* Ṿ ṿ */ + 0x1e80, 501, /* Ẁ ẁ */ + 0x1e82, 501, /* Ẃ ẃ */ + 0x1e84, 501, /* Ẅ ẅ */ + 0x1e86, 501, /* Ẇ ẇ */ + 0x1e88, 501, /* Ẉ ẉ */ + 0x1e8a, 501, /* Ẋ ẋ */ + 0x1e8c, 501, /* Ẍ ẍ */ + 0x1e8e, 501, /* Ẏ ẏ */ + 0x1e90, 501, /* Ẑ ẑ */ + 0x1e92, 501, /* Ẓ ẓ */ + 0x1e94, 501, /* Ẕ ẕ */ + 0x1ea0, 501, /* Ạ ạ */ + 0x1ea2, 501, /* Ả ả */ + 0x1ea4, 501, /* Ấ ấ */ + 0x1ea6, 501, /* Ầ ầ */ + 0x1ea8, 501, /* Ẩ ẩ */ + 0x1eaa, 501, /* Ẫ ẫ */ + 0x1eac, 501, /* Ậ ậ */ + 0x1eae, 501, /* Ắ ắ */ + 0x1eb0, 501, /* Ằ ằ */ + 0x1eb2, 501, /* Ẳ ẳ */ + 0x1eb4, 501, /* Ẵ ẵ */ + 0x1eb6, 501, /* Ặ ặ */ + 0x1eb8, 501, /* Ẹ ẹ */ + 0x1eba, 501, /* Ẻ ẻ */ + 0x1ebc, 501, /* Ẽ ẽ */ + 0x1ebe, 501, /* Ế ế */ + 0x1ec0, 501, /* Ề ề */ + 0x1ec2, 501, /* Ể ể */ + 0x1ec4, 501, /* Ễ ễ */ + 0x1ec6, 501, /* Ệ ệ */ + 0x1ec8, 501, /* Ỉ ỉ */ + 0x1eca, 501, /* Ị ị */ + 0x1ecc, 501, /* Ọ ọ */ + 0x1ece, 501, /* Ỏ ỏ */ + 0x1ed0, 501, /* Ố ố */ + 0x1ed2, 501, /* Ồ ồ */ + 0x1ed4, 501, /* Ổ ổ */ + 0x1ed6, 501, /* Ỗ ỗ */ + 0x1ed8, 501, /* Ộ ộ */ + 0x1eda, 501, /* Ớ ớ */ + 0x1edc, 501, /* Ờ ờ */ + 0x1ede, 501, /* Ở ở */ + 0x1ee0, 501, /* Ỡ ỡ */ + 0x1ee2, 501, /* Ợ ợ */ + 0x1ee4, 501, /* Ụ ụ */ + 0x1ee6, 501, /* Ủ ủ */ + 0x1ee8, 501, /* Ứ ứ */ + 0x1eea, 501, /* Ừ ừ */ + 0x1eec, 501, /* Ử ử */ + 0x1eee, 501, /* Ữ ữ */ + 0x1ef0, 501, /* Ự ự */ + 0x1ef2, 501, /* Ỳ ỳ */ + 0x1ef4, 501, /* Ỵ ỵ */ + 0x1ef6, 501, /* Ỷ ỷ */ + 0x1ef8, 501, /* Ỹ ỹ */ + 0x1f59, 492, /* Ὑ ὑ */ + 0x1f5b, 492, /* Ὓ ὓ */ + 0x1f5d, 492, /* Ὕ ὕ */ + 0x1f5f, 492, /* Ὗ ὗ */ + 0x1fbc, 491, /* ᾼ ᾳ */ + 0x1fcc, 491, /* ῌ ῃ */ + 0x1fec, 493, /* Ῥ ῥ */ + 0x1ffc, 491, /* ῼ ῳ */ +}; + +/* + * title characters are those between + * upper and lower case. ie DZ Dz dz + */ +static +Rune _totitle1[] = +{ + 0x01c4, 501, /* DŽ Dž */ + 0x01c6, 499, /* dž Dž */ + 0x01c7, 501, /* LJ Lj */ + 0x01c9, 499, /* lj Lj */ + 0x01ca, 501, /* NJ Nj */ + 0x01cc, 499, /* nj Nj */ + 0x01f1, 501, /* DZ Dz */ + 0x01f3, 499, /* dz Dz */ +}; + +static +Rune* +bsearch(Rune c, Rune *t, int n, int ne) +{ + Rune *p; + int m; + + while(n > 1) { + m = n/2; + p = t + m*ne; + if(c >= p[0]) { + t = p; + n = n-m; + } else + n = m; + } + if(n && c >= t[0]) + return t; + return 0; +} + +Rune +tolowerrune(Rune c) +{ + Rune *p; + + p = bsearch(c, _tolower2, nelem(_tolower2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 500; + p = bsearch(c, _tolower1, nelem(_tolower1)/2, 2); + if(p && c == p[0]) + return c + p[1] - 500; + return c; +} + +Rune +toupperrune(Rune c) +{ + Rune *p; + + p = bsearch(c, _toupper2, nelem(_toupper2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 500; + p = bsearch(c, _toupper1, nelem(_toupper1)/2, 2); + if(p && c == p[0]) + return c + p[1] - 500; + return c; +} + +Rune +totitlerune(Rune c) +{ + Rune *p; + + p = bsearch(c, _totitle1, nelem(_totitle1)/2, 2); + if(p && c == p[0]) + return c + p[1] - 500; + return c; +} + +int +islowerrune(Rune c) +{ + Rune *p; + + p = bsearch(c, _toupper2, nelem(_toupper2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = bsearch(c, _toupper1, nelem(_toupper1)/2, 2); + if(p && c == p[0]) + return 1; + return 0; +} + +int +isupperrune(Rune c) +{ + Rune *p; + + p = bsearch(c, _tolower2, nelem(_tolower2)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = bsearch(c, _tolower1, nelem(_tolower1)/2, 2); + if(p && c == p[0]) + return 1; + return 0; +} + +int +isalpharune(Rune c) +{ + Rune *p; + + if(isupperrune(c) || islowerrune(c)) + return 1; + p = bsearch(c, _alpha2, nelem(_alpha2)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = bsearch(c, _alpha1, nelem(_alpha1), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +int +istitlerune(Rune c) +{ + return isupperrune(c) && islowerrune(c); +} + +int +isspacerune(Rune c) +{ + Rune *p; + + p = bsearch(c, _space2, nelem(_space2)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + return 0; +} + +int +isdigitrune(Rune c) +{ + Rune *p; + + p = bsearch(c, __isdigitr, nelem(__isdigitr)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + return 0; +} diff --git a/sys/src/libc/port/sin.c b/sys/src/libc/port/sin.c new file mode 100755 index 000000000..7072dd406 --- /dev/null +++ b/sys/src/libc/port/sin.c @@ -0,0 +1,68 @@ +/* + C program for floating point sin/cos. + Calls modf. + There are no error exits. + Coefficients are #3370 from Hart & Cheney (18.80D). +*/ + +#include <u.h> +#include <libc.h> + +#define p0 .1357884097877375669092680e8 +#define p1 -.4942908100902844161158627e7 +#define p2 .4401030535375266501944918e6 +#define p3 -.1384727249982452873054457e5 +#define p4 .1459688406665768722226959e3 +#define q0 .8644558652922534429915149e7 +#define q1 .4081792252343299749395779e6 +#define q2 .9463096101538208180571257e4 +#define q3 .1326534908786136358911494e3 + +static +double +sinus(double arg, int quad) +{ + double e, f, ysq, x, y, temp1, temp2; + int k; + + x = arg; + if(x < 0) { + x = -x; + quad += 2; + } + x *= 1/PIO2; /* underflow? */ + if(x > 32764) { + y = modf(x, &e); + e += quad; + modf(0.25*e, &f); + quad = e - 4*f; + } else { + k = x; + y = x - k; + quad += k; + quad &= 3; + } + if(quad & 1) + y = 1-y; + if(quad > 1) + y = -y; + + ysq = y*y; + temp1 = ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y; + temp2 = ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0); + return temp1/temp2; +} + +double +cos(double arg) +{ + if(arg < 0) + arg = -arg; + return sinus(arg, 1); +} + +double +sin(double arg) +{ + return sinus(arg, 0); +} diff --git a/sys/src/libc/port/sinh.c b/sys/src/libc/port/sinh.c new file mode 100755 index 000000000..115d42c0e --- /dev/null +++ b/sys/src/libc/port/sinh.c @@ -0,0 +1,62 @@ +#include <u.h> +#include <libc.h> + +/* + * sinh(arg) returns the hyperbolic sine of its floating- + * point argument. + * + * The exponential function is called for arguments + * greater in magnitude than 0.5. + * + * A series is used for arguments smaller in magnitude than 0.5. + * The coefficients are #2029 from Hart & Cheney. (20.36D) + * + * cosh(arg) is computed from the exponential function for + * all arguments. + */ + +static double p0 = -0.6307673640497716991184787251e+6; +static double p1 = -0.8991272022039509355398013511e+5; +static double p2 = -0.2894211355989563807284660366e+4; +static double p3 = -0.2630563213397497062819489e+2; +static double q0 = -0.6307673640497716991212077277e+6; +static double q1 = 0.1521517378790019070696485176e+5; +static double q2 = -0.173678953558233699533450911e+3; + +double +sinh(double arg) +{ + double temp, argsq; + int sign; + + sign = 0; + if(arg < 0) { + arg = -arg; + sign++; + } + if(arg > 21) { + temp = exp(arg)/2; + goto out; + } + if(arg > 0.5) { + temp = (exp(arg) - exp(-arg))/2; + goto out; + } + argsq = arg*arg; + temp = (((p3*argsq+p2)*argsq+p1)*argsq+p0)*arg; + temp /= (((argsq+q2)*argsq+q1)*argsq+q0); +out: + if(sign) + temp = -temp; + return temp; +} + +double +cosh(double arg) +{ + if(arg < 0) + arg = - arg; + if(arg > 21) + return exp(arg)/2; + return (exp(arg) + exp(-arg))/2; +} diff --git a/sys/src/libc/port/sqrt.c b/sys/src/libc/port/sqrt.c new file mode 100755 index 000000000..a92efac88 --- /dev/null +++ b/sys/src/libc/port/sqrt.c @@ -0,0 +1,54 @@ +/* + sqrt returns the square root of its floating + point argument. Newton's method. + + calls frexp +*/ + +#include <u.h> +#include <libc.h> + +double +sqrt(double arg) +{ + double x, temp; + int exp, i; + + if(arg <= 0) { + if(arg < 0) + return NaN(); + return 0; + } + if(isInf(arg, 1)) + return arg; + x = frexp(arg, &exp); + while(x < 0.5) { + x *= 2; + exp--; + } + /* + * NOTE + * this wont work on 1's comp + */ + if(exp & 1) { + x *= 2; + exp--; + } + temp = 0.5 * (1.0+x); + + while(exp > 60) { + temp *= (1L<<30); + exp -= 60; + } + while(exp < -60) { + temp /= (1L<<30); + exp += 60; + } + if(exp >= 0) + temp *= 1L << (exp/2); + else + temp /= 1L << (-exp/2); + for(i=0; i<=4; i++) + temp = 0.5*(temp + arg/temp); + return temp; +} diff --git a/sys/src/libc/port/strcat.c b/sys/src/libc/port/strcat.c new file mode 100755 index 000000000..137dc8195 --- /dev/null +++ b/sys/src/libc/port/strcat.c @@ -0,0 +1,10 @@ +#include <u.h> +#include <libc.h> + +char* +strcat(char *s1, char *s2) +{ + + strcpy(strchr(s1, 0), s2); + return s1; +} diff --git a/sys/src/libc/port/strchr.c b/sys/src/libc/port/strchr.c new file mode 100755 index 000000000..1e9aab597 --- /dev/null +++ b/sys/src/libc/port/strchr.c @@ -0,0 +1,20 @@ +#include <u.h> +#include <libc.h> + +char* +strchr(char *s, int c) +{ + char c0 = c; + char c1; + + if(c == 0) { + while(*s++) + ; + return s-1; + } + + while(c1 = *s++) + if(c1 == c0) + return s-1; + return 0; +} diff --git a/sys/src/libc/port/strcmp.c b/sys/src/libc/port/strcmp.c new file mode 100755 index 000000000..9d0c0b398 --- /dev/null +++ b/sys/src/libc/port/strcmp.c @@ -0,0 +1,20 @@ +#include <u.h> +#include <libc.h> + +int +strcmp(char *s1, char *s2) +{ + unsigned c1, c2; + + for(;;) { + c1 = *s1++; + c2 = *s2++; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + return 0; + } +} diff --git a/sys/src/libc/port/strcpy.c b/sys/src/libc/port/strcpy.c new file mode 100755 index 000000000..233a9c1b0 --- /dev/null +++ b/sys/src/libc/port/strcpy.c @@ -0,0 +1,16 @@ +#include <u.h> +#include <libc.h> +#define N 10000 + +char* +strcpy(char *s1, char *s2) +{ + char *os1; + + os1 = s1; + while(!memccpy(s1, s2, 0, N)) { + s1 += N; + s2 += N; + } + return os1; +} diff --git a/sys/src/libc/port/strcspn.c b/sys/src/libc/port/strcspn.c new file mode 100755 index 000000000..8349af335 --- /dev/null +++ b/sys/src/libc/port/strcspn.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> + +#define N 256 + +long +strcspn(char *s, char *b) +{ + char map[N], *os; + + memset(map, 0, N); + for(;;) { + map[*(uchar*)b] = 1; + if(*b++ == 0) + break; + } + os = s; + while(map[*(uchar*)s++] == 0) + ; + return s - os - 1; +} diff --git a/sys/src/libc/port/strdup.c b/sys/src/libc/port/strdup.c new file mode 100755 index 000000000..3d5fe523f --- /dev/null +++ b/sys/src/libc/port/strdup.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +char* +strdup(char *s) +{ + char *ns; + + ns = malloc(strlen(s) + 1); + if(ns == 0) + return 0; + + return strcpy(ns, s); +} diff --git a/sys/src/libc/port/strecpy.c b/sys/src/libc/port/strecpy.c new file mode 100755 index 000000000..a44dffdd8 --- /dev/null +++ b/sys/src/libc/port/strecpy.c @@ -0,0 +1,17 @@ +#include <u.h> +#include <libc.h> + +char* +strecpy(char *to, char *e, char *from) +{ + if(to >= e) + return to; + to = memccpy(to, from, '\0', e - to); + if(to == nil){ + to = e - 1; + *to = '\0'; + }else{ + to--; + } + return to; +} diff --git a/sys/src/libc/port/strlen.c b/sys/src/libc/port/strlen.c new file mode 100755 index 000000000..9a3c372a5 --- /dev/null +++ b/sys/src/libc/port/strlen.c @@ -0,0 +1,9 @@ +#include <u.h> +#include <libc.h> + +long +strlen(char *s) +{ + + return strchr(s, 0) - s; +} diff --git a/sys/src/libc/port/strncat.c b/sys/src/libc/port/strncat.c new file mode 100755 index 000000000..9d793e42d --- /dev/null +++ b/sys/src/libc/port/strncat.c @@ -0,0 +1,19 @@ +#include <u.h> +#include <libc.h> + +char* +strncat(char *s1, char *s2, long n) +{ + char *os1; + + os1 = s1; + while(*s1++) + ; + s1--; + while(*s1++ = *s2++) + if(--n < 0) { + s1[-1] = 0; + break; + } + return os1; +} diff --git a/sys/src/libc/port/strncmp.c b/sys/src/libc/port/strncmp.c new file mode 100755 index 000000000..b61db6d5d --- /dev/null +++ b/sys/src/libc/port/strncmp.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> + +int +strncmp(char *s1, char *s2, long n) +{ + unsigned c1, c2; + + while(n > 0) { + c1 = *s1++; + c2 = *s2++; + n--; + if(c1 != c2) { + if(c1 > c2) + return 1; + return -1; + } + if(c1 == 0) + break; + } + return 0; +} diff --git a/sys/src/libc/port/strncpy.c b/sys/src/libc/port/strncpy.c new file mode 100755 index 000000000..bd5acdedb --- /dev/null +++ b/sys/src/libc/port/strncpy.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> + +char* +strncpy(char *s1, char *s2, long n) +{ + int i; + char *os1; + + os1 = s1; + for(i = 0; i < n; i++) + if((*s1++ = *s2++) == 0) { + while(++i < n) + *s1++ = 0; + return os1; + } + return os1; +} diff --git a/sys/src/libc/port/strpbrk.c b/sys/src/libc/port/strpbrk.c new file mode 100755 index 000000000..bbd91eafb --- /dev/null +++ b/sys/src/libc/port/strpbrk.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> +#define N 256 + +char* +strpbrk(char *cs, char *cb) +{ + char map[N]; + uchar *s=(uchar*)cs, *b=(uchar*)cb; + + memset(map, 0, N); + for(;;) { + map[*b] = 1; + if(*b++ == 0) + break; + } + while(map[*s++] == 0) + ; + if(*--s) + return (char*)s; + return 0; +} diff --git a/sys/src/libc/port/strrchr.c b/sys/src/libc/port/strrchr.c new file mode 100755 index 000000000..18fd38634 --- /dev/null +++ b/sys/src/libc/port/strrchr.c @@ -0,0 +1,15 @@ +#include <u.h> +#include <libc.h> + +char* +strrchr(char *s, int c) +{ + char *r; + + if(c == 0) + return strchr(s, 0); + r = 0; + while(s = strchr(s, c)) + r = s++; + return r; +} diff --git a/sys/src/libc/port/strspn.c b/sys/src/libc/port/strspn.c new file mode 100755 index 000000000..8744fd0ec --- /dev/null +++ b/sys/src/libc/port/strspn.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> + +#define N 256 + +long +strspn(char *s, char *b) +{ + char map[N], *os; + + memset(map, 0, N); + while(*b) + map[*(uchar *)b++] = 1; + os = s; + while(map[*(uchar *)s++]) + ; + return s - os - 1; +} diff --git a/sys/src/libc/port/strstr.c b/sys/src/libc/port/strstr.c new file mode 100755 index 000000000..4541ccd04 --- /dev/null +++ b/sys/src/libc/port/strstr.c @@ -0,0 +1,29 @@ +#include <u.h> +#include <libc.h> + +/* + * Return pointer to first occurrence of s2 in s1, + * 0 if none + */ +char* +strstr(char *s1, char *s2) +{ + char *p, *pa, *pb; + int c0, c; + + c0 = *s2; + if(c0 == 0) + return s1; + s2++; + for(p=strchr(s1, c0); p; p=strchr(p+1, c0)) { + pa = p; + for(pb=s2;; pb++) { + c = *pb; + if(c == 0) + return p; + if(c != *++pa) + break; + } + } + return 0; +} diff --git a/sys/src/libc/port/strtod.c b/sys/src/libc/port/strtod.c new file mode 100755 index 000000000..9ea252856 --- /dev/null +++ b/sys/src/libc/port/strtod.c @@ -0,0 +1,520 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +/* + * This routine will convert to arbitrary precision + * floating point entirely in multi-precision fixed. + * The answer is the closest floating point number to + * the given decimal number. Exactly half way are + * rounded ala ieee rules. + * Method is to scale input decimal between .500 and .999... + * with external power of 2, then binary search for the + * closest mantissa to this decimal number. + * Nmant is is the required precision. (53 for ieee dp) + * Nbits is the max number of bits/word. (must be <= 28) + * Prec is calculated - the number of words of fixed mantissa. + */ +enum +{ + Nbits = 28, // bits safely represented in a ulong + Nmant = 53, // bits of precision required + Bias = 1022, + Prec = (Nmant+Nbits+1)/Nbits, // words of Nbits each to represent mantissa + Sigbit = 1<<(Prec*Nbits-Nmant), // first significant bit of Prec-th word + Ndig = 1500, + One = (ulong)(1<<Nbits), + Half = (ulong)(One>>1), + Maxe = 310, + Fsign = 1<<0, // found - + Fesign = 1<<1, // found e- + Fdpoint = 1<<2, // found . + + S0 = 0, // _ _S0 +S1 #S2 .S3 + S1, // _+ #S2 .S3 + S2, // _+# #S2 .S4 eS5 + S3, // _+. #S4 + S4, // _+#.# #S4 eS5 + S5, // _+#.#e +S6 #S7 + S6, // _+#.#e+ #S7 + S7, // _+#.#e+# #S7 +}; + +static int xcmp(char*, char*); +static int fpcmp(char*, ulong*); +static void frnorm(ulong*); +static void divascii(char*, int*, int*, int*); +static void mulascii(char*, int*, int*, int*); +static void divby(char*, int*, int); + +typedef struct Tab Tab; +struct Tab +{ + int bp; + int siz; + char* cmp; +}; + +double +strtod(char *as, char **aas) +{ + int na, ona, ex, dp, bp, c, i, flag, state; + ulong low[Prec], hig[Prec], mid[Prec], num, den; + double d; + char *s, a[Ndig]; + + flag = 0; // Fsign, Fesign, Fdpoint + na = 0; // number of digits of a[] + dp = 0; // na of decimal point + ex = 0; // exonent + + state = S0; + for(s=as;; s++) { + c = *s; + if(c >= '0' && c <= '9') { + switch(state) { + case S0: + case S1: + case S2: + state = S2; + break; + case S3: + case S4: + state = S4; + break; + + case S5: + case S6: + case S7: + state = S7; + ex = ex*10 + (c-'0'); + continue; + } + if(na == 0 && c == '0') { + dp--; + continue; + } + if(na < Ndig-50) + a[na++] = c; + continue; + } + switch(c) { + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + if(state == S0) + continue; + break; + case '-': + if(state == S0) + flag |= Fsign; + else + flag |= Fesign; + case '+': + if(state == S0) + state = S1; + else + if(state == S5) + state = S6; + else + break; // syntax + continue; + case '.': + flag |= Fdpoint; + dp = na; + if(state == S0 || state == S1) { + state = S3; + continue; + } + if(state == S2) { + state = S4; + continue; + } + break; + case 'e': + case 'E': + if(state == S2 || state == S4) { + state = S5; + continue; + } + break; + } + break; + } + + /* + * clean up return char-pointer + */ + switch(state) { + case S0: + if(xcmp(s, "nan") == 0) { + if(aas != nil) + *aas = s+3; + goto retnan; + } + case S1: + if(xcmp(s, "infinity") == 0) { + if(aas != nil) + *aas = s+8; + goto retinf; + } + if(xcmp(s, "inf") == 0) { + if(aas != nil) + *aas = s+3; + goto retinf; + } + case S3: + if(aas != nil) + *aas = as; + goto ret0; // no digits found + case S6: + s--; // back over +- + case S5: + s--; // back over e + break; + } + if(aas != nil) + *aas = s; + + if(flag & Fdpoint) + while(na > 0 && a[na-1] == '0') + na--; + if(na == 0) + goto ret0; // zero + a[na] = 0; + if(!(flag & Fdpoint)) + dp = na; + if(flag & Fesign) + ex = -ex; + dp += ex; + if(dp < -Maxe-Nmant/3) /* actually -Nmant*log(2)/log(10), but Nmant/3 close enough */ + goto ret0; // underflow by exp + else + if(dp > +Maxe) + goto retinf; // overflow by exp + + /* + * normalize the decimal ascii number + * to range .[5-9][0-9]* e0 + */ + bp = 0; // binary exponent + while(dp > 0) + divascii(a, &na, &dp, &bp); + while(dp < 0 || a[0] < '5') + mulascii(a, &na, &dp, &bp); + a[na] = 0; + + /* + * very small numbers are represented using + * bp = -Bias+1. adjust accordingly. + */ + if(bp < -Bias+1){ + ona = na; + divby(a, &na, -bp-Bias+1); + if(na < ona){ + memmove(a+ona-na, a, na); + memset(a, '0', ona-na); + na = ona; + } + a[na] = 0; + bp = -Bias+1; + } + + /* close approx by naive conversion */ + num = 0; + den = 1; + for(i=0; i<9 && (c=a[i]); i++) { + num = num*10 + (c-'0'); + den *= 10; + } + low[0] = umuldiv(num, One, den); + hig[0] = umuldiv(num+1, One, den); + for(i=1; i<Prec; i++) { + low[i] = 0; + hig[i] = One-1; + } + + /* binary search for closest mantissa */ + for(;;) { + /* mid = (hig + low) / 2 */ + c = 0; + for(i=0; i<Prec; i++) { + mid[i] = hig[i] + low[i]; + if(c) + mid[i] += One; + c = mid[i] & 1; + mid[i] >>= 1; + } + frnorm(mid); + + /* compare */ + c = fpcmp(a, mid); + if(c > 0) { + c = 1; + for(i=0; i<Prec; i++) + if(low[i] != mid[i]) { + c = 0; + low[i] = mid[i]; + } + if(c) + break; // between mid and hig + continue; + } + if(c < 0) { + for(i=0; i<Prec; i++) + hig[i] = mid[i]; + continue; + } + + /* only hard part is if even/odd roundings wants to go up */ + c = mid[Prec-1] & (Sigbit-1); + if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0) + mid[Prec-1] -= c; + break; // exactly mid + } + + /* normal rounding applies */ + c = mid[Prec-1] & (Sigbit-1); + mid[Prec-1] -= c; + if(c >= Sigbit/2) { + mid[Prec-1] += Sigbit; + frnorm(mid); + } + d = 0; + for(i=0; i<Prec; i++) + d = d*One + mid[i]; + if(flag & Fsign) + d = -d; + d = ldexp(d, bp - Prec*Nbits); + return d; + +ret0: + return 0; + +retnan: + return NaN(); + +retinf: + if(flag & Fsign) + return Inf(-1); + return Inf(+1); +} + +static void +frnorm(ulong *f) +{ + int i, c; + + c = 0; + for(i=Prec-1; i>0; i--) { + f[i] += c; + c = f[i] >> Nbits; + f[i] &= One-1; + } + f[0] += c; +} + +static int +fpcmp(char *a, ulong* f) +{ + ulong tf[Prec]; + int i, d, c; + + for(i=0; i<Prec; i++) + tf[i] = f[i]; + + for(;;) { + /* tf *= 10 */ + for(i=0; i<Prec; i++) + tf[i] = tf[i]*10; + frnorm(tf); + d = (tf[0] >> Nbits) + '0'; + tf[0] &= One-1; + + /* compare next digit */ + c = *a; + if(c == 0) { + if('0' < d) + return -1; + if(tf[0] != 0) + goto cont; + for(i=1; i<Prec; i++) + if(tf[i] != 0) + goto cont; + return 0; + } + if(c > d) + return +1; + if(c < d) + return -1; + a++; + cont:; + } +} + +static void +_divby(char *a, int *na, int b) +{ + int n, c; + char *p; + + p = a; + n = 0; + while(n>>b == 0) { + c = *a++; + if(c == 0) { + while(n) { + c = n*10; + if(c>>b) + break; + n = c; + } + goto xx; + } + n = n*10 + c-'0'; + (*na)--; + } + for(;;) { + c = n>>b; + n -= c<<b; + *p++ = c + '0'; + c = *a++; + if(c == 0) + break; + n = n*10 + c-'0'; + } + (*na)++; +xx: + while(n) { + n = n*10; + c = n>>b; + n -= c<<b; + *p++ = c + '0'; + (*na)++; + } + *p = 0; +} + +static void +divby(char *a, int *na, int b) +{ + while(b > 9){ + _divby(a, na, 9); + a[*na] = 0; + b -= 9; + } + if(b > 0) + _divby(a, na, b); +} + +static Tab tab1[] = +{ + 1, 0, "", + 3, 1, "7", + 6, 2, "63", + 9, 3, "511", + 13, 4, "8191", + 16, 5, "65535", + 19, 6, "524287", + 23, 7, "8388607", + 26, 8, "67108863", + 27, 9, "134217727", +}; + +static void +divascii(char *a, int *na, int *dp, int *bp) +{ + int b, d; + Tab *t; + + d = *dp; + if(d >= nelem(tab1)) + d = nelem(tab1)-1; + t = tab1 + d; + b = t->bp; + if(memcmp(a, t->cmp, t->siz) > 0) + d--; + *dp -= d; + *bp += b; + divby(a, na, b); +} + +static void +mulby(char *a, char *p, char *q, int b) +{ + int n, c; + + n = 0; + *p = 0; + for(;;) { + q--; + if(q < a) + break; + c = *q - '0'; + c = (c<<b) + n; + n = c/10; + c -= n*10; + p--; + *p = c + '0'; + } + while(n) { + c = n; + n = c/10; + c -= n*10; + p--; + *p = c + '0'; + } +} + +static Tab tab2[] = +{ + 1, 1, "", // dp = 0-0 + 3, 3, "125", + 6, 5, "15625", + 9, 7, "1953125", + 13, 10, "1220703125", + 16, 12, "152587890625", + 19, 14, "19073486328125", + 23, 17, "11920928955078125", + 26, 19, "1490116119384765625", + 27, 19, "7450580596923828125", // dp 8-9 +}; + +static void +mulascii(char *a, int *na, int *dp, int *bp) +{ + char *p; + int d, b; + Tab *t; + + d = -*dp; + if(d >= nelem(tab2)) + d = nelem(tab2)-1; + t = tab2 + d; + b = t->bp; + if(memcmp(a, t->cmp, t->siz) < 0) + d--; + p = a + *na; + *bp -= b; + *dp += d; + *na += d; + mulby(a, p+d, p, b); +} + +static int +xcmp(char *a, char *b) +{ + int c1, c2; + + while(c1 = *b++) { + c2 = *a++; + if(isupper(c2)) + c2 = tolower(c2); + if(c1 != c2) + return 1; + } + return 0; +} diff --git a/sys/src/libc/port/strtok.c b/sys/src/libc/port/strtok.c new file mode 100755 index 000000000..cb8d5fdf5 --- /dev/null +++ b/sys/src/libc/port/strtok.c @@ -0,0 +1,30 @@ +#include <u.h> +#include <libc.h> + +#define N 256 + +char* +strtok(char *s, char *b) +{ + static char *under_rock; + char map[N], *os; + + memset(map, 0, N); + while(*b) + map[*(uchar*)b++] = 1; + if(s == 0) + s = under_rock; + while(map[*(uchar*)s++]) + ; + if(*--s == 0) + return 0; + os = s; + while(map[*(uchar*)s] == 0) + if(*s++ == 0) { + under_rock = s-1; + return os; + } + *s++ = 0; + under_rock = s; + return os; +} diff --git a/sys/src/libc/port/strtol.c b/sys/src/libc/port/strtol.c new file mode 100755 index 000000000..e512910a8 --- /dev/null +++ b/sys/src/libc/port/strtol.c @@ -0,0 +1,101 @@ +#include <u.h> +#include <libc.h> + +#define LONG_MAX 2147483647L +#define LONG_MIN -2147483648L + +long +strtol(char *nptr, char **endptr, int base) +{ + char *p; + long n, nn, m; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;; p++) { + switch(*p) { + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p=='-' || *p=='+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base==0) { + base = 10; + if(*p == '0') { + base = 8; + if(p[1]=='x' || p[1]=='X') { + p += 2; + base = 16; + } + } + } else + if(base==16 && *p=='0'){ + if(p[1]=='x' || p[1]=='X') + p += 2; + } else + if(base<0 || 36<base) + goto Return; + + /* + * Non-empty sequence of digits + */ + m = LONG_MAX/base; + for(;; p++,ndig++){ + c = *p; + v = base; + if('0'<=c && c<='9') + v = c - '0'; + else + if('a'<=c && c<='z') + v = c - 'a' + 10; + else + if('A'<=c && c<='Z') + v = c - 'A' + 10; + if(v >= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + +Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = p; + if(ovfl){ + if(neg) + return LONG_MIN; + return LONG_MAX; + } + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/strtoll.c b/sys/src/libc/port/strtoll.c new file mode 100755 index 000000000..444728ae5 --- /dev/null +++ b/sys/src/libc/port/strtoll.c @@ -0,0 +1,101 @@ +#include <u.h> +#include <libc.h> + +#define VLONG_MAX ~(1LL<<63) +#define VLONG_MIN (1LL<<63) + +vlong +strtoll(char *nptr, char **endptr, int base) +{ + char *p; + vlong n, nn, m; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;; p++) { + switch(*p) { + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p=='-' || *p=='+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base==0){ + base = 10; + if(*p == '0') { + base = 8; + if(p[1]=='x' || p[1]=='X') { + p += 2; + base = 16; + } + } + } else + if(base==16 && *p=='0') { + if(p[1]=='x' || p[1]=='X') + p += 2; + } else + if(base<0 || 36<base) + goto Return; + + /* + * Non-empty sequence of digits + */ + m = VLONG_MAX/base; + for(;; p++,ndig++) { + c = *p; + v = base; + if('0'<=c && c<='9') + v = c - '0'; + else + if('a'<=c && c<='z') + v = c - 'a' + 10; + else + if('A'<=c && c<='Z') + v = c - 'A' + 10; + if(v >= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + +Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = p; + if(ovfl){ + if(neg) + return VLONG_MIN; + return VLONG_MAX; + } + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/strtoul.c b/sys/src/libc/port/strtoul.c new file mode 100755 index 000000000..6a12fdd94 --- /dev/null +++ b/sys/src/libc/port/strtoul.c @@ -0,0 +1,97 @@ +#include <u.h> +#include <libc.h> + +#define ULONG_MAX 4294967295UL + +ulong +strtoul(char *nptr, char **endptr, int base) +{ + char *p; + ulong n, nn, m; + int c, ovfl, neg, v, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;;p++){ + switch(*p){ + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p=='-' || *p=='+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base==0){ + if(*p != '0') + base = 10; + else{ + base = 8; + if(p[1]=='x' || p[1]=='X') + base = 16; + } + } + if(base<2 || 36<base) + goto Return; + if(base==16 && *p=='0'){ + if(p[1]=='x' || p[1]=='X') + if(('0' <= p[2] && p[2] <= '9') + ||('a' <= p[2] && p[2] <= 'f') + ||('A' <= p[2] && p[2] <= 'F')) + p += 2; + } + /* + * Non-empty sequence of digits + */ + n = 0; + m = ULONG_MAX/base; + for(;; p++,ndig++){ + c = *p; + v = base; + if('0'<=c && c<='9') + v = c - '0'; + else if('a'<=c && c<='z') + v = c - 'a' + 10; + else if('A'<=c && c<='Z') + v = c - 'A' + 10; + if(v >= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + + Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = p; + if(ovfl) + return ULONG_MAX; + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/strtoull.c b/sys/src/libc/port/strtoull.c new file mode 100755 index 000000000..85ab7c5fc --- /dev/null +++ b/sys/src/libc/port/strtoull.c @@ -0,0 +1,97 @@ +#include <u.h> +#include <libc.h> + +#define UVLONG_MAX (1LL<<63) + +uvlong +strtoull(char *nptr, char **endptr, int base) +{ + char *p; + uvlong n, nn, m; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + for(;; p++) { + switch(*p) { + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + case '\v': + continue; + } + break; + } + + /* + * Sign + */ + if(*p == '-' || *p == '+') + if(*p++ == '-') + neg = 1; + + /* + * Base + */ + if(base == 0) { + base = 10; + if(*p == '0') { + base = 8; + if(p[1] == 'x' || p[1] == 'X'){ + p += 2; + base = 16; + } + } + } else + if(base == 16 && *p == '0') { + if(p[1] == 'x' || p[1] == 'X') + p += 2; + } else + if(base < 0 || 36 < base) + goto Return; + + /* + * Non-empty sequence of digits + */ + m = UVLONG_MAX/base; + for(;; p++,ndig++) { + c = *p; + v = base; + if('0' <= c && c <= '9') + v = c - '0'; + else + if('a' <= c && c <= 'z') + v = c - 'a' + 10; + else + if('A' <= c && c <= 'Z') + v = c - 'A' + 10; + if(v >= base) + break; + if(n > m) + ovfl = 1; + nn = n*base + v; + if(nn < n) + ovfl = 1; + n = nn; + } + +Return: + if(ndig == 0) + p = nptr; + if(endptr) + *endptr = p; + if(ovfl) + return UVLONG_MAX; + if(neg) + return -n; + return n; +} diff --git a/sys/src/libc/port/tan.c b/sys/src/libc/port/tan.c new file mode 100755 index 000000000..b562e282d --- /dev/null +++ b/sys/src/libc/port/tan.c @@ -0,0 +1,67 @@ +/* + floating point tangent + + A series is used after range reduction. + Coefficients are #4285 from Hart & Cheney. (19.74D) + */ + +#include <u.h> +#include <libc.h> + +static double p0 = -0.1306820264754825668269611177e+5; +static double p1 = 0.1055970901714953193602353981e+4; +static double p2 = -0.1550685653483266376941705728e+2; +static double p3 = 0.3422554387241003435328470489e-1; +static double p4 = 0.3386638642677172096076369e-4; +static double q0 = -0.1663895238947119001851464661e+5; +static double q1 = 0.4765751362916483698926655581e+4; +static double q2 = -0.1555033164031709966900124574e+3; + +double +tan(double arg) +{ + double temp, e, x, xsq; + int flag, sign, i; + + flag = 0; + sign = 0; + if(arg < 0){ + arg = -arg; + sign++; + } + arg = 2*arg/PIO2; /* overflow? */ + x = modf(arg, &e); + i = e; + switch(i%4) { + case 1: + x = 1 - x; + flag = 1; + break; + + case 2: + sign = !sign; + flag = 1; + break; + + case 3: + x = 1 - x; + sign = !sign; + break; + + case 0: + break; + } + + xsq = x*x; + temp = ((((p4*xsq+p3)*xsq+p2)*xsq+p1)*xsq+p0)*x; + temp = temp/(((xsq+q2)*xsq+q1)*xsq+q0); + + if(flag) { + if(temp == 0) + return NaN(); + temp = 1/temp; + } + if(sign) + temp = -temp; + return temp; +} diff --git a/sys/src/libc/port/tanh.c b/sys/src/libc/port/tanh.c new file mode 100755 index 000000000..32e3a35ac --- /dev/null +++ b/sys/src/libc/port/tanh.c @@ -0,0 +1,25 @@ +#include <u.h> +#include <libc.h> + +/* + tanh(arg) computes the hyperbolic tangent of its floating + point argument. + + sinh and cosh are called except for large arguments, which + would cause overflow improperly. + */ + +double +tanh(double arg) +{ + + if(arg < 0) { + arg = -arg; + if(arg > 21) + return -1; + return -sinh(arg)/cosh(arg); + } + if(arg > 21) + return 1; + return sinh(arg)/cosh(arg); +} diff --git a/sys/src/libc/port/tokenize.c b/sys/src/libc/port/tokenize.c new file mode 100755 index 000000000..de234d440 --- /dev/null +++ b/sys/src/libc/port/tokenize.c @@ -0,0 +1,107 @@ +#include <u.h> +#include <libc.h> + +static char qsep[] = " \t\r\n"; + +static char* +qtoken(char *s, char *sep) +{ + int quoting; + char *t; + + quoting = 0; + t = s; /* s is output string, t is input string */ + while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ + if(*t != '\''){ + *s++ = *t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t++; + *s++ = *t++; + } + if(*s != '\0'){ + *s = '\0'; + if(t == s) + t++; + } + return t; +} + +static char* +etoken(char *t, char *sep) +{ + int quoting; + + /* move to end of next token */ + quoting = 0; + while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){ + if(*t != '\''){ + t++; + continue; + } + /* *t is a quote */ + if(!quoting){ + quoting = 1; + t++; + continue; + } + /* quoting and we're on a quote */ + if(t[1] != '\''){ + /* end of quoted section; absorb closing quote */ + t++; + quoting = 0; + continue; + } + /* doubled quote; fold one quote into two */ + t += 2; + } + return t; +} + +int +gettokens(char *s, char **args, int maxargs, char *sep) +{ + int nargs; + + for(nargs=0; nargs<maxargs; nargs++){ + while(*s!='\0' && utfrune(sep, *s)!=nil) + *s++ = '\0'; + if(*s == '\0') + break; + args[nargs] = s; + s = etoken(s, sep); + } + + return nargs; +} + +int +tokenize(char *s, char **args, int maxargs) +{ + int nargs; + + for(nargs=0; nargs<maxargs; nargs++){ + while(*s!='\0' && utfrune(qsep, *s)!=nil) + s++; + if(*s == '\0') + break; + args[nargs] = s; + s = qtoken(s, qsep); + } + + return nargs; +} diff --git a/sys/src/libc/port/toupper.c b/sys/src/libc/port/toupper.c new file mode 100755 index 000000000..d5fcf7b19 --- /dev/null +++ b/sys/src/libc/port/toupper.c @@ -0,0 +1,19 @@ +#include <ctype.h> + +int +toupper(int c) +{ + + if(c < 'a' || c > 'z') + return c; + return _toupper(c); +} + +int +tolower(int c) +{ + + if(c < 'A' || c > 'Z') + return c; + return _tolower(c); +} diff --git a/sys/src/libc/port/u16.c b/sys/src/libc/port/u16.c new file mode 100755 index 000000000..4e1637120 --- /dev/null +++ b/sys/src/libc/port/u16.c @@ -0,0 +1,53 @@ +#include <u.h> +#include <libc.h> +static char t16e[] = "0123456789ABCDEF"; + +int +dec16(uchar *out, int lim, char *in, int n) +{ + int c, w = 0, i = 0; + uchar *start = out; + uchar *eout = out + lim; + + while(n-- > 0){ + c = *in++; + if('0' <= c && c <= '9') + c = c - '0'; + else if('a' <= c && c <= 'z') + c = c - 'a' + 10; + else if('A' <= c && c <= 'Z') + c = c - 'A' + 10; + else + continue; + w = (w<<4) + c; + i++; + if(i == 2){ + if(out + 1 > eout) + goto exhausted; + *out++ = w; + w = 0; + i = 0; + } + } +exhausted: + return out - start; +} + +int +enc16(char *out, int lim, uchar *in, int n) +{ + uint c; + char *eout = out + lim; + char *start = out; + + while(n-- > 0){ + c = *in++; + if(out + 2 >= eout) + goto exhausted; + *out++ = t16e[c>>4]; + *out++ = t16e[c&0xf]; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/sys/src/libc/port/u32.c b/sys/src/libc/port/u32.c new file mode 100755 index 000000000..7423984a2 --- /dev/null +++ b/sys/src/libc/port/u32.c @@ -0,0 +1,110 @@ +#include <u.h> +#include <libc.h> + +int +dec32(uchar *dest, int ndest, char *src, int nsrc) +{ + char *s, *tab; + uchar *start; + int i, u[8]; + + if(ndest+1 < (5*nsrc+7)/8) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=8){ + for(i=0; i<8; i++){ + s = strchr(tab,(int)src[i]); + u[i] = s ? s-tab : 0; + } + *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + *dest++ = ((0x7 & u[6])<<5) | u[7]; + src += 8; + nsrc -= 8; + } + if(nsrc > 0){ + if(nsrc == 1 || nsrc == 3 || nsrc == 6) + return -1; + for(i=0; i<nsrc; i++){ + s = strchr(tab,(int)src[i]); + u[i] = s ? s-tab : 0; + } + *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); + if(nsrc == 2) + goto out; + *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); + if(nsrc == 4) + goto out; + *dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1)); + if(nsrc == 5) + goto out; + *dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3)); + } +out: + return dest-start; +} + +int +enc32(char *dest, int ndest, uchar *src, int nsrc) +{ + char *tab, *start; + int j; + + if(ndest <= (8*nsrc+4)/5 ) + return -1; + start = dest; + tab = "23456789abcdefghijkmnpqrstuvwxyz"; + while(nsrc>=5){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5)); + *dest++ = tab[j]; + j = (0x1f & (src[4])); + *dest++ = tab[j]; + src += 5; + nsrc -= 5; + } + if(nsrc){ + j = (0x1f & (src[0]>>3)); + *dest++ = tab[j]; + j = (0x1c & (src[0]<<2)); + if(nsrc == 1) + goto out; + j |= (0x03 & (src[1]>>6)); + *dest++ = tab[j]; + j = (0x1f & (src[1]>>1)); + if(nsrc == 2) + goto out; + *dest++ = tab[j]; + j = (0x10 & (src[1]<<4)); + if(nsrc == 3) + goto out; + j |= (0x0f & (src[2]>>4)); + *dest++ = tab[j]; + j = (0x1e & (src[2]<<1)); + if(nsrc == 4) + goto out; + j |= (0x01 & (src[3]>>7)); + *dest++ = tab[j]; + j = (0x1f & (src[3]>>2)); + *dest++ = tab[j]; + j = (0x18 & (src[3]<<3)); +out: + *dest++ = tab[j]; + } + *dest = 0; + return dest-start; +} diff --git a/sys/src/libc/port/u64.c b/sys/src/libc/port/u64.c new file mode 100755 index 000000000..bf86c634c --- /dev/null +++ b/sys/src/libc/port/u64.c @@ -0,0 +1,127 @@ +#include <u.h> +#include <libc.h> + +enum { + INVAL= 255 +}; + +static uchar t64d[256] = { + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, + INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL +}; +static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +int +dec64(uchar *out, int lim, char *in, int n) +{ + ulong b24; + uchar *start = out; + uchar *e = out + lim; + int i, c; + + b24 = 0; + i = 0; + while(n-- > 0){ + + c = t64d[*(uchar*)in++]; + if(c == INVAL) + continue; + switch(i){ + case 0: + b24 = c<<18; + break; + case 1: + b24 |= c<<12; + break; + case 2: + b24 |= c<<6; + break; + case 3: + if(out + 3 > e) + goto exhausted; + + b24 |= c; + *out++ = b24>>16; + *out++ = b24>>8; + *out++ = b24; + i = -1; + break; + } + i++; + } + switch(i){ + case 2: + if(out + 1 > e) + goto exhausted; + *out++ = b24>>16; + break; + case 3: + if(out + 2 > e) + goto exhausted; + *out++ = b24>>16; + *out++ = b24>>8; + break; + } +exhausted: + return out - start; +} + +int +enc64(char *out, int lim, uchar *in, int n) +{ + int i; + ulong b24; + char *start = out; + char *e = out + lim; + + for(i = n/3; i > 0; i--){ + b24 = (*in++)<<16; + b24 |= (*in++)<<8; + b24 |= *in++; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = t64e[(b24)&0x3f]; + } + + switch(n%3){ + case 2: + b24 = (*in++)<<16; + b24 |= (*in)<<8; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = t64e[(b24>>6)&0x3f]; + *out++ = '='; + break; + case 1: + b24 = (*in)<<16; + if(out + 4 >= e) + goto exhausted; + *out++ = t64e[(b24>>18)]; + *out++ = t64e[(b24>>12)&0x3f]; + *out++ = '='; + *out++ = '='; + break; + } +exhausted: + *out = 0; + return out - start; +} diff --git a/sys/src/libc/port/utfecpy.c b/sys/src/libc/port/utfecpy.c new file mode 100755 index 000000000..565368bdf --- /dev/null +++ b/sys/src/libc/port/utfecpy.c @@ -0,0 +1,21 @@ +#include <u.h> +#include <libc.h> + +char* +utfecpy(char *to, char *e, char *from) +{ + char *end; + + if(to >= e) + return to; + end = memccpy(to, from, '\0', e - to); + if(end == nil){ + end = e; + while(end>to && (*--end&0xC0)==0x80) + ; + *end = '\0'; + }else{ + end--; + } + return end; +} diff --git a/sys/src/libc/port/utflen.c b/sys/src/libc/port/utflen.c new file mode 100755 index 000000000..4356fb1c2 --- /dev/null +++ b/sys/src/libc/port/utflen.c @@ -0,0 +1,22 @@ +#include <u.h> +#include <libc.h> + +int +utflen(char *s) +{ + int c; + long n; + Rune rune; + + n = 0; + for(;;) { + c = *(uchar*)s; + if(c < Runeself) { + if(c == 0) + return n; + s++; + } else + s += chartorune(&rune, s); + n++; + } +} diff --git a/sys/src/libc/port/utfnlen.c b/sys/src/libc/port/utfnlen.c new file mode 100755 index 000000000..43e9c4aae --- /dev/null +++ b/sys/src/libc/port/utfnlen.c @@ -0,0 +1,26 @@ +#include <u.h> +#include <libc.h> + +int +utfnlen(char *s, long m) +{ + int c; + long n; + Rune rune; + char *es; + + es = s + m; + for(n = 0; s < es; n++) { + c = *(uchar*)s; + if(c < Runeself){ + if(c == '\0') + break; + s++; + continue; + } + if(!fullrune(s, es-s)) + break; + s += chartorune(&rune, s); + } + return n; +} diff --git a/sys/src/libc/port/utfrrune.c b/sys/src/libc/port/utfrrune.c new file mode 100755 index 000000000..c52791f88 --- /dev/null +++ b/sys/src/libc/port/utfrrune.c @@ -0,0 +1,30 @@ +#include <u.h> +#include <libc.h> + +char* +utfrrune(char *s, long c) +{ + long c1; + Rune r; + char *s1; + + if(c < Runesync) /* not part of utf sequence */ + return strrchr(s, c); + + s1 = 0; + for(;;) { + c1 = *(uchar*)s; + if(c1 < Runeself) { /* one byte rune */ + if(c1 == 0) + return s1; + if(c1 == c) + s1 = s; + s++; + continue; + } + c1 = chartorune(&r, s); + if(r == c) + s1 = s; + s += c1; + } +} diff --git a/sys/src/libc/port/utfrune.c b/sys/src/libc/port/utfrune.c new file mode 100755 index 000000000..8d975855d --- /dev/null +++ b/sys/src/libc/port/utfrune.c @@ -0,0 +1,29 @@ +#include <u.h> +#include <libc.h> + +char* +utfrune(char *s, long c) +{ + long c1; + Rune r; + int n; + + if(c < Runesync) /* not part of utf sequence */ + return strchr(s, c); + + for(;;) { + c1 = *(uchar*)s; + if(c1 < Runeself) { /* one byte rune */ + if(c1 == 0) + return 0; + if(c1 == c) + return s; + s++; + continue; + } + n = chartorune(&r, s); + if(r == c) + return s; + s += n; + } +} diff --git a/sys/src/libc/port/utfutf.c b/sys/src/libc/port/utfutf.c new file mode 100755 index 000000000..48d1ee831 --- /dev/null +++ b/sys/src/libc/port/utfutf.c @@ -0,0 +1,26 @@ +#include <u.h> +#include <libc.h> + + +/* + * Return pointer to first occurrence of s2 in s1, + * 0 if none + */ +char* +utfutf(char *s1, char *s2) +{ + char *p; + long f, n1, n2; + Rune r; + + n1 = chartorune(&r, s2); + f = r; + if(f <= Runesync) /* represents self */ + return strstr(s1, s2); + + n2 = strlen(s2); + for(p=s1; p=utfrune(p, f); p+=n1) + if(strncmp(p, s2, n2) == 0) + return p; + return 0; +} diff --git a/sys/src/libc/power/argv0.s b/sys/src/libc/power/argv0.s new file mode 100755 index 000000000..8d9f9b29b --- /dev/null +++ b/sys/src/libc/power/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/power/atom.s b/sys/src/libc/power/atom.s new file mode 100755 index 000000000..86776e6ed --- /dev/null +++ b/sys/src/libc/power/atom.s @@ -0,0 +1,65 @@ +TEXT ainc(SB),$0 /* long ainc(long *); */ + MOVW R3, R4 +xincloop: + LWAR (R4), R3 + ADD $1, R3 + DCBT (R4) /* fix 405 errata cpu_210 */ + STWCCC R3, (R4) + BNE xincloop + RETURN + +TEXT adec(SB),$0 /* long adec(long *); */ + MOVW R3, R4 +xdecloop: + LWAR (R4), R3 + ADD $-1, R3 + DCBT (R4) /* fix 405 errata cpu_210 */ + STWCCC R3, (R4) + BNE xdecloop + RETURN + +TEXT loadlink(SB), $0 + + LWAR (R3), R3 + RETURN + +TEXT storecond(SB), $0 + + MOVW val+4(FP), R4 + DCBT (R3) /* fix 405 errata cpu_210 */ + STWCCC R4, (R3) + BNE storecondfail + MOVW $1, R3 + RETURN +storecondfail: + MOVW $0, R3 + RETURN + +/* + * int cas32(u32int *p, u32int ov, u32int nv); + * int cas(uint *p, int ov, int nv); + * int casp(void **p, void *ov, void *nv); + * int casl(ulong *p, ulong ov, ulong nv); + */ + +TEXT cas32+0(SB),0,$0 +TEXT cas+0(SB),0,$0 +TEXT casp+0(SB),0,$0 +TEXT casl+0(SB),0,$0 + MOVW ov+4(FP),R4 + MOVW nv+8(FP),R8 + LWAR (R3),R5 + CMP R5,R4 + BNE fail + DCBT (R3) /* fix 405 errata cpu_210 */ + STWCCC R8,(R3) + BNE fail1 + MOVW $1,R3 + RETURN +fail: + DCBT (R3) /* fix 405 errata cpu_210 */ + STWCCC R5,(R3) /* give up exclusive access */ +fail1: + MOVW R0,R3 + RETURN + END diff --git a/sys/src/libc/power/cycles.s b/sys/src/libc/power/cycles.s new file mode 100755 index 000000000..441171136 --- /dev/null +++ b/sys/src/libc/power/cycles.s @@ -0,0 +1,17 @@ +#define TBRL 268 +#define TBRU 269 /* Time base Upper/Lower (Reading) */ + +/* + * time stamp counter; _cycles since power up + * Runs at fasthz/4 cycles per second (m->clkin>>3) + */ +TEXT cycles(SB),1,$0 +loop: + MOVW SPR(TBRU),R7 + MOVW SPR(TBRL),R8 + MOVW SPR(TBRU),R5 + CMP R5,R7 + BNE loop + MOVW R7,0(R3) + MOVW R8,4(R3) + RETURN diff --git a/sys/src/libc/power/getcallerpc.s b/sys/src/libc/power/getcallerpc.s new file mode 100755 index 000000000..62c3ee233 --- /dev/null +++ b/sys/src/libc/power/getcallerpc.s @@ -0,0 +1,4 @@ +TEXT getcallerpc(SB),1,$-4 + MOVW 0(R1), R3 + RETURN + diff --git a/sys/src/libc/power/getfcr.s b/sys/src/libc/power/getfcr.s new file mode 100755 index 000000000..b61d52e68 --- /dev/null +++ b/sys/src/libc/power/getfcr.s @@ -0,0 +1,28 @@ +TEXT getfcr(SB), $8 + MOVFL FPSCR, F3 + FMOVD F3, f-8(SP) + MOVW -4(SP), R3 + RETURN + +TEXT getfsr(SB), $8 + MOVFL FPSCR, F3 + FMOVD F3, f-8(SP) + MOVW -4(SP), R3 + RETURN + +TEXT setfcr(SB), $8 + SYNC + MOVW R3, -4(SP) + FMOVD -8(SP), F3 + MOVFL F3, FPSCR + ISYNC + RETURN + +TEXT setfsr(SB), $8 + SYNC + MOVW R3, -4(SP) + FMOVD -8(SP), F3 + MOVFL F3, FPSCR + ISYNC + RETURN + diff --git a/sys/src/libc/power/main9.s b/sys/src/libc/power/main9.s new file mode 100755 index 000000000..46085adf5 --- /dev/null +++ b/sys/src/libc/power/main9.s @@ -0,0 +1,25 @@ +#define NPRIVATES 16 + +TEXT _main(SB), 1, $(16 + NPRIVATES*4) + + MOVW $setSB(SB), R2 + MOVW R3, _tos(SB) + + MOVW $p-64(SP), R4 + MOVW R4, _privates+0(SB) + MOVW $16, R4 + MOVW R4, _nprivates+0(SB) + + MOVW inargc-4(FP), R3 + MOVW $inargv+0(FP), R4 + MOVW R3, 4(R1) + MOVW R4, 8(R1) + BL main(SB) +loop: + MOVW $_exitstr<>(SB), R3 + MOVW R3, 4(R1) + BL exits(SB) + BR loop + +DATA _exitstr<>+0(SB)/4, $"main" +GLOBL _exitstr<>+0(SB), $5 diff --git a/sys/src/libc/power/main9p.s b/sys/src/libc/power/main9p.s new file mode 100755 index 000000000..76723cc10 --- /dev/null +++ b/sys/src/libc/power/main9p.s @@ -0,0 +1,37 @@ +#define NPRIVATES 16 + +TEXT _mainp(SB), 1, $(16 + NPRIVATES*4) + + MOVW $setSB(SB), R2 + MOVW R3, _tos(SB) + + MOVW $p-64(SP), R4 + MOVW R4, _privates+0(SB) + MOVW $16, R4 + MOVW R4, _nprivates+0(SB) + + BL _profmain(SB) + MOVW _tos(SB), R3 + MOVW 4(R3), R4 + MOVW R4, 0(R3) + MOVW inargc-4(FP), R3 + MOVW $inargv+0(FP), R4 + MOVW R3, 4(R1) + MOVW R4, 8(R1) + BL main(SB) +loop: + MOVW $exits<>(SB), R3 + MOVW R3, 4(R1) + BL exits(SB) + MOVW $_profin(SB), R3 /* force loading of profile */ + BR loop + +TEXT _savearg(SB), 1, $0 + RETURN + +TEXT _callpc(SB), 1, $0 + MOVW argp-4(FP), R3 + RETURN + +DATA exits<>+0(SB)/4, $"main" +GLOBL exits<>+0(SB), $5 diff --git a/sys/src/libc/power/memccpy.s b/sys/src/libc/power/memccpy.s new file mode 100755 index 000000000..4a4a34449 --- /dev/null +++ b/sys/src/libc/power/memccpy.s @@ -0,0 +1,23 @@ + TEXT memccpy(SB), $0 +#define BDNZ BC 16,0, + MOVW R3, s1+0(FP) + MOVW n+12(FP), R7 + MOVW s2+4(FP), R4 + MOVBZ c+11(FP), R5 + CMP R7, $0 + BEQ nf + MOVW R7, CTR + SUB $1, R3 + SUB $1, R4 +l1: + MOVBZU 1(R4), R6 + CMP R6, R5 + MOVBZU R6, 1(R3) + BEQ eq + BDNZ l1 +nf: + MOVW $0, R3 + RETURN +eq: + ADD $1, R3 + RETURN diff --git a/sys/src/libc/power/memcmp.s b/sys/src/libc/power/memcmp.s new file mode 100755 index 000000000..f524fa9d3 --- /dev/null +++ b/sys/src/libc/power/memcmp.s @@ -0,0 +1,110 @@ + TEXT memcmp(SB), $0 +#define BDNZ BC 16,0, + MOVW R3, s1+0(FP) /* R3 is pointer1 */ + +/* + * performance: + * 67mb/sec aligned; 16mb/sec unaligned + */ + + MOVW n+8(FP), R4 /* R4 is count */ + MOVW s2+4(FP), R5 /* R5 is pointer2 */ + +/* + * let LSW do the work for 4 characters or less; aligned and unaligned + */ + CMP R4, $0 + BLE eq + CMP R4, $4 + BLE out + + XOR R3, R5, R9 + ANDCC $3, R9 + BNE l4 /* pointers misaligned; use LSW loop */ + +/* + * do enough bytes to align pointers + */ + ANDCC $3,R3, R9 + BEQ l2 + SUBC R9, $4, R9 + MOVW R9, XER + LSW (R3), R10 + ADD R9, R3 + LSW (R5), R14 + ADD R9, R5 + SUB R9, R4 + CMPU R10, R14 + BNE ne + +/* + * compare 16 at a time + */ +l2: + SRAWCC $4, R4, R9 + BLE l4 + MOVW R9, CTR + SUB $4, R3 + SUB $4, R5 +l3: + MOVWU 4(R3), R10 + MOVWU 4(R5), R12 + MOVWU 4(R3), R11 + MOVWU 4(R5), R13 + CMPU R10, R12 + BNE ne + MOVWU 4(R3), R10 + MOVWU 4(R5), R12 + CMPU R11, R13 + BNE ne + MOVWU 4(R3), R11 + MOVWU 4(R5), R13 + CMPU R10, R12 + BNE ne + CMPU R11, R13 + BNE ne + BDNZ l3 + ADD $4, R3 + ADD $4, R5 + RLWNMCC $0, R4, $15, R4 /* residue */ + BEQ eq + +/* + * do remaining words with LSW; also does unaligned case + */ +l4: + SRAWCC $2, R4, R9 + BLE out + MOVW R9, CTR +l5: + LSW (R3), $4, R10 + ADD $4, R3 + LSW (R5), $4, R11 + ADD $4, R5 + CMPU R10, R11 + BNE ne + BDNZ l5 + RLWNMCC $0, R4, $3, R4 /* residue */ + BEQ eq + +/* + * do remaining bytes with final LSW + */ +out: + MOVW R4, XER + LSW (R3), R10 + LSW (R5), R11 + CMPU R10, R11 + BNE ne + +eq: + MOVW $0, R3 + RETURN + +ne: + MOVW $1, R3 + BGE ret + MOVW $-1,R3 +ret: + RETURN + END diff --git a/sys/src/libc/power/memmove.s b/sys/src/libc/power/memmove.s new file mode 100755 index 000000000..34c1e3c5f --- /dev/null +++ b/sys/src/libc/power/memmove.s @@ -0,0 +1,170 @@ +#define BDNZ BC 16,0, + TEXT memmove(SB), $0 + BR move + + TEXT memcpy(SB), $0 +move: + +/* + * performance: + * (tba) + */ + + MOVW R3, s1+0(FP) + MOVW n+8(FP), R9 /* R9 is count */ + MOVW R3, R10 /* R10 is to-pointer */ + CMP R9, $0 + BEQ ret + BLT trap + MOVW s2+4(FP), R11 /* R11 is from-pointer */ + +/* + * if no more than 16 bytes, just use one lsw/stsw + */ + CMP R9, $16 + BLE fout + + ADD R9,R11, R13 /* R13 is end from-pointer */ + ADD R9,R10, R12 /* R12 is end to-pointer */ + +/* + * easiest test is copy backwards if + * destination string has higher mem address + */ + CMPU R10, R11 + BGT back + +/* + * test if both pointers + * are similarly word aligned + */ + XOR R10,R11, R7 + ANDCC $3,R7 + BNE fbad + +/* + * move a few bytes to align pointers + */ + ANDCC $3,R10,R7 + BEQ f2 + SUBC R7, $4, R7 + SUB R7, R9 + MOVW R7, XER + LSW (R11), R16 + ADD R7, R11 + STSW R16, (R10) + ADD R7, R10 + +/* + * turn R14 into doubleword count + * copy 16 bytes at a time while there's room. + */ +f2: + SRAWCC $4, R9, R14 + BLE fout + MOVW R14, CTR + SUB $4, R11 + SUB $4, R10 +f3: + MOVWU 4(R11), R16 + MOVWU 4(R11), R17 + MOVWU 4(R11), R18 + MOVWU 4(R11), R19 + MOVWU R16, 4(R10) + MOVWU R17, 4(R10) + MOVWU R18, 4(R10) + MOVWU R19, 4(R10) + BDNZ f3 + RLWNMCC $0, R9, $15, R9 /* residue */ + BEQ ret + ADD $4, R11 + ADD $4, R10 + +/* + * move up to 16 bytes through R16 .. R19; aligned and unaligned + */ +fout: + MOVW R9, XER + LSW (R11), R16 + STSW R16, (R10) + BR ret + +/* + * loop for unaligned copy, then copy up to 15 remaining bytes + */ +fbad: + SRAWCC $4, R9, R14 + BLE f6 + MOVW R14, CTR +f5: + LSW (R11), $16, R16 + ADD $16, R11 + STSW R16, $16, (R10) + ADD $16, R10 + BDNZ f5 + RLWNMCC $0, R9, $15, R9 /* residue */ + BEQ ret +f6: + MOVW R9, XER + LSW (R11), R16 + STSW R16, (R10) + BR ret + +/* + * whole thing repeated for backwards + */ +back: + CMP R9, $4 + BLT bout + + XOR R12,R13, R7 + ANDCC $3,R7 + BNE bout +b1: + ANDCC $3,R13, R7 + BEQ b2 + MOVBZU -1(R13), R16 + MOVBZU R16, -1(R12) + SUB $1, R9 + BR b1 +b2: + SRAWCC $4, R9, R14 + BLE b4 + MOVW R14, CTR +b3: + MOVWU -4(R13), R16 + MOVWU -4(R13), R17 + MOVWU -4(R13), R18 + MOVWU -4(R13), R19 + MOVWU R16, -4(R12) + MOVWU R17, -4(R12) + MOVWU R18, -4(R12) + MOVWU R19, -4(R12) + BDNZ b3 + RLWNMCC $0, R9, $15, R9 /* residue */ + BEQ ret +b4: + SRAWCC $2, R9, R14 + BLE bout + MOVW R14, CTR +b5: + MOVWU -4(R13), R16 + MOVWU R16, -4(R12) + BDNZ b5 + RLWNMCC $0, R9, $3, R9 /* residue */ + BEQ ret + +bout: + CMPU R13, R11 + BLE ret + MOVBZU -1(R13), R16 + MOVBZU R16, -1(R12) + BR bout + +trap: + MOVW $0, R0 + MOVW 0(R0), R0 + +ret: + MOVW s1+0(FP), R3 + RETURN diff --git a/sys/src/libc/power/memset.s b/sys/src/libc/power/memset.s new file mode 100755 index 000000000..fa6e8d920 --- /dev/null +++ b/sys/src/libc/power/memset.s @@ -0,0 +1,73 @@ + TEXT memset(SB),$0 +#define BDNZ BC 16,0, + MOVW R3, p+0(FP) /* R3 is pointer */ + +/* + * performance: + * about 100mbytes/sec (8k blocks) on a 603/105 without L2 cache + * drops to 40mbytes/sec (10k blocks) and 28mbytes/sec with 32k blocks + */ + + MOVW n+8(FP), R4 /* R4 is count */ + CMP R4, $0 + BLE ret + MOVW c+4(FP), R5 /* R5 is char */ + +/* + * create 16 copies of c in R5 .. R8 + */ + RLWNM $0, R5, $0xff, R5 + RLWMI $8, R5, $0xff00, R5 + RLWMI $16, R5, $0xffff0000, R5 + MOVW R5, R6 + MOVW R5, R7 + MOVW R5, R8 + +/* + * let STSW do the work for 16 characters or less; aligned and unaligned + */ + CMP R4, $16 + BLE out + +/* + * store enough bytes to align pointer + */ + ANDCC $7,R3, R9 + BEQ l2 + SUBC R9, $8, R9 + MOVW R9, XER + STSW R5, (R3) + ADD R9, R3 + SUB R9, R4 + +/* + * store 16 at a time while there's room + * STSW was used here originally, but it's `completion serialised' + */ +l2: + SRAWCC $4, R4, R9 + BLE out + MOVW R9, CTR +l3: + MOVW R5, 0(R3) + ADD $8, R3, R10 + MOVW R6, 4(R3) + MOVW R7, 0(R10) + ADD $8, R10, R3 + MOVW R8, 4(R10) + BDNZ l3 + RLWNMCC $0, R4, $15, R4 /* residue */ + BEQ ret + +/* + * store up to 16 bytes from R5 .. R8; aligned and unaligned + */ + +out: + MOVW R4, XER + STSW R5, (R3) + +ret: + MOVW 0(FP), R3 + RETURN + END diff --git a/sys/src/libc/power/mkfile b/sys/src/libc/power/mkfile new file mode 100755 index 000000000..c02f8a98d --- /dev/null +++ b/sys/src/libc/power/mkfile @@ -0,0 +1,37 @@ +objtype=power +</$objtype/mkfile + +LIB=/$objtype/lib/libc.a +SFILES=\ + argv0.s\ + atom.s\ + cycles.s\ + getcallerpc.s\ + getfcr.s\ + main9.s\ + main9p.s\ + memccpy.s\ + memcmp.s\ + memmove.s\ + memset.s\ + setjmp.s\ + strcmp.s\ + strncmp.s\ + tas.s\ + vlop.s + +CFILES=\ + 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/power/notejmp.c b/sys/src/libc/power/notejmp.c new file mode 100755 index 000000000..5394a4d75 --- /dev/null +++ b/sys/src/libc/power/notejmp.c @@ -0,0 +1,22 @@ +#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 r3 in noted + */ + r->r4 = ret; + if(ret == 0) + r->r4 = 1; + r->r5 = j[JMPBUFPC] - JMPBUFDPC; + r->pc = (ulong)__noterestore; + r->sp = j[JMPBUFSP]; + noted(NCONT); +} diff --git a/sys/src/libc/power/setjmp.s b/sys/src/libc/power/setjmp.s new file mode 100755 index 000000000..f3f2f44ae --- /dev/null +++ b/sys/src/libc/power/setjmp.s @@ -0,0 +1,26 @@ +TEXT setjmp(SB), 1, $-4 + MOVW LR, R4 + MOVW R1, (R3) + MOVW R4, 4(R3) + MOVW $0, R3 + RETURN + +TEXT longjmp(SB), 1, $-4 + MOVW R3, R4 + MOVW r+4(FP), R3 + CMP R3, $0 + BNE ok /* ansi: "longjmp(0) => longjmp(1)" */ + MOVW $1, R3 /* bless their pointed heads */ +ok: MOVW (R4), R1 + MOVW 4(R4), R4 + MOVW R4, LR + BR (LR) + +/* + * trampoline functions because the kernel smashes r1 + * in the uregs given to notejmp + */ +TEXT __noterestore(SB), 1, $-4 + MOVW R4, R3 + MOVW R5, LR + BR (LR) diff --git a/sys/src/libc/power/sqrt.c b/sys/src/libc/power/sqrt.c new file mode 100755 index 000000000..fa27c35ef --- /dev/null +++ b/sys/src/libc/power/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/power/strcmp.s b/sys/src/libc/power/strcmp.s new file mode 100755 index 000000000..0aef5b29c --- /dev/null +++ b/sys/src/libc/power/strcmp.s @@ -0,0 +1,21 @@ +TEXT strcmp(SB), $0 + + MOVW s2+4(FP), R4 + + SUB $1, R3 + SUB $1, R4 +l1: + MOVBZU 1(R3), R5 + MOVBZU 1(R4), R6 + CMP R5, R6 + BNE ne + CMP R5, $0 + BNE l1 + MOVW $0, R3 + RETURN +ne: + MOVW $1, R3 + BGT ret + MOVW $-1, R3 +ret: + RETURN diff --git a/sys/src/libc/power/strncmp.s b/sys/src/libc/power/strncmp.s new file mode 100755 index 000000000..c55962faa --- /dev/null +++ b/sys/src/libc/power/strncmp.s @@ -0,0 +1,29 @@ +TEXT strncmp(SB), $0 +#define BDNZ BC 16,0, + + MOVW s2+4(FP), R4 + MOVW n+8(FP), R7 + + CMP R7, $0 + MOVW R7, CTR + BLE eq + + SUB $1, R3 + SUB $1, R4 +l1: + MOVBZU 1(R3), R5 + MOVBZU 1(R4), R6 + CMP R5, R6 + BNE ne + CMP R5, $0 + BEQ eq + BDNZ l1 +eq: + MOVW $0, R3 + RETURN +ne: + MOVW $1, R3 + BGT ret + MOVW $-1, R3 +ret: + RETURN diff --git a/sys/src/libc/power/tas.s b/sys/src/libc/power/tas.s new file mode 100755 index 000000000..246b18056 --- /dev/null +++ b/sys/src/libc/power/tas.s @@ -0,0 +1,14 @@ +TEXT _tas(SB), 1, $-4 + MOVW R3, R4 + MOVW $0xdeaddead,R5 +tas1: +/* DCBF (R4) fix for 603x bug */ + SYNC + LWAR (R4), R3 + CMP R3, $0 + BNE tas0 + DCBT (R4) /* fix 405 errata cpu_210 */ + STWCCC R5, (R4) + BNE tas1 +tas0: + RETURN diff --git a/sys/src/libc/power/vlop.s b/sys/src/libc/power/vlop.s new file mode 100755 index 000000000..9085da247 --- /dev/null +++ b/sys/src/libc/power/vlop.s @@ -0,0 +1,132 @@ +#define BDNZ BC 16,0, + +/* + * 64/64 division adapted from powerpc compiler writer's handbook + * + * (R3:R4) = (R3:R4) / (R5:R6) (64b) = (64b / 64b) + * quo dvd dvs + * + * Remainder is left in R7:R8 + * + * Code comment notation: + * msw = most-significant (high-order) word, i.e. bits 0..31 + * lsw = least-significant (low-order) word, i.e. bits 32..63 + * LZ = Leading Zeroes + * SD = Significant Digits + * + * R3:R4 = dvd (input dividend); quo (output quotient) + * R5:R6 = dvs (input divisor) + * + * R7:R8 = tmp; rem (output remainder) + */ + +TEXT _divu64(SB), $0 + MOVW a+0(FP), R3 + MOVW a+4(FP), R4 + MOVW b+8(FP), R5 + MOVW b+12(FP), R6 + + /* count the number of leading 0s in the dividend */ + CMP R3, $0 /* dvd.msw == 0? R3, */ + CNTLZW R3, R11 /* R11 = dvd.msw.LZ */ + CNTLZW R4, R9 /* R9 = dvd.lsw.LZ */ + BNE lab1 /* if(dvd.msw != 0) dvd.LZ = dvd.msw.LZ */ + ADD $32, R9, R11 /* dvd.LZ = dvd.lsw.LZ + 32 */ + +lab1: + /* count the number of leading 0s in the divisor */ + CMP R5, $0 /* dvd.msw == 0? */ + CNTLZW R5, R9 /* R9 = dvs.msw.LZ */ + CNTLZW R6, R10 /* R10 = dvs.lsw.LZ */ + BNE lab2 /* if(dvs.msw != 0) dvs.LZ = dvs.msw.LZ */ + ADD $32, R10, R9 /* dvs.LZ = dvs.lsw.LZ + 32 */ + +lab2: + /* determine shift amounts to minimize the number of iterations */ + CMP R11, R9 /* compare dvd.LZ to dvs.LZ */ + SUBC R11, $64, R10 /* R10 = dvd.SD */ + BGT lab9 /* if(dvs > dvd) quotient = 0 */ + ADD $1, R9 /* ++dvs.LZ (or --dvs.SD) */ + SUBC R9, $64, R9 /* R9 = dvs.SD */ + ADD R9, R11 /* (dvd.LZ + dvs.SD) = left shift of dvd for */ + /* initial dvd */ + SUB R9, R10, R9 /* (dvd.SD - dvs.SD) = right shift of dvd for */ + /* initial tmp */ + MOVW R9, CTR /* number of iterations = dvd.SD - dvs.SD */ + + /* R7:R8 = R3:R4 >> R9 */ + CMP R9, $32 + ADD $-32, R9, R7 + BLT lab3 /* if(R9 < 32) jump to lab3 */ + SRW R7, R3, R8 /* tmp.lsw = dvd.msw >> (R9 - 32) */ + MOVW $0, R7 /* tmp.msw = 0 */ + BR lab4 +lab3: + SRW R9, R4, R8 /* R8 = dvd.lsw >> R9 */ + SUBC R9, $32, R7 + SLW R7, R3, R7 /* R7 = dvd.msw << 32 - R9 */ + OR R7, R8 /* tmp.lsw = R8 | R7 */ + SRW R9, R3, R7 /* tmp.msw = dvd.msw >> R9 */ + +lab4: + /* R3:R4 = R3:R4 << R11 */ + CMP R11,$32 + ADDC $-32, R11, R9 + BLT lab5 /* (R11 < 32)? */ + SLW R9, R4, R3 /* dvd.msw = dvs.lsw << R9 */ + MOVW $0, R4 /* dvd.lsw = 0 */ + BR lab6 + +lab5: + SLW R11, R3 /* R3 = dvd.msw << R11 */ + SUBC R11, $32, R9 + SRW R9, R4, R9 /* R9 = dvd.lsw >> 32 - R11 */ + OR R9, R3 /* dvd.msw = R3 | R9 */ + SLW R11, R4 /* dvd.lsw = dvd.lsw << R11 */ + +lab6: + /* restoring division shift and subtract loop */ + MOVW $-1, R10 + ADDC $0, R7 /* clear carry bit before loop starts */ +lab7: + /* tmp:dvd is considered one large register */ + /* each portion is shifted left 1 bit by adding it to itself */ + /* adde sums the carry from the previous and creates a new carry */ + ADDE R4,R4 /* shift dvd.lsw left 1 bit */ + ADDE R3,R3 /* shift dvd.msw to left 1 bit */ + ADDE R8,R8 /* shift tmp.lsw to left 1 bit */ + ADDE R7,R7 /* shift tmp.msw to left 1 bit */ + SUBC R6, R8, R11 /* tmp.lsw - dvs.lsw */ + SUBECC R5, R7, R9 /* tmp.msw - dvs.msw */ + BLT lab8 /* if(result < 0) clear carry bit */ + MOVW R11, R8 /* move lsw */ + MOVW R9, R7 /* move msw */ + ADDC $1, R10, R11 /* set carry bit */ +lab8: + BDNZ lab7 + + ADDE R4,R4 /* quo.lsw (lsb = CA) */ + ADDE R3,R3 /* quo.msw (lsb from lsw) */ + +lab10: + MOVW qp+16(FP), R9 + MOVW rp+20(FP), R10 + CMP R9, $0 + BEQ lab11 + MOVW R3, 0(R9) + MOVW R4, 4(R9) +lab11: + CMP R10, $0 + BEQ lab12 + MOVW R7, 0(R10) + MOVW R8, 4(R10) +lab12: + RETURN + +lab9: + /* Quotient is 0 (dvs > dvd) */ + MOVW R4, R8 /* rmd.lsw = dvd.lsw */ + MOVW R3, R7 /* rmd.msw = dvd.msw */ + MOVW $0, R4 /* dvd.lsw = 0 */ + MOVW $0, R3 /* dvd.msw = 0 */ + BR lab10 diff --git a/sys/src/libc/power/vlrt.c b/sys/src/libc/power/vlrt.c new file mode 100755 index 000000000..681a3b49b --- /dev/null +++ b/sys/src/libc/power/vlrt.c @@ -0,0 +1,254 @@ +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 hi; + ulong lo; +}; + +void abort(void); +void _divu64(Vlong, Vlong, Vlong*, Vlong*); + +void +_d2v(Vlong *y, double d) +{ + union { double d; 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); +} + +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; + } + _divu64(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; + } + _divu64(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); + _divu64(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); + _divu64(n, d, 0, r); + if(nneg) + vneg(r); +} + +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; +} 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); +} |