6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 10:14 pm

All times are UTC




Post new topic Reply to topic  [ 354 posts ]  Go to page Previous  1 ... 8, 9, 10, 11, 12, 13, 14 ... 24  Next
Author Message
PostPosted: Tue Dec 15, 2020 9:22 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
JimBoyd wrote:
[color=#000000]
I do not recall an SD card for the C64.


you can find it here.
https://www.thefuturewas8bit.com/shop/c ... w1EALw_wcB


Quote:
I think I've mentioned this elsewhere, Fleet Forth determines which drive to use for block access based on block number. Originally, only five drives were supported but it takes less code to support eight drives. Here a table showing which block numbers go to which drive.


This is a big thread and haven't read it from start to finish yet. But yes, I can see how that works.

Quote:
Although the system will choose a specific drive for each range of 4096 blocks, not all blocks will be available.
For example, if device 8 is a Commodore 1541 drive, only 166 blocks are available. This means that the range of available blocks is not continuous. The range selected for the drives is a design consideration I made to facilitate copying blocks from one device to another while allowing a larger capacity drive to have more blocks available than what is possible with the 1541 drive.
The maximum REU size that is compatible with other C64 REU's is 16 megabytes or 16384 blocks. The 1764 REU had a capacity of 256 blocks and the 1750 REU had a capacity of 512 blocks.


I have to think this through some more. This BLK, SCRN, LOAD and LINE method still seems quite cumbersome.


Quote:
To be able to access blocks on a disk, the drive must be opened with the word DOPEN . This word takes no parameters and leaves no parameters. It opens the disk on the current drive. The current drive is 8 upon startup or a cold start but can be changed with the word DRIVE . For example, if I wanted to access blocks on drives 8 and 9, I could do the following:
Code:
8 DRIVE DOPEN 9 DRIVE DOPEN



I would like to convert that to
OPEN filename


Quote:
Fleet Forth maintains one or more buffers for blocks. I usually use four, but I sometimes use more when manipulating blocks. The buffers are right up against the memory limit specified by the system value LIMIT .

LIMIT can be lowered if the need arises. The buffer access table sits right up against the buffers. Although Fleet Forth reads blocks using direct access to read four Commodore disk sectors, it reads each block as a one kilobyte chunk. Fleet Forth only reads one block at a time and only writes one block at a time.


I think four buffers is almost the minimum. I will need 2 buffers to OPEN files and another 2 buffers for working on those files. I see now I can't get away from all those buffers. The first buffer houses the error messages, but since am working on a 128kb machine, I have some room to spare and might make the errors part of the system.



Fleet Forth is quite large and a C64 only has 64 kb memory? Is memory constraints so tight that it would be difficult to use graphics or write large applications with Fleet Forth?


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 16, 2020 6:48 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 255
IamRob wrote:
I think four buffers is almost the minimum. I will need 2 buffers to OPEN files and another 2 buffers for working on those files. I see now I can't get away from all those buffers. The first buffer houses the error messages, but since am working on a 128kb machine, I have some room to spare and might make the errors part of the system.
It's possible to do more than you think with a single buffer. I was also trying to figure out what the minimum number of buffers was for TaliForth2, and I ended up trying to make it work with a single buffer and it actually worked! I can load a screen that has other LOAD or THRU commands in it. The trick is to put back whatever was in the buffer if it was in use before (and you can check that by looking in BLK). This is horribly inefficient time-wise, but makes it so only 1K is needed.

The single buffer actually made some of the coding easier because I didn't have to deal with a buffer that was being used for interpretation being re-loaded into a different location (which might happen if the code being interpreted touched enough different blocks to cause a round-robin or LRU-type replacement algorithm to reuse the buffer the code was in, and then reload it in a different buffer when it was time to resume processing). As long as the original screen being interpreted is put back into memory and the pointers/indices are pointing at the next word to process, you can just resume interpreting as if the buffer contents were always there.

More buffers, of course, makes it so the system doesn't have to thrash around trying to restore what used to be in a buffer if it still has a copy. Tali2 is designed for systems with 32K or less of RAM and some folks won't use the block words at all, so it made sense to have it use as little RAM as possible.

I use the block words for storing forth code and data on an I2C EEPROM and it works very well for that. Emacs has a special forth mode to save the code in block format that I use.


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 16, 2020 11:47 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

IamRob wrote:
JimBoyd wrote:
I do not recall an SD card for the C64.

you can find it here.
https://www.thefuturewas8bit.com/shop/c ... w1EALw_wcB

I was not aware of that, nor was I aware of it back in the nineties when I was first using Forth on a Commodore 64. The word for disk read/write of a block, DR/W , is deferred so new functionality supporting new hardware can be added. Likewise, the word for REU read/write of a block, RR/W , is also deferred so new functionality can be added.
Quote:
Quote:
Although the system will choose a specific drive for each range of 4096 blocks, not all blocks will be available.
For example, if device 8 is a Commodore 1541 drive, only 166 blocks are available. This means that the range of available blocks is not continuous. The range selected for the drives is a design consideration I made to facilitate copying blocks from one device to another while allowing a larger capacity drive to have more blocks available than what is possible with the 1541 drive.
The maximum REU size that is compatible with other C64 REU's is 16 megabytes or 16384 blocks. The 1764 REU had a capacity of 256 blocks and the 1750 REU had a capacity of 512 blocks.

I have to think this through some more. This BLK, SCRN, LOAD and LINE method still seems quite cumbersome.

It's not too bad. To load a range of blocks, I use THRU . For example, if I want to load blocks 4, 5, 6, 7, 8, and 9 I would type this:
Code:
4 9 THRU

Quote:
Quote:
To be able to access blocks on a disk, the drive must be opened with the word DOPEN . This word takes no parameters and leaves no parameters. It opens the disk on the current drive. The current drive is 8 upon startup or a cold start but can be changed with the word DRIVE . For example, if I wanted to access blocks on drives 8 and 9, I could do the following:
Code:
8 DRIVE DOPEN 9 DRIVE DOPEN


I would like to convert that to
OPEN filename

Do you mean having blocks in a named file or Forth source in a text file?
Quote:
Quote:
Fleet Forth maintains one or more buffers for blocks. I usually use four, but I sometimes use more when manipulating blocks. The buffers are right up against the memory limit specified by the system value LIMIT .

LIMIT can be lowered if the need arises. The buffer access table sits right up against the buffers. Although Fleet Forth reads blocks using direct access to read four Commodore disk sectors, it reads each block as a one kilobyte chunk. Fleet Forth only reads one block at a time and only writes one block at a time.

I think four buffers is almost the minimum. I will need 2 buffers to OPEN files and another 2 buffers for working on those files. I see now I can't get away from all those buffers. The first buffer houses the error messages, but since am working on a 128kb machine, I have some room to spare and might make the errors part of the system.

Fleet Forth's errors are part of the system. I added up the memory used by the error messages in the kernel and it is 161 bytes. The error message strings for the error codes returned by the C64's kernal take up another 157 bytes.
I can use one buffer just fine. The extra buffers are to minimize "buffer thrashing". This is especially useful when editing source in a block. If I make a change in one block and it affects words in other blocks, then I edit those blocks and find that there is a better solution...
All that editing back and forth goes a lot smoother if there are enough buffers to hold all the blocks that I'm editing as I refine a design.
When I use the metacompiler, I need at least two buffers. One would work... slowly. The metacompiler uses some of the blocks in the C64's REU as virtual memory while it builds the new kernel. With only one buffer, every fetch or store involving virtual memory would flush the buffer with the source back out to disk.
Quote:
Fleet Forth is quite large and a C64 only has 64 kb memory?

I've tried streamlining Fleet Forth since releasing my initial prototype.
The Fleet Forth kernel is under ten k (about nine and three quarter). It is a complete Forth-83 system without an assembler or editor so I suppose the name 'kernel' is a bit of a misnomer. Part of the cold start routine switches out BASIC ROM because it is not needed.
The kernel plus system loader is just under 15.5 k. The system loader includes the assembler, the Starting Forth editor, the screen editor, printer and logger words, the auxiliary stack words, and some other useful words.
Loading the utilities increases the size to just under 20 k. This includes the decompiler, block manipulation tools, and a few more utilities.
Quote:
Is memory constraints so tight that it would be difficult to use graphics

I have successfully ported Blazin' Forth's graphics words to Fleet Forth. The first time I tried loading it was a disaster because Blazin' Forth's line drawing routine overwrote Fleet Forth's IP and W virtual registers in zero page! Yes, this locked up the Commodore, necessitating a reset.
The C64 video chip needs 8000 bytes for the graphics screen. For graphics, Blazin Forth sets the video chip to look at the last 16k of memory and uses the RAM under the kernal ROM. Since only 8000 bytes are needed, that leaves the last 192 bytes untouched. Blazin' Forth has a clever way to allow normal interrupt processing while the kernal ROM is switched out.
Blazin' Forth's graphics utilities add turtle graphics to Forth.
Quote:
or write large applications with Fleet Forth?

The last 'application' I wrote in Forth on the C64 was "A Virtual Nondeterministic Machine in Forth". If memory is tight, the extras can be left out. DUMP and SEE are, in my opinion, for diagnostics when something goes wrong. That is why SEE is so big. It also decompiles CODE words and handles the transition from high level to CODE and back.
An application is unlikely to need either.
I suppose the metacompiler could be considered an application in Forth. In that case, the metacompiler was the last application I wrote in Forth on a C64.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 17, 2020 12:17 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
SamCoVT wrote:
IamRob wrote:
I think four buffers is almost the minimum. I will need 2 buffers to OPEN files and another 2 buffers for working on those files. I see now I can't get away from all those buffers. The first buffer houses the error messages, but since am working on a 128kb machine, I have some room to spare and might make the errors part of the system.
It's possible to do more than you think with a single buffer. I was also trying to figure out what the minimum number of buffers was for TaliForth2, and I ended up trying to make it work with a single buffer and it actually worked! I can load a screen that has other LOAD or THRU commands in it. The trick is to put back whatever was in the buffer if it was in use before (and you can check that by looking in BLK). This is horribly inefficient time-wise, but makes it so only 1K is needed.

The single buffer actually made some of the coding easier because I didn't have to deal with a buffer that was being used for interpretation being re-loaded into a different location (which might happen if the code being interpreted touched enough different blocks to cause a round-robin or LRU-type replacement algorithm to reuse the buffer the code was in, and then reload it in a different buffer when it was time to resume processing). As long as the original screen being interpreted is put back into memory and the pointers/indices are pointing at the next word to process, you can just resume interpreting as if the buffer contents were always there.


The easiest way I've found when designing a Forth-83 system is to have LOAD save BLK and >IN on the return stack and restore them after.
Fleet Forth's parsing word, WORD uses 'STREAM . If BLK is not zero, 'STREAM calls BLOCK so it doesn't matter if a block load is interrupted by another block access and the original block is read into a different buffer. Every time WORD executes, BLOCK is executed. This is why Fleet Forth's BLOCK (and BUFFER ) starts out as a CODE word. If the requested block is the most recently used, BLOCK is screaming fast.
Quote:
More buffers, of course, makes it so the system doesn't have to thrash around trying to restore what used to be in a buffer if it still has a copy. Tali2 is designed for systems with 32K or less of RAM and some folks won't use the block words at all, so it made sense to have it use as little RAM as possible.

By allowing the number of buffers to be altered on the fly, it is possible to set the number of buffers to zero in Fleet Forth with:
Code:
0 TO #BUF CONFIGURE

Just don't try to use blocks with zero buffers!
Quote:
I use the block words for storing forth code and data on an I2C EEPROM and it works very well for that. Emacs has a special forth mode to save the code in block format that I use.

Yes, blocks are not just for source code. When metacompiling, I use some blocks in the C64's REU (ram expansion unit) for virtual memory.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 17, 2020 4:48 am 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
Quote:
It's possible to do more than you think with a single buffer. I was also trying to figure out what the minimum number of buffers was for TaliForth2, and I ended up trying to make it work with a single buffer and it actually worked! I can load a screen that has other LOAD or THRU commands in it. The trick is to put back whatever was in the buffer if it was in use before (and you can check that by looking in BLK). This is horribly inefficient time-wise, but makes it so only 1K is needed.



Under Prodos, the minimum would be 2 buffers. The OPEN file command needs 1 buffer reserved for information about the file. The 2nd buffer is needed for the READ command which reads the actual data of the file. I can read 1024 bytes at a time and compile a line at a time that ends in a CR delimiter.

With a text file, each line gets moved into PAD and the CR gets converted to a zero before compiling. When the end of the buffer is reached, then the next block is read in and compiling continues until the end of the file is encountered.

This idea will be similar in use to the SCRN# LOAD and SCRN# LIST words, but won't need the "-->" at the end of each 1024 byte block. The new word definition for loading text file getting compiled is with "LOAD filename" (without the quotes). This way I can have as many text file applications, utilities and games all on hard drive all at the same time and swap between them easily with LOAD TEXTFILE and FORGET TASK.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 17, 2020 5:54 am 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
Quote:
Do you mean having blocks in a named file or Forth source in a text file?


Both. But blocks are not padded with spaces like in screens. The idea is to load a text file which requites 2 buffers. One for the OPEN command and one for the READ command. Prodos requires the OPEN file buffer for information about the file. The READ buffer is for the actual data. A block (1024 bytes) of text gets read in at a time. Each line delimited by a CR is moved to PAD and the CR converted to a zero. That line gets compiled, then the next line gets read in. If the end of the buffer is reached and a line is cut off when being moved to PAD, then the next block gets read in. This continues until the end of the file is reached. The RUN word launches the last word that gets loaded and launches the application. This makes it easy to have all the applications, games, and utilities stored in text files and can be swapped easily between them with LOAD TEXTFILE and FORGET TASK.


Quote:
Fleet Forth maintains one or more buffers for blocks. I usually use four, but I sometimes use more when manipulating blocks. The buffers are right up against the memory limit specified by the system value LIMIT .


I need a minimum 2 buffers for Prodos. The first one is reserved for information about the file and used by the Machine Interface and the second one is used to load the actual data.


Quote:
LIMIT can be lowered if the need arises.


In ProForth, LIMIT is pointing at the USER area with the buffers just underneath. FIRST is used to designate the start of the buffers. But I would prefer to have LIMIT designated to be the upper limit of free memory.


Quote:
Fleet Forth's errors are part of the system.


ProForth errors are actually part of a screen file. The screen file is a file on disk that houses 16 screens of 1024 bytes and takes up 1 constant buffer. But there is a lot of waste with the screens as every line is padded with spaces. Thus I want to make the errors part of the system and convert everything else to text file delimited by a CR to eliminate all the wasted space.


Quote:
I've tried streamlining Fleet Forth since releasing my initial prototype.
The Fleet Forth kernel is under ten k (about nine and three quarter). It is a complete Forth-83 system without an assembler or editor so I suppose the name 'kernel' is a bit of a misnomer. Part of the cold start routine switches out BASIC ROM because it is not needed.


I am trying to weed the kernel down to being just the primitives required to compile a colon definition and code words. Everything else can be added through text file loading as required.


Quote:
The kernel plus system loader is just under 15.5 k.


If all goes well, I believe I can get the bare kernel down to under 5 K. The system loader will move all the actual names and their CFA's of the words to Auxiliary memory along with a sorting algorithm. This sorter will cut compiling time down into a fraction of the time and also eliminates a lot of words when they are with their description. LFA, NFA, PFA, TRAVERSE, COUNT are no longer needed. And the dictionary of words can be listed in alphabetical order or just the words that are part of a VOCABULARY, which makes words easier to find in the list. I can also just list words that start with the first letter. Really nice not to have the entire word library listed every time.


Quote:
The system loader includes the assembler, the Starting Forth editor, the screen editor


I already have very nice system applications of these three, even though I have to leave FORTH. But I am not ready to re-invent the wheel right now.



Quote:
I have successfully ported Blazin' Forth's graphics words to Fleet Forth.


Graphics is on my to-do list


Quote:
Blazin' Forth's graphics utilities add turtle graphics to Forth.


I also have turtle graphics in an ML program. It wouldn't take much to separate the code and make word definitions for each turtle command.



Quote:
Quote:
or write large applications with Fleet Forth?

The last 'application' I wrote in Forth on the C64 was "A Virtual Nondeterministic Machine in Forth". If memory is tight, the extras can be left out.


This is where my theory of loading text files for an application can benefit. It can load larger programs in memory than can fit when creating them, as the editor and assembler are also in memory when creating applications. I will have the ability to clear the first words create and then append extra words to a text file.


Quote:
That is why SEE is so big. It also decompiles CODE words and handles the transition from high level to CODE and back.


I call my word decompiler DECODE and it does a pretty good job at decoding everything. The one problem I have to rectify yet is that -FIND returns the PFA of a word. The problem with that is that some words do not have a PFA. The CFA points somewhere else in memory. Then comes the big crash to the monitor.

Can your SEE decode BRANCH and 0BRANCH back into IF-ELSE-THEN or BEGIN-UNTIL (REPEAT or AGAIN) statements? I think I have it figured, but just when I think I have it figured out, I question my logic.


Top
 Profile  
Reply with quote  
PostPosted: Fri Dec 18, 2020 6:07 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
IamRob wrote:
Can your SEE decode BRANCH and 0BRANCH back into IF-ELSE-THEN or BEGIN-UNTIL (REPEAT or AGAIN) statements? I think I have it figured, but just when I think I have it figured out, I question my logic.

Oof ... that does seem like a tough nut to be able to reliably crack. :)

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Fri Dec 18, 2020 10:05 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
IamRob wrote:
The new word definition for loading text file getting compiled is with "LOAD filename" (without the quotes). This way I can have as many text file applications, utilities and games all on hard drive all at the same time and swap between them easily with LOAD TEXTFILE and FORGET TASK.


If your source was in a text file rather than blocks, the functionality for your Forth's LOAD sounds like the Ans Forth word INCLUDE , which makes a text file the input source and interprets/compiles from the file until the end of file.


Top
 Profile  
Reply with quote  
PostPosted: Fri Dec 18, 2020 10:37 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
IamRob wrote:
If all goes well, I believe I can get the bare kernel down to under 5 K. The system loader will move all the actual names and their CFA's of the words to Auxiliary memory along with a sorting algorithm. This sorter will cut compiling time down into a fraction of the time and also eliminates a lot of words when they are with their description. LFA, NFA, PFA, TRAVERSE, COUNT are no longer needed. And the dictionary of words can be listed in alphabetical order or just the words that are part of a VOCABULARY, which makes words easier to find in the list. I can also just list words that start with the first letter. Really nice not to have the entire word library listed every time.


I have a word IN-NAME that shows all word in the context vocabulary that have a specific string.
Code:
" SP" IN-NAME

will show all words with 'sp' in the name.
Code:
"  SP" IN-NAME

will show all words that begin with 'sp'.
Code:
" SP " IN-NAME

will show all words that end with 'sp'.

Quote:
Quote:
The system loader includes the assembler, the Starting Forth editor, the screen editor


I already have very nice system applications of these three, even though I have to leave FORTH. But I am not ready to re-invent the wheel right now.

I find it helps with development, especially on the C64, with the editor and assembler as part of Forth.


Quote:
Quote:
Quote:
or write large applications with Fleet Forth?

The last 'application' I wrote in Forth on the C64 was "A Virtual Nondeterministic Machine in Forth". If memory is tight, the extras can be left out.


This is where my theory of loading text files for an application can benefit. It can load larger programs in memory than can fit when creating them, as the editor and assembler are also in memory when creating applications. I will have the ability to clear the first words create and then append extra words to a text file.

I like to have the Forth system available. It's useful when the "application" is an extension of Forth to control an electronics project connected to the C64, like I did back when I had a real one. Although I build my kernel with a metacompiler, which is now written in Fleet Forth, I have an idea for another project if more room is ever needed. A target compiler, an adaptation of the metacompiler for building stand alone applications that do not need the Forth system.
No headers, no unneeded words, but I need to give this idea some more thought.
Quote:
Can your SEE decode BRANCH and 0BRANCH back into IF-ELSE-THEN or BEGIN-UNTIL (REPEAT or AGAIN) statements? I think I have it figured, but just when I think I have it figured out, I question my logic.

No. Since I wrote Fleet Forth, I already have the source available and I include the source with the system. My implementation of SEE does exactly what I want it to. It shows me what actually got compiled, not what the original source code was. I started a thread on SEE.
Here is an example:
Code:
SEE 2CONSTANT
2CONSTANT
 11920  8748 CREATE
 11922  7699 ,
 11924  7699 ,
 11926  7794 DOES
 11928  9377    JMP ' DOES> >BODY 21 +
 11931  4817 2@
 11933  2403 EXIT
15
 OK

and the source:
Code:
: 2CONSTANT
   CREATE , , DOES>
      2@ ;

Here is an example with branches:
Code:
SEE QUIT
QUIT
  8551  3314 [ IMMEDIATE
  8553  3630 RP!
  8555  7036 CR
  8557  8110 QUERY
  8559  8454 INTERPRET
  8561  2764 STATE
  8563  4782 @
  8565  4401 0=
  8567  3292 ?BRANCH 8553
  8571  6711 (.")  OK
  8577  3280 BRANCH 8553
30
 OK

and the source:
Code:
: QUIT  ( -- )
   [COMPILE] [
   BEGIN
         RP! CR QUERY INTERPRET
         STATE @ 0=
      CS-DUP UNTIL  // CONTINUE
      ."  OK"
   AGAIN ; -2 ALLOT



Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 20, 2020 8:53 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
IamRob wrote:
Quote:
The system loader includes the assembler, the Starting Forth editor, the screen editor

I already have very nice system applications of these three, even though I have to leave FORTH. But I am not ready to re-invent the wheel right now.


If you do not have an assembler included with your Forth then how do you write CODE words?


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 21, 2020 10:56 am 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
JimBoyd wrote:
IamRob wrote:
Quote:
The system loader includes the assembler, the Starting Forth editor, the screen editor

I already have very nice system applications of these three, even though I have to leave FORTH. But I am not ready to re-invent the wheel right now.


If you do not have an assembler included with your Forth then how do you write CODE words?

manually using the left and right brackets

: test ;code [ 20 c, fc58 , 00a0 , ... etc ] ;


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 14, 2021 7:55 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
JimBoyd wrote:

?MEM is different. It does not return the amount of bytes free. Given a number of bytes, it performs the test to see if there is enough memory available. It takes the number of bytes and if that number is available, it returns that same number. This is why, in a previous post, I called it "transparent".
For example, here is the source for Fleet Forth's ALLOT .
Code:
: ALLOT  ( N -- )
   ?MEM  DP +! ;

ALLOT was previously defined without memory checking:
Code:
: ALLOT  ( N -- )
   DP +! ;

This seems more convenient to me than picking a "reasonable" amount of memory that needs to be available in CREATE or the need to check memory if I need to ALLOT some. If there is not enough memory, HERE does not change and the system aborts.
So far ?MEM is only used in two other places:
" places a string at PAD while interpreting or compiles (") and inlines the string while compiling.
FBUF in the editor.
The new and improved version of (ABORT") wasn't just to remove 0EXIT from ?MEM , but to make all uses of (ABORT") faster when there is no error to report.

When a colon word is being defined, it is stored in TIB, correct?

How about just scanning TIB and counting the number of spaces? Each word in TIB basically gets reduced to its 2-byte CFA. So # of spaces times 2 plus the word length basically gives a very close approximation to the space needed to create and compile that word.

Therefore the memory available only needs to be checked once at the beginning by INTERPRET or even in QUIT. In my Forth QUIT calls QUERY then INTERPRET. SCAN can be put between the two and INTERPRET will not even be called if low on memory.

This word might do it:

0 VARIABLE CNTR
: SCAN 0 CNTR ! TIB @ DO DUP C@ 0= IF LEAVE ELSE DUP C@ 20 = IF 1 CNTR +! THEN 1+ THEN UNTIL CNTR 2* MEM - 5 - 0< # ?ERROR ;

# - is a real number assigned to the "Out of Memory" message
The 5 is just an average word length but can be changed to calculate the actual length of the word


Top
 Profile  
Reply with quote  
PostPosted: Fri Jan 15, 2021 9:27 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
IamRob wrote:
When a colon word is being defined, it is stored in TIB, correct?

How about just scanning TIB and counting the number of spaces? Each word in TIB basically gets reduced to its 2-byte CFA. So # of spaces times 2 plus the word length basically gives a very close approximation to the space needed to create and compile that word.

Therefore the memory available only needs to be checked once at the beginning by INTERPRET or even in QUIT. In my Forth QUIT calls QUERY then INTERPRET. SCAN can be put between the two and INTERPRET will not even be called if low on memory.

This word might do it:

0 VARIABLE CNTR
: SCAN 0 CNTR ! TIB @ DO DUP C@ 0= IF LEAVE ELSE DUP C@ 20 = IF 1 CNTR +! THEN 1+ THEN UNTIL CNTR 2* MEM - 5 - 0< # ?ERROR ;

# - is a real number assigned to the "Out of Memory" message
The 5 is just an average word length but can be changed to calculate the actual length of the word


If entering a definition from Forth's command line then yes the source for the colon definition will be in the TIB. If loading a block, the source will be in whatever buffer is assigned to that block. The colon definition is built at HERE .
Your word SCAN looks odd. I see DO but no LOOP . I believe I see what you are doing and I cleaned up the code. I used the word 'STREAM because it returns the address of the text stream and a count of the remaining size. In Fleet Forth, WORD uses 'STREAM for parsing.
Code:
: 'STREAM  ( -- ADR N )
   BLK @ ?DUP
   IF
      BLOCK B/BUF
   ELSE
      TIB #TIB @
   THEN
   DUP >IN @ UMIN DUP NEGATE
   UNDER+ UNDER+ ;

This will allow it to work for the text input buffer and loading blocks (and when evaluating strings). I also changed the name to PROBE . Fleet Forth already has a word named SCAN . It is used by WORD and (CHAR) . I also rewrote the DO LOOP to make it faster.
Code:
: MEM  ( -- U )  MRU PAD - ;
VARIABLE CNTR
: PROBE
   CNTR OFF 'STREAM 0
   DO
      COUNT BL <> 1+ CNTR +!
   LOOP
   DROP  MEM  CNTR @ 2* 5 + U<
   ABORT" LOW MEMORY" ;

Rather than build a new system, I hot patched ALLOT to redefine it as:
Code:
: ALLOT  ( N -- )  DP +! ;

by doing this:
Code:
' ALLOT >BODY DUP 2+ SWAP 6 MOVE

and I defined the following:
Code:
: NLINELOAD  ( LINE# BLK# -- )
   ?DUP 0=
   ABORT" CAN'T LOAD 0"
   BLK 2@ 2>R
   BLK !  C/L * >IN !
   PROBE INTERPRET  2R> BLK 2! ;
: NLOAD  ( U -- )
   0 SWAP NLINELOAD ;
: NTHRU  ( U1 U2 -- )
   1+ SWAP
   DO
      5 ?CR
      I DUP U. NLOAD DONE? ?LEAVE
   LOOP ;

and a few redefinitions
Code:
: LINELOAD   NLINELOAD ;
: LOAD   NLOAD ;
: THRU   NTHRU ;

I have a disk (image) of Blazin' Forth's utilities modified to work with Fleet Forth. I copied the blocks from that disk to some of the blocks used by the REU (Commodore's Ram Expansion Unit) so the drive access speed would not be a consideration.
Here are my results:
Fleet Forth with ?MEM takes 3% longer to load blocks in REU than Fleet Forth with no 'out of memory' protection.
Fleet Forth with PROBE instead of ?MEM takes 23% longer to load blocks in REU than Fleet Forth with no 'out of memory' protection.
using PROBE before INTERPRET adds more overhead than having ?MEM in ALLOT. Almost eight times more.
PROBE is bigger.
PROBE is inaccurate but ?MEM is dead on. If alloting a large data buffer, it is possible to exhaust the free memory and PROBE will not catch the problem. For example:
Code:
CREATE DATA 10000 ALLOT

?MEM only aborts if too much memory is to be alloted. The command line can still be used to INTERPRET commands to free some memory.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jan 16, 2021 2:16 am 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
JimBoyd wrote:
I have a disk (image) of Blazin' Forth's utilities modified to work with Fleet Forth. I copied the blocks from that disk to some of the blocks used by the REU (Commodore's Ram Expansion Unit) so the drive access speed would not be a consideration.
Here are my results:
Fleet Forth with ?MEM takes 3% longer to load blocks in REU than Fleet Forth with no 'out of memory' protection.
Fleet Forth with PROBE instead of ?MEM takes 23% longer to load blocks in REU than Fleet Forth with no 'out of memory' protection.
using PROBE before INTERPRET adds more overhead than having ?MEM in ALLOT. Almost eight times more.
PROBE is bigger.
PROBE is inaccurate but ?MEM is dead on. If alloting a large data buffer, it is possible to exhaust the free memory and PROBE will not catch the problem. For example:
Code:
CREATE DATA 10000 ALLOT

?MEM only aborts if too much memory is to be alloted. The command line can still be used to INTERPRET commands to free some memory.[/color]

I am actually surprised by the poor results as the only difference is that PROBE only does the memory calculation of LIMIT PAD - once compared to ?MEM has to do it at every word being interpreted, but PROBE did have the overhead of probing each character for a space to be counted. I was sure the math overhead would be more time consuming.

PROBE was only meant to determine if memory was running out before words were added tot he dictionary and not when variables, arrays, strings and space were allotted. Which would mean that ALLOT should definitely have its own memory test.

But thanks for testing PROBE for me. I was going to use it when LOADing words from the Virtual disk to create programs.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 18, 2021 11:22 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
IamRob wrote:
I am actually surprised by the poor results as the only difference is that PROBE only does the memory calculation of LIMIT PAD - once compared to ?MEM has to do it at every word being interpreted, but PROBE did have the overhead of probing each character for a space to be counted. I was sure the math overhead would be more time consuming.

PROBE was only meant to determine if memory was running out before words were added tot he dictionary and not when variables, arrays, strings and space were allotted. Which would mean that ALLOT should definitely have its own memory test.


?MEM is only used in ALLOT and words that store a string at PAD . For example, the word " ( quote ) will, if interpreting, store a string at PAD and return the address of PAD . If compiling, it will compile the word (") and an inline string.
Quote:
But thanks for testing PROBE for me. I was going to use it when LOADing words from the Virtual disk to create programs.


You're welcome.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 354 posts ]  Go to page Previous  1 ... 8, 9, 10, 11, 12, 13, 14 ... 24  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 8 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: