6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 4:00 pm

All times are UTC




Post new topic Reply to topic  [ 25 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Fri Oct 19, 2018 8:36 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
whartung wrote:
JimBoyd wrote:
whartung wrote:
Historically, the term of art for PAUSE functionality in cooperative multi tasking systems is called YIELD.

What Forth system?

I didn't say any Forth system. I just said cooperative multi tasking systems generically.

Sometimes it can be beneficial to use names common in the general programming community but not always. For example, COBOL uses ADD n TO SOMEVARIABLE but Forth has +!. Some languages use one or two symbol tokens for AND, OR, EXCLUSIVE-OR, etc. while the Forth words for those logic functions are spelled out: AND, OR, XOR.
I just don't see the value of looking outside the Forth community to name a given functionality when there already exists a name in the Forth community for said functionality.

Quote:
F83 uses PAUSE as well.

Even more reason it would be prudent to reserve the name PAUSE for multitasking.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 05, 2021 3:23 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
scotws wrote:
After reading up a bit more on PETTIL (very impressive, and three cheers for the TRS-80, the first computer I ever physically touched!), I started to wonder how any of this will work with multitasking. Does PETTIL in fact do multitasking? I haven't found it mentioned (apols if missed), and "PAUSE" for instance seems to do something totally different.

It would seem at first glance that my envisioned model would force every task to have its own 32 byte block of DPs, which is a lot of memory.


Not necessarily.
With a large system capable of supporting multiple programmers at the same time, each programmer will need a private dictionary that is linked into the main Forth dictionary.
On a small system with a single programmer using that system, the other tasks can be background tasks that do not need their own dictionary.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 05, 2021 2:50 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
scotws wrote:
Also, as far as I can tell from just thinking about this, multiple simply linked lists by size would eliminate the necessity of including the size value in the header of a word at all. So if we have, say, 100 words in the Dictionary at the beginning, we save 100 bytes.

Obviously I'll need to write some actual code to test this all. Any feedback on the general idea would be most welcome - this can't be a totally new idea after all.

I am trying something totally new in Forth programming and in doing so, am deviating greatly from any Forth standards, but the benefits in space savings and speed increase will be far greater in the end, so I would like to throw my hat in the ring for contention.

I created an insertion sort that greatly simplifies a lot of Forth idiosyncrasies. Here are some of the benefits.

- Links are no longer needed
- Words are sorted in alpha order and kept separate from the code.
- The word search is binary search instead of linear. Any word can be found in 3-5 tries.
- Many words are no longer needed and some have to be redefined, but are usually much shorter.
- Due to this ease of operation, Forth is much simpler to use and the complex operation of DEFINITIONS and VOCABULARIES is no longer required, making Forth even more simplified.
- No extra space is required as the sort routine is < 512 bytes and the space used is about the same as the space for the words removed. The 2-byte links alone for 256 words is 512 bytes and savings is multiplied with more than 256 words.
- Saving the Forth system with the code of an application or game is much easier and smaller since the words and links are not included with the definitions and nothing extra has to be done.
- Word lists can be listed alphabetically or by the order in which they were entered into the dictionary, or by the first character without having to search the entire dictionary, all with minimum code. The code to do this in regular Forth is substantially greater.
- The space savings now allows for use of the graphics screen.
- This layout also allows way more definitions to be crammed into a small area where the small area was separated by the graphics screen, like on the Apple II. The system definitions can now fit below the graphics screen, and the game definitions can fit above the graphics screen.

The more I delve into this method the more benefits I come across. And there has not been any disturbances in the Forth that I have found that I cannot work around. It has been fairly easy to slightly alter any word definitions from regular Forth to make them work.

The main part of the sort routine is written in strictly 6502 code, and is not computer dependent. I have extra code that allows to use the sort routine in a 2nd bank of 64k, where the words are stored. Which goes to show that if one has extra memory, this routine can benefit even more.

Once I am sure all the bugs are worked out, I will start another thread for anyone to follow along.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 05, 2021 8:26 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
Be sure to see the topic "dictionary hashing" and where Sam Falvo suggested the search cache about 80% of the way down the first page. It does not have the memory-efficiency advantage you're talking about, but searches are greatly sped up compared to the usual FIND method.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 31, 2021 1:53 am 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
I have written so many Forths, initially for the 6511, 6502, 65816, M377xx etc as well as many other 8 to 32-bit micros. In some systems there isn't much memory and so there is always the desire to save memory and also speed up dictionary searches. I think I have tried every method I could think of and while some of them worked very well, they also added processing overhead and housekeeping complications thus negating many other advantages. I have even had the dictionary in I2C EEPROM and on SD cards.

But one thing I always do now is never compile the headers inline with the code, and there are lots and lots of very good reasons not to. Rather, build the dictionary down from some predetermined location towards the code growing up in memory. Also, because all the words are packed in together with the newest word lower in memory then there is no need for any link fields. Instead each entry has a byte that combines the word count + attributes. I find that I rarely use very long words, preferring to factor into smaller functions with simpler names. Though I never go beyond 15 characters, I still allow for 31 and another 3 bits for attributes. There is no such thing as a smudge flag either and while a word is being defined, it itself is not included in the search although RECURSE will always compile a call to the current definition. One of the attribute bits will indicate that this word is "private" which is useful later on since we can reclaim all the memory of all or certain words that are private and recompact the dictionary without worrying about link fields etc. Another attribute I call preempt which works like the traditional immediate does, but because my newer Forths always compile word by word even in interactive mode (that's another big story), then preempt is used to override this when needed. Finally there are two bytes after the name for the address of the code and although I use 32-bits these days I still favor 16-bits for address or encoded instruction (literals, IF etc). This is a quick dump to show how it all looks:
Code:
TAQOZ# HERE .L --- $0000_A63E ok
TAQOZ# @WORDS $20 DUMP ---
1BEB0: 03 52 45 44  32 A6 06 45  44 53 45 43  54 0C A6 83     '.RED2..EDSECT...'
1BEC0: 53 45 44 B2  A5 44 53 45  44 3A 8A A5  08 45 44 49     'SED..DSED:...EDI' ok

Now we add a new word and examine memory again:
Code:
TAQOZ# : fibo  0 1 ROT FOR BOUNDS NEXT DROP ; ---  ok
TAQOZ# HERE .L --- $0000_A64E ok
TAQOZ# @WORDS $10 DUMP ---
1BEA9: 04 66 69 62  6F 3E A6 03  52 45 44 32  A6 06 45 44     '.fibo>..RED2..ED' ok

And to see what the code looks like:
Code:
1BEA9: pub fibo
0A63E: 1800     0
0A640: 1801     1
0A642: 0092     ROT
0A644: 1068     FOR
0A646: 008D       BOUNDS
0A648: 0135     NEXT
0A64A: 0077     DROP
0A64C: 005D     ;
      ( 16  bytes )

I also have another stack just for looping including the loop branch address that is saved by DO/FOR.

There are stacks of advantages in having a separate dictionary and because my code does not have a code field it allows one function to fall through into the one after it. Since all code is word aligned I use the lsb to indicate jumping rather than calling, thus saving on a call/EXIT.

BTW, we can also trace the execution of the code if you are interested. I plan to build all these features into a 65816/7700 Forth one day, just for the fun of it. I still have scores of boards floating around.
Code:
TAQOZ# TRACE 6 fibo UNTRACE ---
 0A650 :  1806
 0A652 :  A63E fibo             1( 00000006 )
 0A63E :   1800 FALSE           1( 00000006 )
 0A640 :   1801                 2( 00000000  00000006 )
 0A642 :   0092 ROT             3( 00000001  00000000  00000006 )
 0A644 :   1068 FOR             3( 00000006  00000001  00000000 )
 0A646 :   008D BOUNDS          2( 00000001  00000000 )
 0A648 :   0135 NEXT            2( 00000000  00000001 )
 0A646 :   008D BOUNDS          2( 00000000  00000001 )
 0A648 :   0135 NEXT            2( 00000001  00000001 )
 0A646 :   008D BOUNDS          2( 00000001  00000001 )
 0A648 :   0135 NEXT            2( 00000001  00000002 )
 0A646 :   008D BOUNDS          2( 00000001  00000002 )
 0A648 :   0135 NEXT            2( 00000002  00000003 )
 0A646 :   008D BOUNDS          2( 00000002  00000003 )
 0A648 :   0135 NEXT            2( 00000003  00000005 )
 0A646 :   008D BOUNDS          2( 00000003  00000005 )
 0A648 :   0135 NEXT            2( 00000005  00000008 )
 0A64A :   0077 DROP            2( 00000005  00000008 )
 0A64C :   005D EXIT            1( 00000008 )
 0A654 :  0430 UNTRACE          1( 00000008  ok
TAQOZ#


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 12:18 am 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
Just to add a little bit more on the "save memory" part of this thread, remember that having dictionary separate from the code allows a lot more flexibility and another thing to remember too is that Forth benefits from factoring into smaller definitions except that that requires more and more dictionary words. That's the beauty with "private" words in that we can have all the names we like when writing and compiling but save the memory by reclaiming those private words. Much better than the headerless kludge that I used to use in my first Forth, "RSC Forth".
Here's an example from an editor I wrote and even though I have plenty of memory available in this system, I may not in another, or if or when I do a 65816 version.

The editor has a mix of public and private definitions, like this:
Code:
pri ?HEX
    tw 16 = 0EXIT   I 1+ tw // ?EXIT
    TAB I 15 - 16 ADO I SED@ .BOLD LOOP ;
pub .BLOCK
    tcur @ tblk 1- ANDN HEADER RULER
    tblk ADO ROWS I SED@ .EMIT ?CR ?HEX LOOP ON CURSOR ;

Now pub and pri just create standard : definitions but force an attribute flag in the header. The very first word in this editor is *SED*, so now I can tell my Forth to reclaim all dictionary memory or just up to this point, like this:
Code:
TAQOZ# RECLAIM *SED*

{
 SED: SEDKEY SAVEFILE SED^X CLRLN SEDESC !TEXT FNCKEY ESC5B ESC3
 ESC2 tDEL tINS ?BLOCK SEDCHAR SEDKEY! SQUIT ?HEX .BOLD @TEXT
 ?CR ROWS HEADER RULER CLOCK SIZE TXTS HDRS @STATUS TEXTCUR
 TEXTXY y0 VCUR WRCUR CURSOR [/b] [b] SECTOR? RAM? FILE?
 FLASH? BLOCKS blksect TXTBLK BLK! HEXBLK tblk tw tcur+! tcur
Reclaimed 401 bytes
} ---  ok
TAQOZ#


Only the dictionary is compacted word by word (using a <CMOVE) and in this case since it is only a small editor of 1.6kB of code, but still there were 401 bytes freed.


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 5:45 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
Warning: The following is all related and relevant IMO, yet just slightly off-topic. Hopefully it will trigger another good idea in someone's mind.

I like the various ideas on separating the headers from the code. I would comment though that a dictionary has definitions too, not just the word names, so in the context of Forth, although we don't need things like etymology, a dictionary does include definitions, ie, the colon definitions (for secondaries) and code definitions (for primitives), and any data spaces, meaning in many cases nearly all the memory that Forth is using. This goes along with Bill Hartung's comment in the fourth post on the first page of this topic that what we're searching is a vocabulary. So what we're moving elsewhere is the headers, not the whole dictionary.

The method I plan to use to implement local variables when I get around to it is related to one of the ideas above, to put local-variable words (including for arrays, which ANS did not accommodate in locals) at the end of memory, in a temporary buffer, in a buffer chain, so they get included in searches during compilation. When the word these locals are used in is finished being compiled, the compile-time buffer for its locals is deleted, and CONTEXT is set back to the NFA of the word you're finishing up. FIND will have no idea that the temporaries ever existed. The word using the temporaries sets up a buffer at compile time which will contain the temporary variables' headers and the IMMEDIATE code to compile what will be needed to find the right data space later at run time, deletes that compile-time buffer when that word reaches the ; during compilation, and then sets up another buffer at run time for the actual data, and deletes that buffer just before it reaches its unnest (or an EXIT). The result is that these final addresses, put on the data stack at run time, can be used with the normal ! +! @ etc., even CMOVE and CMOVE>, like you can use with global variables and arrays. The buffers only exist and take up memory when the word using them is either being compiled or is running.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 05, 2021 8:51 am 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
Dictionary/Vocabulary/Lexicon/whatever are all just lists of words that become something a bit more specialized when you treat them differently although they haven't changed. I create vocabularies in the same "dictionary" of words simply by inserting special control fields where the count byte = 0 then the following bytes are dictionary control bytes. For instance, a count byte of 0 followed by 0 indicates the end of the dictionary etc. My vocabs are embedded inside the dictionary with these control fields and the search can be customized. My assembler works this way.

You mentioned data spaces and that is something that traditional Forth does not really handle well especially for embedded use since variables are normally sitting in with the code which could be Flash for instance, rather than a separate area. Once again, I keep all "variables" separate so that any inadvertent ! instead of C! etc does not write into code although it can take advantage of contiguous variables where four byte sized variables can be treated as a 32-bit variable or a whole area can be filled etc. So we need something other than VARIABLE, we need to describe what it is and how it fits into memory like in this section of my FAT32 driver:
Code:
    *** FAT32 BOOT RECORD ***

3   bytes   fat32       --- jump code +nop
8   bytes   oemname     --- MSWIN4.1
    word    b/s         --- 0200 = 512B (bytes/sector)
    byte    s/c         --- 40 = 32kB clusters (sectors/cluster)
    word    rsvd        --- 32 reserved sectors from boot record until first fat table
    byte    fats        --- 02
2   res                 --- Maximum Root DirectoryEntries (non-FAT32)
2   res                 --- Number of Sectors inPartition Smaller than 32MB (non-FAT32)
    byte    media       --- F8 hard disk  (IBM defined as 11111red, where r is removable, e is eight sectors/track, d is double sided. )


Code:
TAQOZ# fat32 .L --- $0000_1A45 ok
TAQOZ# $1A45 $10 DUMP ---
01A45: EB 5B 90 54  41 51 4F 5A  20 50 32 00  02 80 20 00     '.[.TAQOZ P2... .' ok
TAQOZ# oemname .L --- $0000_1A48 ok


The fat32 "variable" is really a constant that points to the data area and "3 bytes" advances the data pointer by 3 while creating "fat32" as a constant with the current data pointer. Now the whole data structure can be written to from the boot record sector with a simple CMOVE but I can still do the traditional fetch operations etc. If I do a
Code:
 fat32 90 ERASE
it will wipe all these variables in one hit or
Code:
@BOOT SECTOR fat32 90 CMOVE
will buffer in that sector.

But all this is probably digressing too much from this thread. Perhaps I will start a new one with my Tachyon '816 Forth which will be a 32-bit Forth since I find this the most useful for large memory addressing but also for file addressing etc.


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 05, 2021 9:28 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
pbj wrote:
You mentioned data spaces and that is something that traditional Forth does not really handle well especially for embedded use since variables are normally sitting in with the code which could be Flash for instance, rather than a separate area.

I had to deal with the difference between ROM and RAM compilation 30 years ago, per my post in "Forth-83 VARIABLE." The metacompiler I was using had major problems.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 07, 2021 12:24 pm 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
Yes, real systems that ended up with Forth in some kind of ROM rather than PC Forths that assumed they ran out of RAM is something I dealt with over 35 years ago when I designed commercial POS terminals and first used Forth. So I've never been a PC Forth guy and my main focus is on custom hardware I have designed for commercial products. When I look back at some of that software, while I am amazed at how much it did, I also see how much kludging I had to do to use a standard Forth.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page Previous  1, 2

All times are UTC


Who is online

Users browsing this forum: No registered users and 22 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: