Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

min FORTH *and* good performance

27 views
Skip to first unread message

Ton 't Lam CRC

unread,
Jan 6, 1992, 6:25:18 AM1/6/92
to
Some time ago I asked for the minium FORTH system. It turned out
that 9 words are necessary. However the performance is likely to
be lazy. I can imagen. I started with EMIT and KEY, though.

Now as I go along I appeared to be very easy to add new words in
assembly. My question now is:
- what FORTH words need to be coded in assembly to have a good
performance.
(My estimation 30 till 50 will do.)

Now I am asking:
- How is a number (officially) compiled into a word. I.e.:
Thus how to distinguish a number from an execution address.

- In other strings I read the word POSTPONE. What is this?
How is it implemented?

Ton 't Lam
tonl@hpuamsc

Bernd Paysan

unread,
Jan 7, 1992, 12:43:39 PM1/7/92
to

In article <2746...@hpuamsa.neth.hp.com>, to...@hpuamsa.neth.hp.com

(Ton 't Lam CRC) writes:

|> - How is a number (officially) compiled into a word. I.e.:
|> Thus how to distinguish a number from an execution address.
|>

In basic words:

: LIT R> DUP CELL+ >R @ ;
: LITERAL POSTPONE LIT , ; IMMEDIATE

|> - In other strings I read the word POSTPONE. What is this?
|> How is it implemented?
|>

: COMPILE R> DUP CELL+ >R @ , ;
: POSTPONE BL WORD FIND DUP 0= IF <not found code> THEN
0< IF COMPILE COMPILE THEN , ; IMMEDIATE

COMPILE is not part of ANS-Forth and this definition here is exactly
the wrong thing, because it is rather tricky and dependent on a
threated code Forth. POSTPONE (nice word, awful name) is _not_ that what
a Forth programmer does with the things, he don't want to do (first postpone
them, and then wait...). It postpones the compile time behavior, thus it is
COMPILE for non-immediate words, and [COMPILE] for immediate.

|> - what FORTH words need to be coded in assembly to have a good
|> performance.
|> (My estimation 30 till 50 will do.)

Arithmetics:
+ - AND OR XOR CELL+ UM* UM/MOD

Stack:
DUP OVER SWAP ROT DROP

Return-Stack:
>R R> EXECUTE

Memory:
@ ! C@ C! MOVE FILL

Tests:
0= 0< < U<

Dictionary
FIND or a appropriate basic of it

Inner interpreter:
NEXT DOCOL (DOES>

Control flow:
BRANCH ?BRANCH (LOOP) (+LOOP)

If you compile words like CELLS ( DUP + for 16 Bit) by expanding macros,
these words are enough to give good performance. It is not very worth to
do much more. This is exactly in the range of 30 to 50 words (some more
will not much, some less will decrease performance). It maybe worth to
add LIT as a code word, since literals are used very often. Some people have
tricky ideas about how to realise BRANCH and ?BRANCH, and they are not slow:

: BRANCH R> DUP @ + CELL+ >R ;
: ?BRANCH 0= R> SWAP OVER @ AND + CELL+ >R ;

Mike Haas

unread,
Jan 10, 1992, 5:51:41 PM1/10/92
to
In article <1992Jan7.1...@Informatik.TU-Muenchen.DE> paz...@Informatik.TU-Muenchen.DE (Bernd Paysan) writes:
>
>In article <2746...@hpuamsa.neth.hp.com>, to...@hpuamsa.neth.hp.com
> (Ton 't Lam CRC) writes:
>
>|> - How is a number (officially) compiled into a word. I.e.:
>|> Thus how to distinguish a number from an execution address.
>|>
>
>In basic words:
>
>: LIT R> DUP CELL+ >R @ ;
>: LITERAL POSTPONE LIT , ; IMMEDIATE

This did not answer the question. In fact, the question touches on
something that is important to me as the author of JForth.

JForth includes a standalone-application generator called CLONE.
It is used thusly: CLONE <wordname>

This creates an entirely standalone image that includes only the
forth words needed by <wordname>. If <wordname> didn't call
EMIT, then EMIT doesn't get CLONEd into the image. This leads
to very small executables. (CLONEing NOOP creates a standalone
program of about 3k...this is the support necessary to init the
environment if either double-clicked from an icon or typed into
the AMiga's shell.

When CLONE puts together the new image, it has do perform many
relocations, since everything is moved around relative to the
start of the program (as opposed to the start of the JForth image).

This means that CLONE must be able to tell the difference between
a compiled NUMBER and a compiled ADDRESS (as ['] might produce).

For this purpose, I've implemented ALITERAL.

The concept that a compiled NUMBER must be able to be differentiated
from a compiled ADDRESS is not normally needed in Forth, but for
sophisticated functionality such as CLONE, it is necessary.

The answer to the above question is that there is no standard
way of compiling in an address VS. a literal number...and there
should be.

Rob Chapman

unread,
Jan 12, 1992, 7:11:32 AM1/12/92
to

I once had similar high level definitions for:

: BRANCH ( -- ) R> @ >R ;
: 0BRANCH ( n -- ) 0= R @ CELL - R - AND R> + CELL + >R ;

In this case I got faster branches but slower conditional branches.

0BRANCH and 0= represent the classic chicken and egg syndrome. In the
above definition, we depend on 0= as a primitive. However if we wish to
define 0= in Forth:

: 0= ( n -- f ) IF -1 ELSE 0 THEN ;

then we need conditional branching as a primitive.


Other amusements dredged up from the cellar:

: EXECUTE ( tick -- ) >R ; ( not that portable though! )
: ROT ( a \ b \ c -- b \ c \ a ) >R SWAP R> SWAP ;

( ==== Inner Interpreters ==== )
: (VAR) ( -- addr ) R> ;
: (CONST) ( -- n ) R> @ ;
: (NEXT) ( -- ) R> R> ?DUP IF 1 - >R @ ELSE CELL + ENDIF >R ;
: LIT ( -- n ) R> @+ >R ;
: (DO) ( limit \ index -- ) SWAP R> SWAP >R SWAP >R >R ;
: (LOOP) ( -- ) R> R> 1 + DUP R <
IF >R DUP @ + ELSE R> 2DROP CELL + ENDIF >R ;
: (+LOOP) ( n -- ) R> SWAP DUP R> + SWAP 0< OVER R < XOR
IF >R DUP @ + ELSE R> 2DROP CELL + ENDIF >R ;

( ==== Comparisions via divide and conquer ==== )
: < ( n \ m -- flag ) 2DUP XOR 0< IF DROP ELSE - ENDIF 0< ;
: > ( n \ m -- flag ) 2DUP XOR 0< IF NIP ELSE SWAP - ENDIF 0< ;
: U< ( n \ m -- flag ) 2DUP XOR 0< IF NIP ELSE - ENDIF 0< ;
: U> ( n \ m -- flag ) 2DUP XOR 0< IF DROP ELSE SWAP - ENDIF 0< ;

For the really esoteric:
( ==== Unsigned multiplication and division ==== )
: quot< ( n \ q -- q ) 2* OR ;
: rem<m ( r \ m -- r ) 0< 1 AND SWAP 2* OR ;
: div? ( n \ r -- n \ ?rn- \ f ) OVER - DUP 0<
IF OVER + 0 ELSE 1 ENDIF ;
: /MOD ( m \ n -- r \ q ) SWAP 0 OVER rem<m SWAP 2* ( n \ r \ m/q )
F FOR >R div? SWAP R rem<m SWAP R> quot< NEXT
>R div? >R NIP R> R> quot< ;
: / ( n \ m -- quot ) /MOD NIP ;
: MOD ( n \ m -- rem ) /MOD DROP ;

: * ( n \ m -- nm* ) ( unsigned ) 0 SWAP
F FOR DUP >R 0< IF OVER + ENDIF 2* R> 2* NEXT
0< IF + ELSE NIP ENDIF ;

Rob

Mitch....@eng.sun.com

unread,
Jan 13, 1992, 11:37:42 PM1/13/92
to
> When [JForth's] CLONE puts together the new image, it has do perform many

> relocations, since everything is moved around relative to the
> start of the program (as opposed to the start of the JForth image).

> This means that CLONE must be able to tell the difference between
> a compiled NUMBER and a compiled ADDRESS (as ['] might produce).

> For this purpose, I've implemented ALITERAL.

My Sun Forth and Forthmacs systems, which are fully relocatable and
support an "application stripper" program that does the same thing
as JForth's CLONE, have the same problem and solve it in the same
way. My equivalent of ALITERAL is named (')

> The answer to the above question is that there is no standard
> way of compiling in an address VS. a literal number...and there
> should be.

You can do it in ANS Forth by using POSTPONE with ['] , or by
using something like S" ['] FOO" EVALUATE , possibly with a
string that is constructed at run time.

Mitch....@Eng.Sun.COM

Uwe Kloss

unread,
Jan 14, 1992, 5:42:10 PM1/14/92
to
In <1992Jan12....@idacom.hp.com>, Rob Chapman writes:
> Other amusements dredged up from the cellar:
>
> : EXECUTE ( tick -- ) >R ; ( not that portable though! )
How do you do this trick for non-colon-definitions? ;-)
That's why I recomend to implement EXECUTE as a low-level word.

> For the really esoteric:
> ( ==== Unsigned multiplication and division ==== )

Well ther you are!
And forgot to implement + in terms of and, xor and left-shift! ;-)

> Rob
Uwe
--
Uwe Kloss UUCP: UweK...@lionbbs.bs.open.de
Fasanenstrasse 65 BTX: 0531336908 0001
3300 Braunschweig FIDO: not connected

Uwe Kloss

unread,
Jan 14, 1992, 5:36:28 PM1/14/92
to
In <1992Jan12....@idacom.hp.com>, Rob Chapman writes:
>
> : 0BRANCH ( n -- ) 0= R @ CELL - R - AND R> + CELL + >R ;
>
> 0BRANCH and 0= represent the classic chicken and egg syndrome. In the
> above definition, we depend on 0= as a primitive. However if we wish to
> define 0= in Forth:
>
> : 0= ( n -- f ) IF -1 ELSE 0 THEN ;

That is no must!
You may formulate 0= in terms of left and right shifts and logical
(bitmap) or!

But this is highly machine dependant stuff!
An example for a _16_Bit_ machine follows:

\ utility stuff
: <<2 << << ; : <<4 <<2 <<2 ; : <<8 <<4 <<4 ; : <<16 <<8 <<8 ;

: >>2 >> >> ; : >>4 >>2 >>2 ; : >>8 >>4 >>4 ; : >>16 >>8 >>8 ;

\ if the rightmost bit was 1, now propagate it to the left
: (l0=) dup << or ( 2 bits to the left / if they exist / are set )
dup <<2 or ( 4 bits to the left / if they exist / are set )
dup <<4 or ( 8 bits to the left / if they exist / are set )
dup <<8 or ; ( 16 bits to the left / if they exist / are set )

\ if the leftmost bit was 1, now propagate it to the right
: (r0=) dup >> or ( 2 bits to the right / if they exist / are set )
dup >>2 or ( 4 bits to the right / if they exist / are set )
dup >>4 or ( 8 bits to the right / if they exist / are set )
dup >>8 or ; ( 16 bits to the right / if they exist / are set )

: 0= (l0=) ( if any bit was set, all to its left are set now too )
(r0=) ( if any bit was set at all, all are set now too )
not ; ( finaly implement 0= )

Again: it's not an example for speed but for possibility!

Bernd Paysan

unread,
Jan 13, 1992, 11:42:45 AM1/13/92
to

In article <7...@starnine.UUCP>, mi...@starnine.UUCP (Mike Haas) writes:
|> In article <1992Jan7.1...@Informatik.TU-Muenchen.DE> paz...@Informatik.TU-Muenchen.DE (Bernd Paysan) writes:
|> >
|> >In article <2746...@hpuamsa.neth.hp.com>, to...@hpuamsa.neth.hp.com
|> > (Ton 't Lam CRC) writes:
|> >
|> >|> - How is a number (officially) compiled into a word. I.e.:
|> >|> Thus how to distinguish a number from an execution address.
|> >|>
|> >
|> >In basic words:
|> >
|> >: LIT R> DUP CELL+ >R @ ;
|> >: LITERAL POSTPONE LIT , ; IMMEDIATE
|>
|> This did not answer the question. In fact, the question touches on
|> something that is important to me as the author of JForth.

This is true, if you think of the fact of making a system relocatible.
It is not only the question of a word like CLONE (nice word, but what
are the other 3 KByte of the NOOP solution? I need 200 Bytes on a
Atari ST for a standalone NOOP...). The problems of relocatible
programs are not mentioned in the currend standard. I invented myself
an ALITERAL, too (to compile addresses). Or an A, as the counterpart
of , for addresses. I need it only to save my system relocatible.
"Only" should be put into quotes, because for me as develloper, it is
very important to create images of my programs...

But it answers the question how literals and execution addresses are
distinguished by the inner interpreter. Therefore I think, my answer was
right.

Bernd Paysan

Bernd Paysan

unread,
Jan 15, 1992, 1:30:40 PM1/15/92
to

Mitch,
you are making the relocatible marks to simple. How do you create
tables of addresses? With ['] and guess how long the code for LIT
will be? How do you create deferred words? With TOKEN, ? My
tokens are not compiled as addresses! Your TOKEN, is my A, .
How do you address calculation where it is not worth or too
expensive to do it at run time? You need at least two words:
ALITERAL and A, , whereas A, is the basis.

Mike Haas

unread,
Jan 21, 1992, 8:43:54 PM1/21/92
to
In article <1992Jan13.1...@Informatik.TU-Muenchen.DE> paz...@Informatik.TU-Muenchen.DE (Bernd Paysan) writes:

>...making a system relocatible.


>It is not only the question of a word like CLONE (nice word, but what
>are the other 3 KByte of the NOOP solution? I need 200 Bytes on a
>Atari ST for a standalone NOOP...).

The 3K inherently present in a JForth CLONEd program includes...

1. The core I/O words (KEY, EMIT, etc) (these can optionally
be excluded...drops the executable to below 3K)

2. JForth system VARIABLEs data space

3. Code to initialize the JForth system

4. Code to identify whether the program was launched from the
Amiga's Shell or double-clicked from an icon on the Workbench
and do the appropriate initializations (for example, get any
command-line arguments and place them in the TIB for WORD to
obtain)

5. Code to terminate cleanly

If you can find a Forth on the Atari that can even generate a
standalone image (much less one that gets itself up & running
in 200 bytes), please let us know about it.

Bernd Paysan

unread,
Jan 22, 1992, 10:40:46 AM1/22/92
to

In article <7...@starnine.UUCP>, mi...@starnine.UUCP (Mike Haas) writes:
|> If you can find a Forth on the Atari that can even generate a
|> standalone image (much less one that gets itself up & running
|> in 200 bytes), please let us know about it.

It is my bigFORTH, but the tool to generate a standalone image is now
only in beta test. It will be available with the ANS version (or earlier,
if ANS takes too long). It contains only the startup code for TOS programs
(like CLI programs), not a window manager. The in/output is handled like
every TOS-program by system calls (inline macro expanded), thus it does
not use any byte if the programmer doesn't want it (ie for a simple resident
background process, that does no terminal io). It is not a concept like
CLONE, more like TCOM in F-PC. If I would write a word like CLONE, I would
have to implement IO, user variables and so on, because many words depend
on them, and there are no direct references to IO (there is vectored IO in
the normal bigFORTH).

You can get bigFORTH for 200 DM (send money+10 DM if outside EG) from:

Bernd Paysan
Stockmannstr. 14
8000 Muenchen 71
GERMANY

FORTHmacs from Mitch Bradley can generate a standalone image, too. He uses
a CLONE concept and FORTHmacs runs on the Atari. It should be clear, how to
get it...

Mitch Bradley

unread,
Jan 22, 1992, 8:25:13 PM1/22/92
to
> If you can find a Forth on the Atari that can even generate a
> standalone image (much less one that gets itself up & running
> in 200 bytes), please let us know about it.

Forthmacs by Bradley Forthware, with the optional Application Stripper
package. The minimum application size is roughly the same as
what you describe for JForth, and that includes basically the
same components (initialization, variables, a few core words).

Mitch Bradley

Mike Haas

unread,
Jan 27, 1992, 10:46:52 PM1/27/92
to

Cool. And I'm not surprised to see the "Bradley" name in there.
Excellent.

What other Forths include "standalone application strippers"
besides JForth for Amiga and Forthmacs for Atari? Please post
if you know some not mentioned.

And Mitch, please "toot" a little about Forthmacs...

What kind of threading?

Full file & memory interfaces, no?

What other "Mega-Forth" features are implemented?

I always enjoy hearing about someone having made a Forth
that leapfrogs Forth itself. Par for the Bradley course, though.

Doug Philips

unread,
Jan 29, 1992, 11:33:05 AM1/29/92
to
In article <7...@starnine.UUCP>
mi...@starnine.UUCP (Mike Haas) writes:
+Cool. And I'm not surprised to see the "Bradley" name in there.
+Excellent.

+What other Forths include "standalone application strippers"
+besides JForth for Amiga and Forthmacs for Atari? Please post
+if you know some not mentioned.

F-PC -- TCom (T-Com?)
Upper Deck Forth -- turnkey

Don't BBL and Pygmy have something too?

-Doug
---
Preferred: d...@willett.pgh.pa.us Ok: {pitt,sei}!willett!dwp

0 new messages