--- gforth/prim 2003/01/08 09:38:28 1.115 +++ gforth/prim 2007/06/23 19:45:14 1.214 @@ -1,6 +1,6 @@ \ Gforth primitives -\ Copyright (C) 1995,1996,1997,1998,2000 Free Software Foundation, Inc. +\ Copyright (C) 1995,1996,1997,1998,2000,2003,2004,2005,2006 Free Software Foundation, Inc. \ This file is part of Gforth. @@ -100,12 +100,18 @@ \E s" struct F83Name *" single data-stack type-prefix f83name \E s" struct Longname *" single data-stack type-prefix longname \E +\E data-stack stack-prefix S: +\E fp-stack stack-prefix F: \E return-stack stack-prefix R: \E inst-stream stack-prefix # \E \E set-current \E store-optimization on \E ' noop tail-nextp2 ! \ now INST_TAIL just stores, but does not jump +\E +\E include-skipped-insts on \ static superinsts include cells for components +\E \ useful for dynamic programming and +\E \ superinsts across entry points \ \ @@ -132,11 +138,96 @@ \ throw execute, cfa and NEXT1 out? \ macroize *ip, ip++, *ip++ (pipelining)? +\ Stack caching setup + +ifdef(`STACK_CACHE_FILE', `include(STACK_CACHE_FILE)', `include(cache0.vmg)') + \ these m4 macros would collide with identifiers undefine(`index') undefine(`shift') undefine(`symbols') +\F 0 [if] + +\ run-time routines for non-primitives. They are defined as +\ primitives, because that simplifies things. + +(docol) ( -- R:a_retaddr ) gforth-internal paren_docol +""run-time routine for colon definitions"" +#ifdef NO_IP +a_retaddr = next_code; +INST_TAIL; +goto **(Label *)PFA(CFA); +#else /* !defined(NO_IP) */ +a_retaddr = (Cell *)IP; +SET_IP((Xt *)PFA(CFA)); +#endif /* !defined(NO_IP) */ + +(docon) ( -- w ) gforth-internal paren_docon +""run-time routine for constants"" +w = *(Cell *)PFA(CFA); +#ifdef NO_IP +INST_TAIL; +goto *next_code; +#endif /* defined(NO_IP) */ + +(dovar) ( -- a_body ) gforth-internal paren_dovar +""run-time routine for variables and CREATEd words"" +a_body = PFA(CFA); +#ifdef NO_IP +INST_TAIL; +goto *next_code; +#endif /* defined(NO_IP) */ + +(douser) ( -- a_user ) gforth-internal paren_douser +""run-time routine for constants"" +a_user = (Cell *)(up+*(Cell *)PFA(CFA)); +#ifdef NO_IP +INST_TAIL; +goto *next_code; +#endif /* defined(NO_IP) */ + +(dodefer) ( -- ) gforth-internal paren_dodefer +""run-time routine for deferred words"" +#ifndef NO_IP +ip=IP; /* undo any ip updating that may have been performed by NEXT_P0 */ +#endif /* !defined(NO_IP) */ +SUPER_END; /* !! probably unnecessary and may lead to measurement errors */ +VM_JUMP(EXEC1(*(Xt *)PFA(CFA))); + +(dofield) ( n1 -- n2 ) gforth-internal paren_field +""run-time routine for fields"" +n2 = n1 + *(Cell *)PFA(CFA); +#ifdef NO_IP +INST_TAIL; +goto *next_code; +#endif /* defined(NO_IP) */ + +(dodoes) ( -- a_body R:a_retaddr ) gforth-internal paren_dodoes +""run-time routine for @code{does>}-defined words"" +#ifdef NO_IP +a_retaddr = next_code; +a_body = PFA(CFA); +INST_TAIL; +#ifdef DEBUG +fprintf(stderr, "dodoes to %x, push %x\n", a_retaddr, a_body); +#endif +goto **(Label *)DOES_CODE1(CFA); +#else /* !defined(NO_IP) */ +a_retaddr = (Cell *)IP; +a_body = PFA(CFA); +#ifdef DEBUG +fprintf(stderr, "dodoes to %x, push %x\n", a_retaddr, a_body); +#endif +SET_IP(DOES_CODE1(CFA)); +#endif /* !defined(NO_IP) */ + +(does-handler) ( -- ) gforth-internal paren_does_handler +""just a slot to have an encoding for the DOESJUMP, +which is no longer used anyway (!! eliminate this)"" + +\F [endif] + \g control noop ( -- ) gforth @@ -146,6 +237,7 @@ noop ( -- ) gforth call ( #a_callee -- R:a_retaddr ) new ""Call callee (a variant of docol with inline argument)."" #ifdef NO_IP +assert(0); INST_TAIL; JUMP(a_callee); #else @@ -162,12 +254,14 @@ SET_IP((Xt *)a_callee); execute ( xt -- ) core ""Perform the semantics represented by the execution token, @i{xt}."" +#ifdef DEBUG +fprintf(stderr, "execute %08x\n", xt); +#endif #ifndef NO_IP ip=IP; #endif -IF_spTOS(spTOS = sp[0]); SUPER_END; -EXEC(xt); +VM_JUMP(EXEC1(xt)); perform ( a_addr -- ) gforth ""@code{@@ execute}."" @@ -175,9 +269,8 @@ perform ( a_addr -- ) gforth #ifndef NO_IP ip=IP; #endif -IF_spTOS(spTOS = sp[0]); SUPER_END; -EXEC(*(Xt *)a_addr); +VM_JUMP(EXEC1(*(Xt *)a_addr)); : @ execute ; @@ -200,7 +293,7 @@ lit-perform ( #a_addr -- ) new lit_perfo ip=IP; #endif SUPER_END; -EXEC(*(Xt *)a_addr); +VM_JUMP(EXEC1(*(Xt *)a_addr)); does-exec ( #a_cfa -- R:nest a_pfa ) new does_exec #ifdef NO_IP @@ -209,7 +302,6 @@ assert(0); #else a_pfa = PFA(a_cfa); nest = (Cell)IP; -IF_spTOS(spTOS = sp[0]); #ifdef DEBUG { CFA_TO_NAME(a_cfa); @@ -255,10 +347,10 @@ $5 #ifdef NO_IP JUMP(a_target); #else SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; +ifelse(condbranch_opt,`1',`INST_TAIL; NEXT_P2;',`/* condbranch_opt=0 */') #endif } -SUPER_CONTINUE; +ifelse(condbranch_opt,`1',`SUPER_CONTINUE;',`/* condbranch_opt=0 */') $6 \+glocals @@ -272,10 +364,10 @@ $5 lp += nlocals; JUMP(a_target); #else SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; +ifelse(condbranch_opt,`1',`INST_TAIL; NEXT_P2;',`/* condbranch_opt=0 */') #endif } -SUPER_CONTINUE; +ifelse(condbranch_opt,`1',`SUPER_CONTINUE;',`/* condbranch_opt=0 */') \+ ) @@ -293,37 +385,31 @@ condbranch(?branch,f --,f83 question_bra \+xconds -?dup-?branch ( #a_target f -- f ) new question_dupe_question_branch +?dup-?branch ( #a_target f -- S:... ) new question_dupe_question_branch ""The run-time procedure compiled by @code{?DUP-IF}."" if (f==0) { - sp++; - IF_spTOS(spTOS = sp[0]); #ifdef NO_IP INST_TAIL; JUMP(a_target); #else SET_IP((Xt *)a_target); - INST_TAIL; NEXT_P2; #endif +} else { +sp--; +sp[0]=f; } -SUPER_CONTINUE; -?dup-0=-?branch ( #a_target f -- ) new question_dupe_zero_equals_question_branch +?dup-0=-?branch ( #a_target f -- S:... ) new question_dupe_zero_equals_question_branch ""The run-time procedure compiled by @code{?DUP-0=-IF}."" -/* the approach taken here of declaring the word as having the stack -effect ( f -- ) and correcting for it in the branch-taken case costs a -few cycles in that case, but is easy to convert to a CONDBRANCH -invocation */ if (f!=0) { sp--; + sp[0]=f; #ifdef NO_IP JUMP(a_target); #else SET_IP((Xt *)a_target); - NEXT; #endif } -SUPER_CONTINUE; \+ \fhas? skiploopprims 0= [IF] @@ -349,8 +435,9 @@ condbranch((+loop),n R:nlimit R:n1 -- R: /* dependent upon two's complement arithmetic */ Cell olddiff = n1-nlimit; n2=n1+n; -,if ((olddiff^(olddiff+n))>=0 /* the limit is not crossed */ - || (olddiff^n)>=0 /* it is a wrap-around effect */) { +,if (((olddiff^(olddiff+n)) /* the limit is not crossed */ + &(olddiff^n)) /* OR it is a wrap-around effect */ + >=0) { /* & is used to avoid having two branches for gforth-native */ ,: r> swap r> r> 2dup - >r @@ -379,7 +466,7 @@ if (n<0) { newdiff = -newdiff; } n2=n1+n; -,if (diff>=0 || newdiff<0) { +,if (((~diff)|newdiff)<0) { /* use | to avoid two branches for gforth-native */ ,) \+ @@ -403,10 +490,8 @@ if (nstart == nlimit) { JUMP(a_target); #else SET_IP((Xt *)a_target); - INST_TAIL; NEXT_P2; #endif } -SUPER_CONTINUE; : 2dup = IF r> swap rot >r >r @@ -426,10 +511,8 @@ if (nstart >= nlimit) { JUMP(a_target); #else SET_IP((Xt *)a_target); - INST_TAIL; NEXT_P2; #endif } -SUPER_CONTINUE; : swap 2dup r> swap >r swap >r @@ -449,10 +532,8 @@ if (ustart >= ulimit) { JUMP(a_target); #else SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; #endif } -SUPER_CONTINUE; : swap 2dup r> swap >r swap >r @@ -472,10 +553,8 @@ if (nstart <= nlimit) { JUMP(a_target); #else SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; #endif } -SUPER_CONTINUE; : swap 2dup r> swap >r swap >r @@ -495,10 +574,8 @@ if (ustart <= ulimit) { JUMP(a_target); #else SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; #endif } -SUPER_CONTINUE; : swap 2dup r> swap >r swap >r @@ -557,8 +634,7 @@ cmove ( c_from c_to u -- ) string c_move @i{c-from} to @i{c-to}. The copy proceeds @code{char}-by-@code{char} from low address to high address; i.e., for overlapping areas it is safe if @i{c-to}=<@i{c-from}."" -while (u-- > 0) - *c_to++ = *c_from++; +cmove(c_from,c_to,u); : bounds ?DO dup c@ I c! 1+ LOOP drop ; @@ -567,8 +643,7 @@ cmove> ( c_from c_to u -- ) string c_mov @i{c-from} to @i{c-to}. The copy proceeds @code{char}-by-@code{char} from high address to low address; i.e., for overlapping areas it is safe if @i{c-to}>=@i{c-from}."" -while (u-- > 0) - c_to[u] = c_from[u]; +cmove_up(c_from,c_to,u); : dup 0= IF drop 2drop exit THEN rot over + -rot bounds swap 1- @@ -588,32 +663,31 @@ is 1. Currently this is based on the mac comparison. In the future, this may change to consider the current locale and its collation order."" /* close ' to keep fontify happy */ -n = memcmp(c_addr1, c_addr2, u10) - n = 1; +n = compare(c_addr1, u1, c_addr2, u2); : rot 2dup swap - >r min swap -text dup IF rdrop ELSE drop r> sgn THEN ; -: sgn ( n -- -1/0/1 ) - dup 0= IF EXIT THEN 0< 2* 1+ ; - --text ( c_addr1 u c_addr2 -- n ) new dash_text -n = memcmp(c_addr1, c_addr2, u); -if (n<0) - n = -1; -else if (n>0) - n = 1; -: +: -text ( c_addr1 u c_addr2 -- n ) swap bounds ?DO dup c@ I c@ = WHILE 1+ LOOP drop 0 ELSE c@ I c@ - unloop THEN sgn ; : sgn ( n -- -1/0/1 ) dup 0= IF EXIT THEN 0< 2* 1+ ; +\ -text is only used by replaced primitives now; move it elsewhere +\ -text ( c_addr1 u c_addr2 -- n ) new dash_text +\ n = memcmp(c_addr1, c_addr2, u); +\ if (n<0) +\ n = -1; +\ else if (n>0) +\ n = 1; +\ : +\ swap bounds +\ ?DO dup c@ I c@ = WHILE 1+ LOOP drop 0 +\ ELSE c@ I c@ - unloop THEN sgn ; +\ : sgn ( n -- -1/0/1 ) +\ dup 0= IF EXIT THEN 0< 2* 1+ ; + toupper ( c1 -- c2 ) gforth ""If @i{c1} is a lower-case character (in the current locale), @i{c2} is the equivalent upper-case character. All other characters are unchanged."" @@ -621,28 +695,14 @@ c2 = toupper(c1); : dup [char] a - [ char z char a - 1 + ] Literal u< bl and - ; -capscomp ( c_addr1 u c_addr2 -- n ) new -n = memcasecmp(c_addr1, c_addr2, u); /* !! use something that works in all locales */ -if (n<0) - n = -1; -else if (n>0) - n = 1; -: - swap bounds - ?DO dup c@ I c@ <> - IF dup c@ toupper I c@ toupper = - ELSE true THEN WHILE 1+ LOOP drop 0 - ELSE c@ toupper I c@ toupper - unloop THEN sgn ; - --trailing ( c_addr u1 -- c_addr u2 ) string dash_trailing -""Adjust the string specified by @i{c-addr, u1} to remove all trailing -spaces. @i{u2} is the length of the modified string."" -u2 = u1; -while (u2>0 && c_addr[u2-1] == ' ') - u2--; -: - BEGIN 1- 2dup + c@ bl = WHILE - dup 0= UNTIL ELSE 1+ THEN ; +capscompare ( c_addr1 u1 c_addr2 u2 -- n ) string +""Compare two strings lexicographically. If they are equal, @i{n} is 0; if +the first string is smaller, @i{n} is -1; if the first string is larger, @i{n} +is 1. Currently this is based on the machine's character +comparison. In the future, this may change to consider the current +locale and its collation order."" +/* close ' to keep fontify happy */ +n = capscompare(c_addr1, u1, c_addr2, u2); /string ( c_addr1 u1 n -- c_addr2 u2 ) string slash_string ""Adjust the string specified by @i{c-addr1, u1} to remove @i{n} @@ -664,6 +724,9 @@ n = n1+n2; \ lit+ / lit_plus = lit + lit+ ( n1 #n2 -- n ) new lit_plus +#ifdef DEBUG +fprintf(stderr, "lit+ %08x\n", n2); +#endif n=n1+n2; \ PFE-0.9.14 has it differently, but the next release will have it as follows @@ -725,20 +788,84 @@ n = n1*n2; / ( n1 n2 -- n ) core slash n = n1/n2; +if (CHECK_DIVISION_SW && n2 == 0) + throw(BALL_DIVZERO); +if (CHECK_DIVISION_SW && n2 == -1 && n1 == CELL_MIN) + throw(BALL_RESULTRANGE); +if (FLOORED_DIV && ((n1^n2) < 0) && (n1%n2 != 0)) + n--; : /mod nip ; mod ( n1 n2 -- n ) core n = n1%n2; +if (CHECK_DIVISION_SW && n2 == 0) + throw(BALL_DIVZERO); +if (CHECK_DIVISION_SW && n2 == -1 && n1 == CELL_MIN) + throw(BALL_RESULTRANGE); +if(FLOORED_DIV && ((n1^n2) < 0) && n!=0) n += n2; : /mod drop ; /mod ( n1 n2 -- n3 n4 ) core slash_mod n4 = n1/n2; n3 = n1%n2; /* !! is this correct? look into C standard! */ +if (CHECK_DIVISION_SW && n2 == 0) + throw(BALL_DIVZERO); +if (CHECK_DIVISION_SW && n2 == -1 && n1 == CELL_MIN) + throw(BALL_RESULTRANGE); +if (FLOORED_DIV && ((n1^n2) < 0) && n3!=0) { + n4--; + n3+=n2; +} : >r s>d r> fm/mod ; +*/mod ( n1 n2 n3 -- n4 n5 ) core star_slash_mod +""n1*n2=n3*n5+n4, with the intermediate result (n1*n2) being double."" +#ifdef BUGGY_LL_MUL +DCell d = mmul(n1,n2); +#else +DCell d = (DCell)n1 * (DCell)n2; +#endif +#ifdef ASM_SM_SLASH_REM +ASM_SM_SLASH_REM(DLO(d), DHI(d), n3, n4, n5); +if (FLOORED_DIV && ((DHI(d)^n3)<0) && n4!=0) { + if (CHECK_DIVISION && n5 == CELL_MIN) + throw(BALL_RESULTRANGE); + n5--; + n4+=n3; +} +#else +DCell r = FLOORED_DIV ? fmdiv(d,n3) : smdiv(d,n3); +n4=DHI(r); +n5=DLO(r); +#endif +: + >r m* r> fm/mod ; + +*/ ( n1 n2 n3 -- n4 ) core star_slash +""n4=(n1*n2)/n3, with the intermediate result being double."" +#ifdef BUGGY_LL_MUL +DCell d = mmul(n1,n2); +#else +DCell d = (DCell)n1 * (DCell)n2; +#endif +#ifdef ASM_SM_SLASH_REM +Cell remainder; +ASM_SM_SLASH_REM(DLO(d), DHI(d), n3, remainder, n4); +if (FLOORED_DIV && ((DHI(d)^n3)<0) && remainder!=0) { + if (CHECK_DIVISION && n4 == CELL_MIN) + throw(BALL_RESULTRANGE); + n4--; +} +#else +DCell r = FLOORED_DIV ? fmdiv(d,n3) : smdiv(d,n3); +n4=DLO(r); +#endif +: + */mod nip ; + 2* ( n1 -- n2 ) core two_star ""Shift left by 1; also works on unsigned numbers"" n2 = 2*n1; @@ -751,27 +878,26 @@ division by 2 (note that @code{/} not ne n2 = n1>>1; : dup MINI and IF 1 ELSE 0 THEN - [ bits/byte cell * 1- ] literal + [ bits/char cell * 1- ] literal 0 DO 2* swap dup 2* >r MINI and IF 1 ELSE 0 THEN or r> swap LOOP nip ; fm/mod ( d1 n1 -- n2 n3 ) core f_m_slash_mod ""Floored division: @i{d1} = @i{n3}*@i{n1}+@i{n2}, @i{n1}>@i{n2}>=0 or 0>=@i{n2}>@i{n1}."" -#ifdef BUGGY_LONG_LONG -DCell r = fmdiv(d1,n1); -n2=r.hi; -n3=r.lo; -#else -/* assumes that the processor uses either floored or symmetric division */ -n3 = d1/n1; -n2 = d1%n1; -/* note that this 1%-3>0 is optimized by the compiler */ -if (1%-3>0 && (d1<0) != (n1<0) && n2!=0) { +#ifdef ASM_SM_SLASH_REM +ASM_SM_SLASH_REM(DLO(d1), DHI(d1), n1, n2, n3); +if (((DHI(d1)^n1)<0) && n2!=0) { + if (CHECK_DIVISION && n3 == CELL_MIN) + throw(BALL_RESULTRANGE); n3--; n2+=n1; } -#endif +#else /* !defined(ASM_SM_SLASH_REM) */ +DCell r = fmdiv(d1,n1); +n2=DHI(r); +n3=DLO(r); +#endif /* !defined(ASM_SM_SLASH_REM) */ : dup >r dup 0< IF negate >r dnegate r> THEN over 0< IF tuck + swap THEN @@ -780,20 +906,13 @@ if (1%-3>0 && (d1<0) != (n1<0) && n2!=0) sm/rem ( d1 n1 -- n2 n3 ) core s_m_slash_rem ""Symmetric division: @i{d1} = @i{n3}*@i{n1}+@i{n2}, sign(@i{n2})=sign(@i{d1}) or 0."" -#ifdef BUGGY_LONG_LONG +#ifdef ASM_SM_SLASH_REM +ASM_SM_SLASH_REM(DLO(d1), DHI(d1), n1, n2, n3); +#else /* !defined(ASM_SM_SLASH_REM) */ DCell r = smdiv(d1,n1); -n2=r.hi; -n3=r.lo; -#else -/* assumes that the processor uses either floored or symmetric division */ -n3 = d1/n1; -n2 = d1%n1; -/* note that this 1%-3<0 is optimized by the compiler */ -if (1%-3<0 && (d1<0) != (n1<0) && n2!=0) { - n3++; - n2-=n1; -} -#endif +n2=DHI(r); +n3=DLO(r); +#endif /* !defined(ASM_SM_SLASH_REM) */ : over >r dup >r abs -rot dabs rot um/mod @@ -801,7 +920,7 @@ if (1%-3<0 && (d1<0) != (n1<0) && n2!=0) r> 0< IF swap negate swap THEN ; m* ( n1 n2 -- d ) core m_star -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_MUL d = mmul(n1,n2); #else d = (DCell)n1 * (DCell)n2; @@ -813,31 +932,29 @@ d = (DCell)n1 * (DCell)n2; um* ( u1 u2 -- ud ) core u_m_star /* use u* as alias */ -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_MUL ud = ummul(u1,u2); #else ud = (UDCell)u1 * (UDCell)u2; #endif : - >r >r 0 0 r> r> [ 8 cells ] literal 0 + 0 -rot dup [ 8 cells ] literal - DO - over >r dup >r 0< and d2*+ drop - r> 2* r> swap - LOOP 2drop ; + dup 0< I' and d2*+ drop + LOOP ; : d2*+ ( ud n -- ud+n c ) over MINI and >r >r 2dup d+ swap r> + swap r> ; um/mod ( ud u1 -- u2 u3 ) core u_m_slash_mod ""ud=u3*u1+u2, u1>u2>=0"" -#ifdef BUGGY_LONG_LONG +#ifdef ASM_UM_SLASH_MOD +ASM_UM_SLASH_MOD(DLO(ud), DHI(ud), u1, u2, u3); +#else /* !defined(ASM_UM_SLASH_MOD) */ UDCell r = umdiv(ud,u1); -u2=r.hi; -u3=r.lo; -#else -u3 = ud/u1; -u2 = ud%u1; -#endif +u2=DHI(r); +u3=DLO(r); +#endif /* !defined(ASM_UM_SLASH_MOD) */ : 0 swap [ 8 cells 1 + ] literal 0 ?DO /modstep @@ -849,9 +966,9 @@ u2 = ud%u1; and >r >r 2dup d+ swap r> + swap r> ; m+ ( d1 n -- d2 ) double m_plus -#ifdef BUGGY_LONG_LONG -d2.lo = d1.lo+n; -d2.hi = d1.hi - (n<0) + (d2.lod d+ ; d+ ( d1 d2 -- d ) double d_plus -#ifdef BUGGY_LONG_LONG -d.lo = d1.lo+d2.lo; -d.hi = d1.hi + d2.hi + (d.lor tuck + swap over u> r> swap - ; d- ( d1 d2 -- d ) double d_minus -#ifdef BUGGY_LONG_LONG -d.lo = d1.lo - d2.lo; -d.hi = d1.hi-d2.hi-(d1.lo>(CELL_BITS-1)); -#else -d2 = 2*d1; -#endif +d2 = DLSHIFT(d1,1); : 2dup d+ ; d2/ ( d1 -- d2 ) double d_two_slash ""Arithmetic shift right by 1. For signed numbers this is a floored division by 2."" -#ifdef BUGGY_LONG_LONG -d2.hi = d1.hi>>1; -d2.lo= (d1.lo>>1) | (d1.hi<<(CELL_BITS-1)); +#ifdef BUGGY_LL_SHIFT +DHI_IS(d2, DHI(d1)>>1); +DLO_IS(d2, (DLO(d1)>>1) | (DHI(d1)<<(CELL_BITS-1))); #else d2 = d1>>1; #endif @@ -930,12 +1042,20 @@ w2 = ~w1; rshift ( u1 n -- u2 ) core r_shift ""Logical shift right by @i{n} bits."" - u2 = u1>>n; +#ifdef BROKEN_SHIFT + u2 = rshift(u1, n); +#else + u2 = u1 >> n; +#endif : 0 ?DO 2/ MAXI and LOOP ; lshift ( u1 n -- u2 ) core l_shift - u2 = u1< ( $2 -- f ) $7 $3not_equals -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_CMP f = FLAG($4.lo!=$5.lo || $4.hi!=$5.hi); #else f = FLAG($4!=$5); #endif $1< ( $2 -- f ) $8 $3less_than -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_CMP f = FLAG($4.hi==$5.hi ? $4.lo<$5.lo : $4.hi<$5.hi); #else f = FLAG($4<$5); #endif $1> ( $2 -- f ) $9 $3greater_than -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_CMP f = FLAG($4.hi==$5.hi ? $4.lo>$5.lo : $4.hi>$5.hi); #else f = FLAG($4>$5); #endif $1<= ( $2 -- f ) gforth $3less_or_equal -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_CMP f = FLAG($4.hi==$5.hi ? $4.lo<=$5.lo : $4.hi<=$5.hi); #else f = FLAG($4<=$5); #endif $1>= ( $2 -- f ) gforth $3greater_or_equal -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_CMP f = FLAG($4.hi==$5.hi ? $4.lo>=$5.lo : $4.hi>=$5.hi); #else f = FLAG($4>=$5); @@ -1068,17 +1188,16 @@ useraddr ( #u -- a_addr ) new a_addr = (Cell *)(up+u); up! ( a_addr -- ) gforth up_store -UP=up=(char *)a_addr; +gforth_UP=up=(Address)a_addr; : up ! ; Variable UP -sp@ ( -- a_addr ) gforth sp_fetch -a_addr = sp+1; +sp@ ( S:... -- a_addr ) gforth sp_fetch +a_addr = sp; -sp! ( a_addr -- ) gforth sp_store +sp! ( a_addr -- S:... ) gforth sp_store sp = a_addr; -/* works with and without spTOS caching */ rp@ ( -- a_addr ) gforth rp_fetch a_addr = rp; @@ -1088,10 +1207,10 @@ rp = a_addr; \+floating -fp@ ( -- f_addr ) gforth fp_fetch +fp@ ( f:... -- f_addr ) gforth fp_fetch f_addr = fp; -fp! ( f_addr -- ) gforth fp_store +fp! ( f_addr -- f:... ) gforth fp_store fp = f_addr; \+ @@ -1110,19 +1229,19 @@ rdrop ( R:w -- ) gforth : r> r> drop >r ; -2>r ( w1 w2 -- R:w1 R:w2 ) core-ext two_to_r +2>r ( d -- R:d ) core-ext two_to_r : swap r> swap >r swap >r >r ; -2r> ( R:w1 R:w2 -- w1 w2 ) core-ext two_r_from +2r> ( R:d -- d ) core-ext two_r_from : r> r> swap r> swap >r swap ; -2r@ ( R:w1 R:w2 -- R:w1 R:w2 w1 w2 ) core-ext two_r_fetch +2r@ ( R:d -- R:d d ) core-ext two_r_fetch : i' j ; -2rdrop ( R:w1 R:w2 -- ) gforth two_r_drop +2rdrop ( R:d -- ) gforth two_r_drop : r> r> drop r> drop >r ; @@ -1164,21 +1283,18 @@ tuck ( w1 w2 -- w2 w1 w2 ) core-ext : swap over ; -?dup ( w -- w ) core question_dupe +?dup ( w -- S:... w ) core question_dupe ""Actually the stack effect is: @code{( w -- 0 | w w )}. It performs a @code{dup} if w is nonzero."" if (w!=0) { - IF_spTOS(*sp-- = w;) -#ifndef USE_TOS *--sp = w; -#endif } : dup IF dup THEN ; -pick ( u -- w ) core-ext +pick ( S:... u -- S:... w ) core-ext ""Actually the stack effect is @code{ x0 ... xu u -- x0 ... xu x0 }."" -w = sp[u+1]; +w = sp[u]; : 1+ cells sp@ + @ ; @@ -1342,12 +1458,40 @@ c_addr2 = c_addr1+1; \g compiler -(listlfind) ( c_addr u longname1 -- longname2 ) new paren_listlfind -for (; longname1 != NULL; longname1 = (struct Longname *)(longname1->next)) - if ((UCell)LONGNAME_COUNT(longname1)==u && - memcasecmp(c_addr, longname1->name, u)== 0 /* or inline? */) +\+f83headerstring + +(f83find) ( c_addr u f83name1 -- f83name2 ) new paren_f83find +for (; f83name1 != NULL; f83name1 = (struct F83Name *)(f83name1->next)) + if ((UCell)F83NAME_COUNT(f83name1)==u && + memcasecmp(c_addr, f83name1->name, u)== 0 /* or inline? */) break; -longname2=longname1; +f83name2=f83name1; +#ifdef DEBUG +fprintf(stderr, "F83find "); +fwrite(c_addr, u, 1, stderr); +fprintf(stderr, " found %08x\n", f83name2); +#endif +: + BEGIN dup WHILE (find-samelen) dup WHILE + >r 2dup r@ cell+ char+ capscomp 0= + IF 2drop r> EXIT THEN + r> @ + REPEAT THEN nip nip ; +: (find-samelen) ( u f83name1 -- u f83name2/0 ) + BEGIN 2dup cell+ c@ $1F and <> WHILE @ dup 0= UNTIL THEN ; +: capscomp ( c_addr1 u c_addr2 -- n ) + swap bounds + ?DO dup c@ I c@ <> + IF dup c@ toupper I c@ toupper = + ELSE true THEN WHILE 1+ LOOP drop 0 + ELSE c@ toupper I c@ toupper - unloop THEN sgn ; +: sgn ( n -- -1/0/1 ) + dup 0= IF EXIT THEN 0< 2* 1+ ; + +\- + +(listlfind) ( c_addr u longname1 -- longname2 ) new paren_listlfind +longname2=listlfind(c_addr, u, longname1); : BEGIN dup WHILE (findl-samelen) dup WHILE >r 2dup r@ cell+ cell+ capscomp 0= @@ -1356,23 +1500,19 @@ longname2=longname1; REPEAT THEN nip nip ; : (findl-samelen) ( u longname1 -- u longname2/0 ) BEGIN 2dup cell+ @ lcount-mask and <> WHILE @ dup 0= UNTIL THEN ; +: capscomp ( c_addr1 u c_addr2 -- n ) + swap bounds + ?DO dup c@ I c@ <> + IF dup c@ toupper I c@ toupper = + ELSE true THEN WHILE 1+ LOOP drop 0 + ELSE c@ toupper I c@ toupper - unloop THEN sgn ; +: sgn ( n -- -1/0/1 ) + dup 0= IF EXIT THEN 0< 2* 1+ ; \+hash (hashlfind) ( c_addr u a_addr -- longname2 ) new paren_hashlfind -struct Longname *longname1; -longname2=NULL; -while(a_addr != NULL) -{ - longname1=(struct Longname *)(a_addr[1]); - a_addr=(Cell *)(a_addr[0]); - if ((UCell)LONGNAME_COUNT(longname1)==u && - memcasecmp(c_addr, longname1->name, u)== 0 /* or inline? */) - { - longname2=longname1; - break; - } -} +longname2 = hashlfind(c_addr, u, a_addr); : BEGIN dup WHILE 2@ >r >r dup r@ cell+ @ lcount-mask and = @@ -1383,19 +1523,7 @@ while(a_addr != NULL) (tablelfind) ( c_addr u a_addr -- longname2 ) new paren_tablelfind ""A case-sensitive variant of @code{(hashfind)}"" -struct Longname *longname1; -longname2=NULL; -while(a_addr != NULL) -{ - longname1=(struct Longname *)(a_addr[1]); - a_addr=(Cell *)(a_addr[0]); - if ((UCell)LONGNAME_COUNT(longname1)==u && - memcmp(c_addr, longname1->name, u)== 0 /* or inline? */) - { - longname2=longname1; - break; - } -} +longname2 = tablelfind(c_addr, u, a_addr); : BEGIN dup WHILE 2@ >r >r dup r@ cell+ @ lcount-mask and = @@ -1403,29 +1531,16 @@ while(a_addr != NULL) IF 2drop r> rdrop EXIT THEN THEN rdrop r> REPEAT nip nip ; - -(hashkey) ( c_addr u1 -- u2 ) gforth paren_hashkey -u2=0; -while(u1--) - u2+=(Cell)toupper(*c_addr++); -: - 0 -rot bounds ?DO I c@ toupper + LOOP ; +: -text ( c_addr1 u c_addr2 -- n ) + swap bounds + ?DO dup c@ I c@ = WHILE 1+ LOOP drop 0 + ELSE c@ I c@ - unloop THEN sgn ; +: sgn ( n -- -1/0/1 ) + dup 0= IF EXIT THEN 0< 2* 1+ ; (hashkey1) ( c_addr u ubits -- ukey ) gforth paren_hashkey1 ""ukey is the hash key for the string c_addr u fitting in ubits bits"" -/* this hash function rotates the key at every step by rot bits within - ubits bits and xors it with the character. This function does ok in - the chi-sqare-test. Rot should be <=7 (preferably <=5) for - ASCII strings (larger if ubits is large), and should share no - divisors with ubits. -*/ -static char rot_values[] = {5,0,1,2,3,4,5,5,5,5,3,5,5,5,5,7,5,5,5,5,7,5,5,5,5,6,5,5,5,5,7,5,5}; -unsigned rot = rot_values[ubits]; -Char *cp = c_addr; -for (ukey=0; cp>(ubits-rot))) - ^ toupper(*cp)) - & ((1<r tuck - 2swap r> 0 2swap bounds @@ -1441,20 +1556,12 @@ Create rot-values \+ +\+ + (parse-white) ( c_addr1 u1 -- c_addr2 u2 ) gforth paren_parse_white -/* use !isgraph instead of isspace? */ -Char *endp = c_addr1+u1; -while (c_addr1body ( xt -- a_addr ) core to_body -"" Get the address of the body of the word represented by @i{xt} (the address -of the word's data field)."" -a_addr = PFA(xt); -: - 2 cells + ; - \ threading stuff is currently only interesting if we have a compiler \fhas? standardthreading has? compiler and [IF] - ->code-address ( xt -- c_addr ) gforth to_code_address -""@i{c-addr} is the code address of the word @i{xt}."" -/* !! This behaves installation-dependently for DOES-words */ -c_addr = (Address)CODE_ADDRESS(xt); -: - @ ; - ->does-code ( xt -- a_addr ) gforth to_does_code -""If @i{xt} is the execution token of a child of a @code{DOES>} word, -@i{a-addr} is the start of the Forth code after the @code{DOES>}; -Otherwise @i{a-addr} is 0."" -a_addr = (Cell *)DOES_CODE(xt); -: - cell+ @ ; - -code-address! ( c_addr xt -- ) gforth code_address_store -""Create a code field with code address @i{c-addr} at @i{xt}."" -MAKE_CF(xt, c_addr); -: - ! ; - -does-code! ( a_addr xt -- ) gforth does_code_store -""Create a code field at @i{xt} for a child of a @code{DOES>}-word; -@i{a-addr} is the start of the Forth code after @code{DOES>}."" -MAKE_DOES_CF(xt, a_addr); -: - dodoes: over ! cell+ ! ; - -does-handler! ( a_addr -- ) gforth does_handler_store -""Create a @code{DOES>}-handler at address @i{a-addr}. Normally, -@i{a-addr} points just behind a @code{DOES>}."" -MAKE_DOES_HANDLER(a_addr); -: - drop ; - -/does-handler ( -- n ) gforth slash_does_handler -""The size of a @code{DOES>}-handler (includes possible padding)."" -/* !! a constant or environmental query might be better */ -n = DOES_HANDLER_SIZE; -: - 2 cells ; - threading-method ( -- n ) gforth threading_method ""0 if the engine is direct threaded. Note that this may change during the lifetime of an image."" @@ -1544,41 +1601,62 @@ n=1; \g hostos -key-file ( wfileid -- n ) gforth paren_key_file +key-file ( wfileid -- c ) gforth paren_key_file +""Read one character @i{c} from @i{wfileid}. This word disables +buffering for @i{wfileid}. If you want to read characters from a +terminal in non-canonical (raw) mode, you have to put the terminal in +non-canonical mode yourself (using the C interface); the exception is +@code{stdin}: Gforth automatically puts it into non-canonical mode."" #ifdef HAS_FILE fflush(stdout); -n = key((FILE*)wfileid); +c = key((FILE*)wfileid); #else -n = key(stdin); +c = key(stdin); #endif -key?-file ( wfileid -- n ) facility key_q_file +key?-file ( wfileid -- f ) gforth key_q_file +""@i{f} is true if at least one character can be read from @i{wfileid} +without blocking. If you also want to use @code{read-file} or +@code{read-line} on the file, you have to call @code{key?-file} or +@code{key-file} first (these two words disable buffering)."" #ifdef HAS_FILE fflush(stdout); -n = key_query((FILE*)wfileid); +f = key_query((FILE*)wfileid); #else -n = key_query(stdin); +f = key_query(stdin); #endif -\+os - stdin ( -- wfileid ) gforth +""The standard input file of the Gforth process."" wfileid = (Cell)stdin; stdout ( -- wfileid ) gforth +""The standard output file of the Gforth process."" wfileid = (Cell)stdout; stderr ( -- wfileid ) gforth +""The standard error output file of the Gforth process."" wfileid = (Cell)stderr; +\+os + form ( -- urows ucols ) gforth -""The number of lines and columns in the terminal. These numbers may change -with the window size."" +""The number of lines and columns in the terminal. These numbers may +change with the window size. Note that it depends on the OS whether +this reflects the actual size and changes with the window size +(currently only on Unix-like OSs). On other OSs you just get a +default, and can tell Gforth the terminal size by setting the +environment variables @code{COLUMNS} and @code{LINES} before starting +Gforth."" /* we could block SIGWINCH here to get a consistent size, but I don't think this is necessary or always beneficial */ urows=rows; ucols=cols; +wcwidth ( u -- n ) gforth +""The number of fixed-width characters per unicode character u"" +n = wcwidth(u); + flush-icache ( c_addr u -- ) gforth flush_icache ""Make sure that the instruction cache of the processor (if there is one) does not contain stale data at @i{c-addr} and @i{u} bytes @@ -1595,17 +1673,9 @@ FLUSH_ICACHE(c_addr,u); SUPER_END; return (Label *)n; -(system) ( c_addr u -- wretval wior ) gforth peren_system -#ifndef MSDOS -int old_tp=terminal_prepped; -deprep_terminal(); -#endif -wretval=system(cstr(c_addr,u,1)); /* ~ expansion on first part of string? */ +(system) ( c_addr u -- wretval wior ) gforth paren_system +wretval = gforth_system(c_addr, u); wior = IOR(wretval==-1 || (wretval==127 && errno != 0)); -#ifndef MSDOS -if (old_tp) - prep_terminal(); -#endif getenv ( c_addr1 u1 -- c_addr2 u2 ) gforth ""The string @i{c-addr1 u1} specifies an environment variable. The string @i{c-addr2 u2} @@ -1613,8 +1683,8 @@ is the host operating system's expansion environment variable does not exist, @i{c-addr2 u2} specifies a string 0 characters in length."" /* close ' to keep fontify happy */ -c_addr2 = getenv(cstr(c_addr1,u1,1)); -u2 = (c_addr2 == NULL ? 0 : strlen(c_addr2)); +c_addr2 = (Char *)getenv(cstr(c_addr1,u1,1)); +u2 = (c_addr2 == NULL ? 0 : strlen((char *)c_addr2)); open-pipe ( c_addr u wfam -- wfileid wior ) gforth open_pipe wfileid=(Cell)popen(cstr(c_addr,u,1),pfileattr[wfam]); /* ~ expansion of 1st arg? */ @@ -1627,6 +1697,12 @@ wior = IOR(wretval==-1); time&date ( -- nsec nmin nhour nday nmonth nyear ) facility-ext time_and_date ""Report the current time of day. Seconds, minutes and hours are numbered from 0. Months are numbered from 1."" +#if 1 +time_t now; +struct tm *ltime; +time(&now); +ltime=localtime(&now); +#else struct timeval time1; struct timezone zone1; struct tm *ltime; @@ -1634,6 +1710,7 @@ gettimeofday(&time1,&zone1); /* !! Single Unix specification: If tzp is not a null pointer, the behaviour is unspecified. */ ltime=localtime((time_t *)&time1.tv_sec); +#endif nyear =ltime->tm_year+1900; nmonth=ltime->tm_mon+1; nday =ltime->tm_mday; @@ -1641,12 +1718,9 @@ nhour =ltime->tm_hour; nmin =ltime->tm_min; nsec =ltime->tm_sec; -ms ( n -- ) facility-ext +ms ( u -- ) facility-ext ""Wait at least @i{n} milli-second."" -struct timeval timeout; -timeout.tv_sec=n/1000; -timeout.tv_usec=1000*(n%1000); -(void)select(0,0,0,0,&timeout); +gforth_ms(u); allocate ( u -- a_addr wior ) memory ""Allocate @i{u} address units of contiguous data space. The initial @@ -1683,27 +1757,24 @@ else wior = IOR(a_addr2==NULL); /* !! Define a return code */ strerror ( n -- c_addr u ) gforth -c_addr = strerror(n); -u = strlen(c_addr); +c_addr = (Char *)strerror(n); +u = strlen((char *)c_addr); strsignal ( n -- c_addr u ) gforth -c_addr = strsignal(n); -u = strlen(c_addr); +c_addr = (Char *)strsignal(n); +u = strlen((char *)c_addr); -call-c ( w -- ) gforth call_c +call-c ( ... w -- ... ) gforth call_c ""Call the C function pointed to by @i{w}. The C function has to access the stack itself. The stack pointers are exported in the global -variables @code{SP} and @code{FP}."" +variables @code{gforth_SP} and @code{gforth_FP}."" /* This is a first attempt at support for calls to C. This may change in the future */ -IF_fpTOS(fp[0]=fpTOS); -FP=fp; -SP=sp; +gforth_FP=fp; +gforth_SP=sp; ((void (*)())w)(); -sp=SP; -fp=FP; -IF_spTOS(spTOS=sp[0]); -IF_fpTOS(fpTOS=fp[0]); +sp=gforth_SP; +fp=gforth_FP; \+ \+file @@ -1731,8 +1802,7 @@ wior = IOR(unlink(tilde_cstr(c_addr, u, rename-file ( c_addr1 u1 c_addr2 u2 -- wior ) file-ext rename_file ""Rename file @i{c_addr1 u1} to new name @i{c_addr2 u2}"" -char *s1=tilde_cstr(c_addr2, u2, 1); -wior = IOR(rename(tilde_cstr(c_addr1, u1, 0), s1)==-1); +wior = rename_file(c_addr1, u1, c_addr2, u2); file-position ( wfileid -- ud wior ) file file_position /* !! use tell and lseek? */ @@ -1758,29 +1828,12 @@ wior = FILEIO(u2d_name); + u2 = strlen((char *)dent->d_name); if(u2 > u1) { u2 = u1; wior = -512-ENAMETOOLONG; @@ -1881,6 +1915,21 @@ char * string = cstr(c_addr1, u1, 1); char * pattern = cstr(c_addr2, u2, 0); flag = FLAG(!fnmatch(pattern, string, 0)); +set-dir ( c_addr u -- wior ) gforth set_dir +""Change the current directory to @i{c-addr, u}. +Return an error if this is not possible"" +wior = IOR(chdir(tilde_cstr(c_addr, u, 1))); + +get-dir ( c_addr1 u1 -- c_addr2 u2 ) gforth get_dir +""Store the current directory in the buffer specified by @{c-addr1, u1}. +If the buffer size is not sufficient, return 0 0"" +c_addr2 = (Char *)getcwd((char *)c_addr1, u1); +if(c_addr2 != NULL) { + u2 = strlen((char *)c_addr2); +} else { + u2 = 0; +} + \+ newline ( -- c_addr u ) gforth @@ -1894,7 +1943,7 @@ char newline[] = { '\r','\n' #endif }; -c_addr=newline; +c_addr=(Char *)newline; u=sizeof(newline); : "newline count ; @@ -1923,11 +1972,7 @@ dsystem = timeval2us(&usage.ru_stime); struct timeval time1; gettimeofday(&time1,NULL); duser = timeval2us(&time1); -#ifndef BUGGY_LONG_LONG -dsystem = (DCell)0; -#else -dsystem=(DCell){0,0}; -#endif +dsystem = DZERO; #endif \+ @@ -1939,14 +1984,21 @@ dsystem=(DCell){0,0}; comparisons(f, r1 r2, f_, r1, r2, gforth, gforth, float, gforth) comparisons(f0, r, f_zero_, r, 0., float, gforth, float, gforth) +s>f ( n -- r ) float s_to_f +r = n; + d>f ( d -- r ) float d_to_f -#ifdef BUGGY_LONG_LONG +#ifdef BUGGY_LL_D2F extern double ldexp(double x, int exp); -if (d.hi<0) { +if (DHI(d)<0) { +#ifdef BUGGY_LL_ADD DCell d2=dnegate(d); - r = -(ldexp((Float)d2.hi,CELL_BITS) + (Float)d2.lo); +#else + DCell d2=-d; +#endif + r = -(ldexp((Float)DHI(d2),CELL_BITS) + (Float)DLO(d2)); } else - r = ldexp((Float)d.hi,CELL_BITS) + (Float)d.lo; + r = ldexp((Float)DHI(d),CELL_BITS) + (Float)DLO(d); #else r = d; #endif @@ -1955,6 +2007,9 @@ f>d ( r -- d ) float f_to_d extern DCell double2ll(Float r); d = double2ll(r); +f>s ( r -- n ) float f_to_s +n = (Cell)r; + f! ( r f_addr -- ) float f_store ""Store @i{r} into the float at address @i{f-addr}."" *f_addr = r; @@ -2013,6 +2068,18 @@ f** ( r1 r2 -- r3 ) float-ext f_star_sta ""@i{r3} is @i{r1} raised to the @i{r2}th power."" r3 = pow(r1,r2); +fm* ( r1 n -- r2 ) gforth fm_star +r2 = r1*n; + +fm/ ( r1 n -- r2 ) gforth fm_slash +r2 = r1/n; + +fm*/ ( r1 n1 n2 -- r2 ) gforth fm_star_slash +r2 = (r1*n1)/n2; + +f**2 ( r1 -- r2 ) gforth fm_square +r2 = r1*r1; + fnegate ( r1 -- r2 ) float f_negate r2 = - r1; @@ -2061,58 +2128,34 @@ else represent ( r c_addr u -- n f1 f2 ) float char *sig; +size_t siglen; int flag; int decpt; sig=ecvt(r, u, &decpt, &flag); -n=(r==0 ? 1 : decpt); +n=(r==0. ? 1 : decpt); f1=FLAG(flag!=0); f2=FLAG(isdigit((unsigned)(sig[0]))!=0); -memmove(c_addr,sig,u); +siglen=strlen((char *)sig); +if (siglen>u) /* happens in glibc-2.1.3 if 999.. is rounded up */ + siglen=u; +if (!f2) /* workaround Cygwin trailing 0s for Inf and Nan */ + for (; sig[siglen-1]=='0'; siglen--); + ; +memcpy(c_addr,sig,siglen); +memset(c_addr+siglen,f2?'0':' ',u-siglen); ->float ( c_addr u -- flag ) float to_float +>float ( c_addr u -- f:... flag ) float to_float ""Actual stack effect: ( c_addr u -- r t | f ). Attempt to convert the character string @i{c-addr u} to internal floating-point representation. If the string represents a valid floating-point number @i{r} is placed on the floating-point stack and @i{flag} is true. Otherwise, @i{flag} is false. A string of blanks is a special case and represents the floating-point number 0."" -/* real signature: c_addr u -- r t / f */ Float r; -char *number=cstr(c_addr, u, 1); -char *endconv; -int sign = 0; -if(number[0]=='-') { - sign = 1; - number++; - u--; -} -while(isspace((unsigned)(number[--u])) && u>0); -switch(number[u]) -{ - case 'd': - case 'D': - case 'e': - case 'E': break; - default : u++; break; -} -number[u]='\0'; -r=strtod(number,&endconv); -if((flag=FLAG(!(Cell)*endconv))) -{ - IF_fpTOS(fp[0] = fpTOS); - fp += -1; - fpTOS = sign ? -r : r; -} -else if(*endconv=='d' || *endconv=='D') -{ - *endconv='E'; - r=strtod(number,&endconv); - if((flag=FLAG(!(Cell)*endconv))) - { - IF_fpTOS(fp[0] = fpTOS); - fp += -1; - fpTOS = sign ? -r : r; - } +flag = to_float(c_addr, u, &r); +if (flag) { + fp--; + fp[0]=r; } fabs ( r1 -- r2 ) float-ext f_abs @@ -2251,11 +2294,7 @@ v* ( f_addr1 nstride1 f_addr2 nstride2 u ""dot-product: r=v1*v2. The first element of v1 is at f_addr1, the next at f_addr1+nstride1 and so on (similar for v2). Both vectors have ucount elements."" -for (r=0.; ucount>0; ucount--) { - r += *f_addr1 * *f_addr2; - f_addr1 = (Float *)(((Address)f_addr1)+nstride1); - f_addr2 = (Float *)(((Address)f_addr2)+nstride2); -} +r = v_star(f_addr1, nstride1, f_addr2, nstride2, ucount); : >r swap 2swap swap 0e r> 0 ?DO dup f@ over + 2swap dup f@ f* f+ over + 2swap @@ -2263,11 +2302,7 @@ for (r=0.; ucount>0; ucount--) { faxpy ( ra f_x nstridex f_y nstridey ucount -- ) gforth ""vy=ra*vx+vy"" -for (; ucount>0; ucount--) { - *f_y += ra * *f_x; - f_x = (Float *)(((Address)f_x)+nstridex); - f_y = (Float *)(((Address)f_y)+nstridey); -} +faxpy(ra, f_x, nstridex, f_y, nstridey, ucount); : >r swap 2swap swap r> 0 ?DO fdup dup f@ f* over + 2swap dup f@ f+ dup f! over + 2swap @@ -2346,9 +2381,9 @@ f>l ( r -- ) gforth f_to_l lp -= sizeof(Float); *(Float *)lp = r; -fpick ( u -- r ) gforth +fpick ( f:... u -- f:... r ) gforth ""Actually the stack effect is @code{ r0 ... ru u -- r0 ... ru r0 }."" -r = fp[u+1]; /* +1, because update of fp happens before this fragment */ +r = fp[u]; : floats fp@ + f@ ; @@ -2359,37 +2394,6 @@ r = fp[u+1]; /* +1, because update of fp \g syslib -define(`uploop', - `pushdef(`$1', `$2')_uploop(`$1', `$2', `$3', `$4', `$5')`'popdef(`$1')') -define(`_uploop', - `ifelse($1, `$3', `$5', - `$4`'define(`$1', incr($1))_uploop(`$1', `$2', `$3', `$4', `$5')')') -\ argflist(argnum): Forth argument list -define(argflist, - `ifelse($1, 0, `', - `uploop(`_i', 1, $1, `format(`u%d ', _i)', `format(`u%d ', _i)')')') -\ argdlist(argnum): declare C's arguments -define(argdlist, - `ifelse($1, 0, `', - `uploop(`_i', 1, $1, `Cell, ', `Cell')')') -\ argclist(argnum): pass C's arguments -define(argclist, - `ifelse($1, 0, `', - `uploop(`_i', 1, $1, `format(`u%d, ', _i)', `format(`u%d', _i)')')') -\ icall(argnum) -define(icall, -`icall$1 ( argflist($1)u -- uret ) gforth -uret = (SYSCALL(Cell(*)(argdlist($1)))u)(argclist($1)); - -') -define(fcall, -`fcall$1 ( argflist($1)u -- rret ) gforth -rret = (SYSCALL(Float(*)(argdlist($1)))u)(argclist($1)); - -') - -\ close ' to keep fontify happy - open-lib ( c_addr1 u1 -- u2 ) gforth open_lib #if defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) #ifndef RTLD_GLOBAL @@ -2417,43 +2421,389 @@ u3 = 0; # endif #endif +wcall ( ... u -- ... ) gforth +gforth_FP=fp; +sp=(Cell*)(SYSCALL(Cell*(*)(Cell *, void *))u)(sp, &gforth_FP); +fp=gforth_FP; + +uw@ ( c_addr -- u ) gforth u_w_fetch +""@i{u} is the zero-extended 16-bit value stored at @i{c_addr}."" +u = *(UWyde*)(c_addr); + +sw@ ( c_addr -- n ) gforth s_w_fetch +""@i{n} is the sign-extended 16-bit value stored at @i{c_addr}."" +n = *(Wyde*)(c_addr); + +w! ( w c_addr -- ) gforth w_store +""Store the bottom 16 bits of @i{w} at @i{c_addr}."" +*(Wyde*)(c_addr) = w; + +ul@ ( c_addr -- u ) gforth u_l_fetch +""@i{u} is the zero-extended 32-bit value stored at @i{c_addr}."" +u = *(UTetrabyte*)(c_addr); + +sl@ ( c_addr -- n ) gforth s_l_fetch +""@i{n} is the sign-extended 32-bit value stored at @i{c_addr}."" +n = *(Tetrabyte*)(c_addr); + +l! ( w c_addr -- ) gforth l_store +""Store the bottom 32 bits of @i{w} at @i{c_addr}."" +*(Tetrabyte*)(c_addr) = w; + +\+FFCALL + +av-start-void ( c_addr -- ) gforth av_start_void +av_start_void(alist, c_addr); + +av-start-int ( c_addr -- ) gforth av_start_int +av_start_int(alist, c_addr, &irv); + +av-start-float ( c_addr -- ) gforth av_start_float +av_start_float(alist, c_addr, &frv); + +av-start-double ( c_addr -- ) gforth av_start_double +av_start_double(alist, c_addr, &drv); + +av-start-longlong ( c_addr -- ) gforth av_start_longlong +av_start_longlong(alist, c_addr, &llrv); + +av-start-ptr ( c_addr -- ) gforth av_start_ptr +av_start_ptr(alist, c_addr, void*, &prv); + +av-int ( w -- ) gforth av_int +av_int(alist, w); + +av-float ( r -- ) gforth av_float +av_float(alist, r); + +av-double ( r -- ) gforth av_double +av_double(alist, r); + +av-longlong ( d -- ) gforth av_longlong +#ifdef BUGGY_LL_SIZE +av_longlong(alist, DLO(d)); +#else +av_longlong(alist, d); +#endif + +av-ptr ( c_addr -- ) gforth av_ptr +av_ptr(alist, void*, c_addr); + +av-int-r ( R:w -- ) gforth av_int_r +av_int(alist, w); + +av-float-r ( -- ) gforth av_float_r +float r = *(Float*)lp; +lp += sizeof(Float); +av_float(alist, r); + +av-double-r ( -- ) gforth av_double_r +double r = *(Float*)lp; +lp += sizeof(Float); +av_double(alist, r); + +av-longlong-r ( R:d -- ) gforth av_longlong_r +#ifdef BUGGY_LL_SIZE +av_longlong(alist, DLO(d)); +#else +av_longlong(alist, d); +#endif + +av-ptr-r ( R:c_addr -- ) gforth av_ptr_r +av_ptr(alist, void*, c_addr); + +av-call-void ( ... -- ... ) gforth av_call_void +SAVE_REGS +av_call(alist); +REST_REGS + +av-call-int ( ... -- ... w ) gforth av_call_int +SAVE_REGS +av_call(alist); +REST_REGS +w = irv; + +av-call-float ( ... -- ... r ) gforth av_call_float +SAVE_REGS +av_call(alist); +REST_REGS +r = frv; + +av-call-double ( ... -- ... r ) gforth av_call_double +SAVE_REGS +av_call(alist); +REST_REGS +r = drv; + +av-call-longlong ( ... -- ... d ) gforth av_call_longlong +SAVE_REGS +av_call(alist); +REST_REGS +#ifdef BUGGY_LONG_LONG +DLO_IS(d, llrv); +DHI_IS(d, 0); +#else +d = llrv; +#endif + +av-call-ptr ( ... -- ... c_addr ) gforth av_call_ptr +SAVE_REGS +av_call(alist); +REST_REGS +c_addr = prv; + +alloc-callback ( a_ip -- c_addr ) gforth alloc_callback +c_addr = (char *)alloc_callback(gforth_callback, (Xt *)a_ip); + +va-start-void ( -- ) gforth va_start_void +va_start_void(gforth_clist); + +va-start-int ( -- ) gforth va_start_int +va_start_int(gforth_clist); + +va-start-longlong ( -- ) gforth va_start_longlong +va_start_longlong(gforth_clist); + +va-start-ptr ( -- ) gforth va_start_ptr +va_start_ptr(gforth_clist, (char *)); + +va-start-float ( -- ) gforth va_start_float +va_start_float(gforth_clist); + +va-start-double ( -- ) gforth va_start_double +va_start_double(gforth_clist); + +va-arg-int ( -- w ) gforth va_arg_int +w = va_arg_int(gforth_clist); + +va-arg-longlong ( -- d ) gforth va_arg_longlong +#ifdef BUGGY_LONG_LONG +DLO_IS(d, va_arg_longlong(gforth_clist)); +DHI_IS(d, 0); +#else +d = va_arg_longlong(gforth_clist); +#endif + +va-arg-ptr ( -- c_addr ) gforth va_arg_ptr +c_addr = (char *)va_arg_ptr(gforth_clist,char*); + +va-arg-float ( -- r ) gforth va_arg_float +r = va_arg_float(gforth_clist); + +va-arg-double ( -- r ) gforth va_arg_double +r = va_arg_double(gforth_clist); + +va-return-void ( -- ) gforth va_return_void +va_return_void(gforth_clist); +return 0; + +va-return-int ( w -- ) gforth va_return_int +va_return_int(gforth_clist, w); +return 0; + +va-return-ptr ( c_addr -- ) gforth va_return_ptr +va_return_ptr(gforth_clist, void *, c_addr); +return 0; + +va-return-longlong ( d -- ) gforth va_return_longlong +#ifdef BUGGY_LONG_LONG +va_return_longlong(gforth_clist, d.lo); +#else +va_return_longlong(gforth_clist, d); +#endif +return 0; + +va-return-float ( r -- ) gforth va_return_float +va_return_float(gforth_clist, r); +return 0; + +va-return-double ( r -- ) gforth va_return_double +va_return_double(gforth_clist, r); +return 0; + +\+ + +\+LIBFFI + +ffi-type ( n -- a_type ) gforth ffi_type +static void* ffi_types[] = + { &ffi_type_void, + &ffi_type_uint8, &ffi_type_sint8, + &ffi_type_uint16, &ffi_type_sint16, + &ffi_type_uint32, &ffi_type_sint32, + &ffi_type_uint64, &ffi_type_sint64, + &ffi_type_float, &ffi_type_double, &ffi_type_longdouble, + &ffi_type_pointer }; +a_type = ffi_types[n]; + +ffi-size ( n1 -- n2 ) gforth ffi_size +static int ffi_sizes[] = + { sizeof(ffi_cif), sizeof(ffi_closure) }; +n2 = ffi_sizes[n1]; + +ffi-prep-cif ( a_atypes n a_rtype a_cif -- w ) gforth ffi_prep_cif +w = ffi_prep_cif((ffi_cif *)a_cif, FFI_DEFAULT_ABI, n, + (ffi_type *)a_rtype, (ffi_type **)a_atypes); + +ffi-call ( a_avalues a_rvalue a_ip a_cif -- ) gforth ffi_call +SAVE_REGS +ffi_call((ffi_cif *)a_cif, (void(*)())a_ip, (void *)a_rvalue, (void **)a_avalues); +REST_REGS + +ffi-prep-closure ( a_ip a_cif a_closure -- w ) gforth ffi_prep_closure +w = ffi_prep_closure((ffi_closure *)a_closure, (ffi_cif *)a_cif, gforth_callback, (void *)a_ip); + +ffi-2@ ( a_addr -- d ) gforth ffi_2fetch +#ifdef BUGGY_LONG_LONG +DLO_IS(d, *(Cell*)(*a_addr)); +DHI_IS(d, 0); +#else +d = *(DCell*)(a_addr); +#endif + +ffi-2! ( d a_addr -- ) gforth ffi_2store +#ifdef BUGGY_LONG_LONG +*(Cell*)(a_addr) = DLO(d); +#else +*(DCell*)(a_addr) = d; +#endif + +ffi-arg-int ( -- w ) gforth ffi_arg_int +w = *(int *)(*gforth_clist++); + +ffi-arg-long ( -- w ) gforth ffi_arg_long +w = *(long *)(*gforth_clist++); + +ffi-arg-longlong ( -- d ) gforth ffi_arg_longlong +#ifdef BUGGY_LONG_LONG +DLO_IS(d, *(Cell*)(*gforth_clist++)); +DHI_IS(d, -(*(Cell*)(*gforth_clist++)<0)); +#else +d = *(DCell*)(*gforth_clist++); +#endif + +ffi-arg-dlong ( -- d ) gforth ffi_arg_dlong +#ifdef BUGGY_LONG_LONG +DLO_IS(d, *(Cell*)(*gforth_clist++)); +DHI_IS(d, -(*(Cell*)(*gforth_clist++)<0)); +#else +d = *(Cell*)(*gforth_clist++); +#endif + +ffi-arg-ptr ( -- c_addr ) gforth ffi_arg_ptr +c_addr = *(Char **)(*gforth_clist++); + +ffi-arg-float ( -- r ) gforth ffi_arg_float +r = *(float*)(*gforth_clist++); + +ffi-arg-double ( -- r ) gforth ffi_arg_double +r = *(double*)(*gforth_clist++); + +ffi-ret-void ( -- ) gforth ffi_ret_void +return 0; + +ffi-ret-int ( w -- ) gforth ffi_ret_int +*(int*)(gforth_ritem) = w; +return 0; + +ffi-ret-longlong ( d -- ) gforth ffi_ret_longlong +#ifdef BUGGY_LONG_LONG +*(Cell*)(gforth_ritem) = DLO(d); +#else +*(DCell*)(gforth_ritem) = d; +#endif +return 0; + +ffi-ret-dlong ( d -- ) gforth ffi_ret_dlong +#ifdef BUGGY_LONG_LONG +*(Cell*)(gforth_ritem) = DLO(d); +#else +*(Cell*)(gforth_ritem) = d; +#endif +return 0; + +ffi-ret-long ( n -- ) gforth ffi_ret_long +*(Cell*)(gforth_ritem) = n; +return 0; + +ffi-ret-ptr ( c_addr -- ) gforth ffi_ret_ptr +*(Char **)(gforth_ritem) = c_addr; +return 0; + +ffi-ret-float ( r -- ) gforth ffi_ret_float +*(float*)(gforth_ritem) = r; +return 0; + +ffi-ret-double ( r -- ) gforth ffi_ret_double +*(double*)(gforth_ritem) = r; +return 0; + +\+ + +\+OLDCALL + +define(`uploop', + `pushdef(`$1', `$2')_uploop(`$1', `$2', `$3', `$4', `$5')`'popdef(`$1')') +define(`_uploop', + `ifelse($1, `$3', `$5', + `$4`'define(`$1', incr($1))_uploop(`$1', `$2', `$3', `$4', `$5')')') + +\ argflist(argnum): Forth argument list +define(argflist, + `ifelse($1, 0, `', + `uploop(`_i', 1, $1, ``u''`_i ', ``u''`_i')')') +\ argdlist(argnum): declare C's arguments +define(argdlist, + `ifelse($1, 0, `', + `uploop(`_i', 1, $1, `Cell, ', `Cell')')') +\ argclist(argnum): pass C's arguments +define(argclist, + `ifelse($1, 0, `', + `uploop(`_i', 1, $1, ``u''`_i, ', ``u''`_i')')') +\ icall(argnum) +define(icall, +`icall$1 ( argflist($1) u -- uret ) gforth +uret = (SYSCALL(Cell(*)(argdlist($1)))u)(argclist($1)); + +') +define(fcall, +`fcall$1 ( argflist($1) u -- rret ) gforth +rret = (SYSCALL(Float(*)(argdlist($1)))u)(argclist($1)); + +') + +\ close ' to keep fontify happy + uploop(i, 0, 7, `icall(i)') icall(20) uploop(i, 0, 7, `fcall(i)') fcall(20) \+ +\+ -wcall ( u -- ) gforth -IF_fpTOS(fp[0]=fpTOS); -FP=fp; -sp=(Cell*)(SYSCALL(Cell*(*)(Cell *, void *))u)(sp, &FP); -fp=FP; -IF_spTOS(spTOS=sp[0];) -IF_fpTOS(fpTOS=fp[0]); +\g peephole \+peephole -\g peephole +compile-prim1 ( a_prim -- ) gforth compile_prim1 +""compile prim (incl. immargs) at @var{a_prim}"" +compile_prim1(a_prim); -primtable ( -- wprimtable ) new -""wprimtable is a table containing the xts of the primitives indexed -by sequence-number in prim (for use in prepare-peephole-table)."" -wprimtable = (Cell)primtable(symbols+DOESJUMP+1,MAX_SYMBOLS-DOESJUMP-1); - -prepare-peephole-table ( wprimtable -- wpeeptable ) new prepare_peephole_opt -""wpeeptable is a data structure used by @code{peephole-opt}; it is -constructed by combining a primitives table with a simple peephole -optimization table."" -wpeeptable = prepare_peephole_table((Xt *)wprimtable); - -peephole-opt ( xt1 xt2 wpeeptable -- xt ) new peephole_opt -""xt is the combination of xt1 and xt2 (according to wpeeptable); if -they cannot be combined, xt is 0."" -xt = peephole_opt(xt1, xt2, wpeeptable); +finish-code ( ... -- ... ) gforth finish_code +""Perform delayed steps in code generation (branch resolution, I-cache +flushing)."" +/* The ... above are a workaround for a bug in gcc-2.95, which fails + to save spTOS (gforth-fast --enable-force-reg) */ +finish_code(); + +forget-dyncode ( c_code -- f ) gforth-internal forget_dyncode +f = forget_dyncode(c_code); -compile-prim ( xt1 -- xt2 ) obsolete compile_prim -xt2 = (Xt)compile_prim((Label)xt1); +decompile-prim ( a_code -- a_prim ) gforth-internal decompile_prim +""a_prim is the code address of the primitive that has been +compile_prim1ed to a_code"" +a_prim = (Cell *)decompile_code((Label)a_code); \ set-next-code and call2 do not appear in images and can be \ renumbered arbitrarily @@ -2472,25 +2822,15 @@ JUMP(a_callee); assert(0); #endif -compile-prim1 ( a_prim -- ) gforth compile_prim1 -""compile prim (incl. immargs) at @var{a_prim}"" -compile_prim1(a_prim); - -finish-code ( -- ) gforth finish_code -""Perform delayed steps in code generation (branch resolution, I-cache -flushing)."" -finish_code(); - -forget-dyncode ( c_code -- f ) gforth-internal forget_dyncode -f = forget_dyncode(c_code); - -decompile-prim ( a_code -- a_prim ) gforth-internal decompile_prim -""a_prim is the code address of the primitive that has been -compile_prim1ed to a_code"" -a_prim = (Label)decompile_code((Label)a_code); +tag-offsets ( -- a_addr ) gforth tag_offsets +extern Cell groups[32]; +a_addr = groups; \+ -include(peeprules.vmg) +\g static_super + +ifdef(`STACK_CACHE_FILE', +`include(peeprules.vmg)') \g end