Shop OBEX P1 Docs P2 Docs Learn Events
pfth revisited -- TRY pfth072 Easy to install, easy use // Forth on the Propeller - Page 2 — Parallax Forums

pfth revisited -- TRY pfth072 Easy to install, easy use // Forth on the Propeller

2

Comments

  • KC_RobKC_Rob Posts: 465
    edited 2013-06-26 11:26
    This thread has piqued my interest. I've played some with both TACHYON and PropForth, now I'll have to give pfth a try. Can anyone give an idea of how its performance compares to PropForth?
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-26 11:59
    Dave Hein seems to think it is faster in loops than PropForth. Performance parameters do tend to be an apples versus oranges games as there are trade-offs. pfth right now is a 32 bit cell based dictionary, so the dictionary in hub ram is likely 50% of what PropForth can provide. Bigger projects need the SDcard version as higher EEprom does not support a file system.

    PropForth has some very fancy inter-cog communications. Not sure that pfth has much if anything at all. But cogs can be deployed indepently. I've love to know more about multiple cog use.

    I doubt if anyone will ever beat Tachyon for speed, but you have to keep up with Peter J's fast paced development process as well.

    I have just found that I wanted a broader view of Forth than just one special Forth on the Propeller. We had quite a debate about the pros and cons of ANS Forth, and there will always be special Propeller systems for any Forth on the Propeller. But I'd like to learn and explore programs from ANS Forth users. pfth easily allows that... even plays a chess game.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-26 13:16
    I haven't done much benchmarking, but a simple DO-LOOP ran slightly faster under pfth. The inner loop of pfth does two reads. The first read gets the address of the code pointer of the word, and the second read gets a COG address that it jumps to. PropForth's inner loop only does one read for assembler words, and does the second read only for calls to a non-assembler Forth word. Overall I would say that pfth and PropForth have about the same performance. Tachyon is probably an order of magnitude faster than pfth or PropForth.

    As Loopy said, pfth uses 32 bits for each execution token. I've looked at reducing this to 16 bits, but I haven't gotten very far. The SD card version does allow running code that's stored on the SD card, but it doesn't increase the space available for the dictionary. After running code from the SD card, you have to FORGET it to open up space for another code file. There's not even enough space to run the chess game and the SD code at the same time, but that should change when I go to 16-bit execution tokens.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-27 06:15
    Hi Dave,
    Does pfth have a way to have a word to be defined to automatically run on Power ON?

    PropForth has onboot and onreset that evoke automated words when a boot or a cog reset occurs. I think Tackyon has similar features.
  • Martin_HMartin_H Posts: 4,051
    edited 2013-06-27 06:38
    AmForth (http://amforth.sourceforge.net/) uses a 16 bit cell size for the Atmel Atmega chips. Given the similar memory sizes of the Propeller and those chips, I imagine 16 bits would definitely improve things.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-27 06:57
    @Loopy, for the stand-alone version you would just include the startup word using the Spin FILE directive. For the SD version a startup word could be defined and called, but I haven't done that.

    @Martin_H, pfth will still use a 32-bit CELL size even after I change to 16-bit execution tokens. The stack width will continue to be 32 bits, and ! and @ will store/fetch 32 bit values. I will add w! and w@ words to handle 16-bit unsigned values and the execution tokens will be 16 bits. The "," word will write 32 bits, but the ",compile" word will write 16 bits.
  • Martin_HMartin_H Posts: 4,051
    edited 2013-06-27 07:42
    Dave, thanks for the clarification. I was thinking cell size and the execution token size had to be linked. Having 32 bit cells will be good for arithmetic.

    I've sort of been thinking of the execution token as the address of the function. So just like I can push the address of a data cell, I can push the address of a function. Given the Propeller's small memory size the addresses of cells 16 must be bits? Basically if I was construction an array of pointers I could pack them into 16 bit unsigned values?
  • David BetzDavid Betz Posts: 14,516
    edited 2013-06-27 07:54
    Martin_H wrote: »
    Dave, thanks for the clarification. I was thinking cell size and the execution token size had to be linked. Having 32 bit cells will be good for arithmetic.

    I've sort of been thinking of the execution token as the address of the function. So just like I can push the address of a data cell, I can push the address of a function. Given the Propeller's small memory size the addresses of cells 16 must be bits? Basically if I was construction an array of pointers I could pack them into 16 bit unsigned values?
    For the Propeller 2 you'll need more than 16 bits since the P2 has 128k of hub memory. I guess you could still squeak by with 16 bits if you use word addresses.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-27 08:28
    @Martin_H, pfth's execution token (XT) is the address of the start of a word. I'm changing that in the next update to be the address of the code pointer in the word -- so it's basically the address of a pointer to the code in the cog. In PropForth the XT is the address of code in a cog, or it's the address of the list of XT's in a compiled word. It uses the upper bits of the XT to determine which on it is. I may change to the PropForth method later on, but the current method in pfth is easier for me to work with.

    @David, I realized that changing to 16 bits would only allow addressing the first 64K in P2. Since words are long-aligned I could shift the XT's down by 1 bit when compiling, and shift them up by 1 bit when executing.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-28 09:56
    Dave Hein wrote: »
    @Loopy, for the stand-alone version you would just include the startup word using the Spin FILE directive. For the SD version a startup word could be defined and called, but I haven't done that.

    Hi.
    I was looking into the TIB (Terminal Input Buffer) and the outer interpreter. Your suggestions seems much simpler, and cleaner. Several tutorials say to NEVER mess with the TIB and rarely mess with the PAD. So I was beginning to realize I was look in the wrong way.

    I have no problem with adding lexicon via the FILE directive... I guess that is all colon/semi-colon definitions. I just hadn't considered that the FILE directive could be used as the means to automatically start. I will take another closer look at your xxx.fth files.

    What you are implying is that the File directives cause the listed files to be read directly into the TIB as if they were typed in from a serial terminal. I guess <carriage return> would be important as well.


    So if I do a FILE directive and that just has the one particular word I want to use to start ... without the colon/semi-colon, but with a carrage return ... and it is the last in the list, it seems like it would do an automatic start.

    I guess I can run some tests by having ." xxx " message display on reboot.

    It seems I was just thinking too low level and making this harder than it is. Thanks.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-28 10:45
    If you look at the PASM getch routine you will see that the first thing it does is read a byte from infileptr. If this is non-zero it will return the value, otherwise it will read a byte from the serial port. At bootup infileptr contains the address of infile, which is where all the FILE directives are located. The list of FILE directives is terminated with a "long 0". This allows pfth to read all of the files stored in RAM as if they were input through the serial port. The compiled data will overwrite the files that are stored in memory, which is why there is zero-padding before the first file.

    The serial output is disabled by default, and there's some code in version.fth that turns on the output. This way all the bootup stuff is done quietly. You should place your file befor version.fth if you don't want it echoed to the serial port, or you can put it after version.fth if you want the interpreter to print out your file as it processes it. There is also a 3-second WAITCNT in the Spin code, which gives enough time to start up a serial terminal. You can remove the 3-second wait if you don't want it.

    Your file does need to terminate each line with a LF or CR. Text files normally have a LF at the end of each line, so pfth will handle normal text files. Text files created under Windows will have both a LF and CR, so you will see an extra blank line when using Windows files.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-28 11:49
    Hi again,
    Well I tested it. Without the line feed or carriage return, the line of code does not execute and the terminal is shut out to the user. One actually has to correct the .fth file, recompile, and then reload the Eeprom to regain a functional Propeller. And, I actually tried the Forth word cr without ending the line and that doesn't work either.

    So properly ending the line is critical to using this autostart feature. One just has to make sure that when editing the .fth file that you have the cursor move to the line below by hitting the <enter> on your keyboard, and then save the file.

    If the line of code is correct and the line is terminated right, it goes right to work without waiting for input from the keyboard.

    Slowly I am learning how to read the PASM code and all the parts of Forth... the inner interpreter, the outer interpreter, the TIB, the PAD, and how all the more mysterious words are a part of that.

    Thanks for mentioning that the position of the file before or after the version.fth offers a choice of silient or visible loading. Both choices are handy. Silent for the finished code, visible to be sure you are loading.

    It really helps that you did follow ANS Forth in your design. I can't easily follow PropForth or Tachyon.. both are more innovative in their code. I suppose one day, I might be able to. But you provide a clearer entry point for those new to Forth as several authors have explained Forth that follows your approach.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-29 07:10
    Hi,
    I am enclosing a test loading of a 712 item data table. And the words that confirm a correct load. I have freed up space by excluding FILE directives for code I do not need.. in particular all the Chess files, the I2C files, and a few others.

    I still can't seem to get a 100% load and confirmation. I am thinking of expanding the input buffer for the TIB as it may just have run out of space.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-29 08:45
    I resolved my problems with 'Load problems.txt'. Live and learn.

    Apparently using Cut and Paste to the Serial Terminal will just about always crash, but by using a File directive to load the same file... it works cleanly everytime. This was a bit hurdle as my whole project is based on having that 712 item lookup table.

    I had been thinking that I could test everything with Cut and Paste and just run the file last, but it seems that I should have run the file first. And so, a few hours eaten up in trying different things that didn't work.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-29 18:44
    Loopy, the file "Load problems.txt" doesn't have any CR or LF's in it. The entire file consist of one very long line of text. pfth's REFILL word reads up to 200 characters, or intil it encounters a CR or LF character. The problem with using one big line is that it will be broken up into several 200-byte lines. Any words that cross a 200-byte boundary will be broken up into two pieces, and will not be handled correctly. You should reformat your file into multiple lines.

    pfth can't handle the Cut and Paste method because it does not buffer the input. It uses a simple serial driver which requires large gaps between the incoming bytes, such as would occur when a human types in characters. A buffered method would require running the serial driver in a seperate cog.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-30 04:23
    Hi Dave,
    Thanks....
    I seem to try things that stretch the boundaries a bit. It is not intentional. It is just project driven.

    I do understand that the inputbuf is only 200 bytes, so that is the size of the TIB. Something seems to be allowing this load of about 1430-50 bytes to load correctly....

    The one long line did load properly via a File directive. (Beginner's luck?)

    I am not quite sure how to break it up into 200 byte segments and tho still have is all load properly as one contiguous data array of 712 entires. The bytes are being converted from decimal to binary long values.

    I suppose I could insert the 'create lookup' and 200 entires, and then somehow insert additional blocks of 200 byte or less without names.
    I need to think of how to do this. I guess that might be my new study project.

    If the massive load does create problems, I will work up a procedure to load in 200 byte blocks. I guess that might be my new study project. I will see how the loaded .spin binary behaves today. If it is still good, this may be a back burner issue for awhile.

    ~~~~~~~~~~~~~~~~~~~~~~~~
    Other stuff.

    I needed a word to poll a pin for input status. So I have created the following. Previously I though that INPUT, OUTPUT, HIGH, and LOW were enough for basic low level i/o.

    PIN may not redundant, but I certainly needed an input polling for individual pins.

    PIN
    INPUT?

    : pin 1 swap lshift ;
    : input? ina@ swap pin and 0<> ;

    I suppose I could entirely skip the word PIN and do the following as well

    : input? ina@ swap 1 swap lshift and 0<> ;
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-30 05:49
    I wrote a program to break your Forth file up into lines that are 200 bytes or less. It didn't split any words, so that explains why it works OK when you load with the FILE directive. After the first few entries in your table everything is represented by a single decimal digit, which is why the words are split. Also, the two compiled words that you define at the end are are separate lines, so I was wrong about the whole file being one line. I've attached a version of your file that breaks the file up into 72-byte lines.

    Your input? word looks like it should work. You could also define it as

    : input? input 0<> ;

    Of course, you could just use the result from input unless you need the non-zero result to be represented as TRUE instead of 1.
  • max72max72 Posts: 1,155
    edited 2013-06-30 05:50
    With tachyon and teraterm you add an end of line delay. Putty should have the delay too, and it is also for Linux. Could it work with pfth?
    Massimo
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-30 06:04
    Adding an end of line delay would work if pfth buffered the input data. However, pfth only looks at the serial port when KEY is called. The first thing the serial driver does is look for the high-to-low transition of the stop start bit. If it misses this transition by more than one-half bit time the input value will be wrong. The REFILL word, which uses KEY is defined as a DEFER word, so it can be re-assigned later using IS. I'll look into creating a new version of KEY and REFILL that uses a buffered serial driver that runs in it's own cog.
  • max72max72 Posts: 1,155
    edited 2013-06-30 06:35
    There also is a char delay. It will slow down the terminal loading, but it should allow the time to call KEY, with no extra coding.
    At least during testing a terminal loading solution is very nice and simplifies developing and debugging.
    If it takes a little more time I guess it is and acceptable tradeoff.

    Massimo
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-30 08:49
    max72 wrote: »
    With tachyon and teraterm you add an end of line delay. Putty should have the delay too, and it is also for Linux. Could it work with pfth?
    Massimo

    Yes, a lot of serial terminal programs have the ability to delay each character and/or each line. I am aware of that and previously explored it as a fix for something else. But it really is a 'fix of last resort' in this context.

    I am aware of it, but I'd much rather verify that there is one good loading procedure than to start inserting code modifications and tweeks that may or may not be right or that mean that one has to do more complex serial terminal configuration. Beginners hit a wall when they are confronted with too much too soon.

    The buffer only being looked at when KEY is called is a difference that I did notice as one has to hit <enter> to get the first OK to come up.

    ~~~~~~~~~~~~~~~~

    @Dave

    I thought your word INPUT was a direction change, not sensing the status of an i/o PIN. Below are the word definitions I was working from.

    : high 1 swap lshift outasetbit ;
    : low 1 swap lshift outaclrbit ;
    : input 1 swap lshift diraclrbit ;
    : output 1 swap lshift dirasetbit ;
    : pin 1 swap lshift ;


    So I don't see how your
    : input? input 0<> ;
    would poll the active status of the input pin. I need to read INA with a INa@.
    Maybe.. It would just verify the direction.... not what I needed.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-30 10:22
    Loopy,

    You are correct about INPUT. I'm not that familiar with the BS2 command set, and I had forgotten that INPUT set the I/O direction. I should have remembered since I looked it up just a few days ago.

    Dave
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-06-30 10:43
    I guess INPUT? is not really BS2.. so neither of us are really keeping with my idea that pfth should offer some extremely easy to adopt terms for the i/o.

    It is an old story. It is just easy to grab whatever name comes to mind and create a new Forth word that does what I personally want it to. And yet, INPUT? makes a lot of sense to me as the ? in Forth usually indicates a query for some sort of status.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-07-02 09:31
    I am doing another New word.

    pfth has a 1 millisecond delay that is useful for most things, but I require 1/50th of 1 millisecond increments for my current project.

    To get started, I used SEE to find out how MS was constructed. And I got the following...

    see ms

    clkfreq@ _lit 1000 / * cnt@ + waitcnt drop

    And so, I created a new word, called MINIDEL for the 1/50th of 1 ms

    : minidel clkfreq@ _lit 50000 / * cnt@ + waitcnt drop ;

    So, it would seem that I could run a test such at

    cnt@ 50000 minidel cnt@ cr swap - .
    And get a figure of 80_000_000 for the difference in the beginning and ending count.

    I am not getting a consistent answer.

    Decimal format seems not to work... I am suspecting that I need unsigned subtraction and that maybe using hex will do. But I also haven't gotten anything near to 80Mhz.

    This works much better

    : minidelay 160 * cnt@ + waitcnt drop ;

    but tweeking the 160 to 158 or 159 makes it closer to the actual time interval. And I am getting reliable results... but varied by input interval with the following:

    cnt@ 500 minidelay cnt@ swap - cr . cr
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-07-02 14:54
    The _LIT word is used to encode 32-bit numbers. When executed it reads the next cell and puts it on the stack. That's the way Forth imbeds constants within a compiled word. My implementation of SEE just prints the names of the words in the definition. When SEE encounters a _LIT word it will read the next cell and print it's value. I should probably modify SEE so that it doesn't print the _LIT word. The MS word is defined as
    : ms clkfreq@ 1000 / * cnt@ + waitcnt drop ;
    
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-07-03 06:57
    Actually, having the _LIT listed is very useful and informative.

    I need to investigate the behavior of my smaller 1/50th ms delay before I am statisfied. The maths want to use unsigned 32bit numbers and I worry that using signed math might cause a negative value to creep in unintentionally.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-07-04 07:07
    @Dave Hein
    I suppose this was bound to happen. I am beginning to run out of room in spite of commenting out FILE directives that I don't need.

    So I am looking at the Long 0[1100] (actually 0[1186] in my image below] and pondering what this 'padding space' is for.

    The situation is that I have a data lookup table that is currently 712 longs. It has to go to 1067 longs due to a redesign. And I'd like to double that an go to 2134 longs.

    I could settle for reading 16 values stored in 32 bits to get the doubling so the shortage appears to mainly be 315 to 400 longs (I will have to add some code to read a 32 bit value and parse out two 16 bit numbers).

    I still can comment out see, but the attached screen shot shows what xxx.fth files are in play.
    652 x 383 - 35K
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-07-04 08:45
    Loopy, the padding is used to put the FILE section close to the end of RAM, and it provides space to put the compiled words as the files are being processed. If you don't have any padding the compiled area will overrun the FILE sections before all of the source has been processed. Also, I currently require that the zero value at the end of the FILE section not be overwritten.

    You should be able to reduce the padding to a much smaller size, but try to keep the end of the FILE section close to the end of memory.

    I wrote some code that buffers the serial input using another cog. It is in the attached file newser.txt. You could try including this in using the FILE directive. You then have to manually type NEWSER to change from the simple serial driver to the buffered serial driver. It generates a couple of garbage character on startup for some unknown reason. I haven't figured out why that happens. But after that it seems to work OK. You could try pasting text into the serial terminal to see if that works with the buffered driver. It uses a 256-byte circular buffer, so it will handle paste sizes up to 256 bytes without a problem. It might handle much larger files if the interpreter can keep up. I haven't tried pasting anything myself.

    At some point I'll make KEY a deferred word so that I can do this more cleanly. This will also make the switch from the FILE code to serial input much cleaner.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-07-04 09:36
    Thanks Dave.
    I will look at your new code and try to understand it before I comment.

    Further investigation on my part seems to indicate that I can at least get the 1034 item lookup table to fit it. That will do for now. I am just using Longs because of that is the simplest in pfth due to the cell size, but it does seem that doubling by having a words might be easy. Of course, if the project wants to double the lookup table again to over 4000, I guess the whole project will shift to PASM.

    Nonetheless, doing all the preliminary work in Forth is a wonderful way to determine what much be done in PASM. I love interactive programing for investigating motor control.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2013-07-08 01:03
    Just a progress report.
    A look up table of 4000 longs is not feasible with pfth072. At this point the basic interpreter and dictionary when cut down to minimum occupy 4970 Longs or so. With a total of 8188 Longs available and about 1000 Longs inserted for File directive padding... there just isn't much space left for both Program and Lookup Table.... though there material in the File directives will overwrite the 1000 Longs used for padding.

    Nonetheless, I am able to provide a 1067 Long Lookup table that works. It does seem that the number of decimal digits can affect the success. Reduce your File directive load files to as few bytes as you can.. even remove comments to assist a tight load. Single digit value of 1 through 9, not a problem. If you have a curve that is about 50% single digits, 48% double digits, and 2% triple digits --- the table is likely to load. But going to all triple digits seems impossible.

    The problem is that File directive images are first loaded as bytes; then compiled into Forth words that may or may not be more compact 32 bit code.

    There is not a lot of viability on when the data in the look up table will be too larger and the load is also shared with the program that exploits the lookup table. The rule of thumb is that if you can have a smaller table, you can have bigger numbers.
Sign In or Register to comment.