Jump to content
matthew180

Forth Tutorials

Recommended Posts

Lee, it seems there is something funny going on with the -TRACE option in TIF.

When I try to load it, I get the following:

 

-TRACE : isn't unique. ok

This is normal because : has just been redefined.

 

I also get a couple of numbers on the stack, namely 0 and 5.

Are you sure the 0 and 5 were not on the stack prior to issuing -TRACE ? Two numbers like that often mean a bad definition was detected. ERROR gets called, the stack is cleared and, usually, two numbers are left on the stack to aid in debugging. The top number is the block that was being interpreted when the error occurred (0, if from the console). The next number is the byte offset of the next character that was about to be accepted when the error occurred. If there was an interpreter error that caused the two numbers on the stack, there should have been an error message. See the definitions of ERROR , WARNING , IN , BLK and ABORT . Otherwise, there may be something wrong on screen/block 44.

 

Subsequently, I get no errors when I execute the word TRACE, but again I get a couple of numbers placed on the stack.

 

I came across this while testing the recursion example on page 29 of your TIF manual which incidentally is missing an IF in the colon definition as it should be

: FACT DUP 1 > IF DUP 1 - MYSELF * ENDIF ;

Nice catch! :-o Thanks. I will correct it in the second edition. It was my mistake because the original is correct.

 

Tracing the execution of the above using TRON gives me correct stack results except for 2 additional unchanging digits at the bottom of the stack.

 

Am my missing something or is there a problem with TRACE?

 

Walid

There may, in fact, be something wrong. Make sure your screen 44 is the same as the one in Appendix I. I ran the examples and got the expected results with no extra numbers on the stack.

 

...lee

Edited by Lee Stewart

Share this post


Link to post
Share on other sites

I checked screen 44 and it is identical to the listing in Appendix I.

However, I was able to solve the problem by executing SP! to clean the stack before initiating a trace with TRON, and now I got good results.

Do I need to always use SP! after running TRACE?

Share this post


Link to post
Share on other sites

I checked screen 44 and it is identical to the listing in Appendix I.

However, I was able to solve the problem by executing SP! to clean the stack before initiating a trace with TRON, and now I got good results.

Do I need to always use SP! after running TRACE?

No. You should, however, always be aware of what is or is not on the stack and what should or should not be there. TRACE should not put anything on the stack itself that it does not take off. The only thing left on the stack should be the results from the words you're executing. You can always run .S to see if there's anything on the stack and run SP! if there is. One thing that always seems to pull me up short with TIF is that a messed up definition always leaves 2 numbers on the stack. As with you, I often forget to clear the stack after that. I really miss TF's always giving you how many numbers are on the stack after the "ok". In fact, I am seriously considering modifying TIF to do just that! It's really useful.

 

...lee

Share this post


Link to post
Share on other sites

No. You should, however, always be aware of what is or is not on the stack and what should or should not be there. TRACE should not put anything on the stack itself that it does not take off. The only thing left on the stack should be the results from the words you're executing. You can always run .S to see if there's anything on the stack and run SP! if there is. One thing that always seems to pull me up short with TIF is that a messed up definition always leaves 2 numbers on the stack. As with you, I often forget to clear the stack after that. I really miss TF's always giving you how many numbers are on the stack after the "ok". In fact, I am seriously considering modifying TIF to do just that! It's really useful.

 

...lee

Lee, the manual states that SP! Should always precede .S, and if I execute .S without it then I get 2 numbers on the stack. The same happens of I execute a . command when the stack is empty.

I believe this was what was confusing me. Now that I understand how TIF handles errors, at least I can anticipate the stack state. Thanks for the explanation :-)

Share this post


Link to post
Share on other sites

Lee, the manual states that SP! Should always precede .S, and if I execute .S without it then I get 2 numbers on the stack. The same happens of I execute a . command when the stack is empty.

I believe this was what was confusing me. Now that I understand how TIF handles errors, at least I can anticipate the stack state. Thanks for the explanation :-)

If you always execute SP! before any .S command, the stack will always be empty. The purpose of .S is to let you see what's on the stack without removing any numbers and without throwing an error when the stack is empty, so you should not get any extra numbers (or ERROR-produced numbers) when it is executed. I think you'll find that the manual says that SP! should be typed before executing a routine that contains .S . You should get 2 unexpected numbers on the stack only when there's an error like executing . on an empty stack---or, for that matter, executing any word that expects something on the stack when the stack is empty.

 

...lee

Share this post


Link to post
Share on other sites

I found an online version of Brodie's Starting Forth and a link at the end for Thinking Forth. Pretty nice.

http://home.iae.nl/users/mhx/sf.html

Very nice, indeed---especially the 1st edition of Starting Forth for use with TI Forth. The 2nd edition is better for TurboForth because it is Forth-83 compliant.

 

...lee

Share this post


Link to post
Share on other sites

I really miss TF's always giving you how many numbers are on the stack after the "ok". In fact, I am seriously considering modifying TIF to do just that! It's really useful.

 

...lee

 

Yeah, it's nice, isn't it?! It's especially nice/useful when you're a newbie. I think I stole the idea from another Forth system somewhere. If TIF has DEPTH it should be relatively easy to modify. In TF, the OK:x is displayed by INTERPRET when it has reached the end of the input buffer.

Share this post


Link to post
Share on other sites

Yeah, it's nice, isn't it?! It's especially nice/useful when you're a newbie. I think I stole the idea from another Forth system somewhere. If TIF has DEPTH it should be relatively easy to modify. In TF, the OK:x is displayed by INTERPRET when it has reached the end of the input buffer.

Well, in TIF, it is QUIT that displays " ok". DEPTH is not part of TIF. I would need to modify the ALC for the resident TIF vocabulary to manage it. That would be painful, but instructive. I have always wanted to try modifying the system. The process is complicated:

  1. Modify ALC of resident vocabulary.
  2. Assemble to FORTH2 object file.
  3. Check listing file for size. (The limit has to do with where on the system disk the end of FORTHSAVE lands, not CPU RAM space. FORTHSAVE cannot be allowed to step on the system Forth screens/blocks. To allow that to happen would require a total rewrite of the TIF system screens because system screen references are so convoluted. Rewriting the system screens might also break extant TI Forth code written over the years.)
  4. If (3) is OK, Load FORTH1, FORTH2 and FSAVE (I haven't released this utility yet, but I have written a quick-and-dirty version) and run FSAVE to save FORTHSAVE.
  5. Modify FORTH (the TIF boot program) to properly copy the correct number of bytes (the new size of FORTHSAVE) to CPU RAM.
  6. Build the new TIF system disk. (I have worked this out in principle, but not in detail!)

The really nice thing about the resident vocabulary is that references can easily be made to words defined later in the dictionary because the words are always there and the references are made directly, not by a dictionary search.

 

...lee

Share this post


Link to post
Share on other sites

Yeah, it's nice, isn't it?! It's especially nice/useful when you're a newbie. I think I stole the idea from another Forth system somewhere. If TIF has DEPTH it should be relatively easy to modify. In TF, the OK:x is displayed by INTERPRET when it has reached the end of the input buffer.

 

Well, in TIF, it is QUIT that displays " ok". DEPTH is not part of TIF. I would need to modify the ALC for the resident TIF vocabulary to manage it. That would be painful, but instructive. I have always wanted to try modifying the system. The process is complicated:

  1. Modify ALC of resident vocabulary.
  2. Assemble to FORTH2 object file.
  3. Check listing file for size. (The limit has to do with where on the system disk the end of FORTHSAVE lands, not CPU RAM space. FORTHSAVE cannot be allowed to step on the system Forth screens/blocks. To allow that to happen would require a total rewrite of the TIF system screens because system screen references are so convoluted. Rewriting the system screens might also break extant TI Forth code written over the years.)
  4. If (3) is OK, Load FORTH1, FORTH2 and FSAVE (I haven't released this utility yet, but I have written a quick-and-dirty version) and run FSAVE to save FORTHSAVE.
  5. Modify FORTH (the TIF boot program) to properly copy the correct number of bytes (the new size of FORTHSAVE) to CPU RAM.
  6. Build the new TIF system disk. (I have worked this out in principle, but not in detail!)

The really nice thing about the resident vocabulary is that references can easily be made to words defined later in the dictionary because the words are always there and the references are made directly, not by a dictionary search.

 

...lee

 

H-m-m-m... There are 3 cells (6 bytes) in QUIT where the "print ' ok' code" is located. I could define ok as the first word loaded from the system disk after the resident system is booted. I would then need to add code after ok to patch the relevant location in QUIT (10E6h) with the CFAs of ok NOP NOP to fill in those 3 cells. Of course, I could define DEPTH just before ok to then use DEPTH in ok . This will be much, much easier than my proposal above!! :!: :-o I'll post the code when I figure it out.

 

...lee

Share this post


Link to post
Share on other sites

How about you just write right over the top of QUIT ?

 

Sounds extreme, but hold on there just a mo... If you write straight over the top of QUIT with something like this:

 

LIT xxxx @ EXECUTE BRANCH -10

 

Then you can vector TIF's QUIT with your own. xxxx represents a convenient address somewhere to fetch the address your QUIT from...

Share this post


Link to post
Share on other sites

H-m-m-m... There are 3 cells (6 bytes) in QUIT where the "print ' ok' code" is located. I could define ok as the first word loaded from the system disk after the resident system is booted. I would then need to add code after ok to patch the relevant location in QUIT (10E6h) with the CFAs of ok NOP NOP to fill in those 3 cells. Of course, I could define DEPTH just before ok to then use DEPTH in ok . This will be much, much easier than my proposal above!! :!: :-o I'll post the code when I figure it out.

 

...lee

 

Hmmm... Just re-read that and allowed it to sink in. Yep. That would work. Nice! :thumbsup:

Share this post


Link to post
Share on other sites

H-m-m-m... There are 3 cells (6 bytes) in QUIT where the "print ' ok' code" is located. I could define ok as the first word loaded from the system disk after the resident system is booted. I would then need to add code after ok to patch the relevant location in QUIT (10E6h) with the CFAs of ok NOP NOP to fill in those 3 cells. Of course, I could define DEPTH just before ok to then use DEPTH in ok . This will be much, much easier than my proposal above!! :!: :-o I'll post the code when I figure it out.

 

...lee

 

OK, for a TurboForth-like "ok:n" for TI Forth, here's the TI Forth code to do it:

 

: DEPTH [email protected] S0 @ SWAP - 1 SRA ;
: ok ." ok:" DEPTH . ;
' NOP CFA DUP ' ok CFA [email protected] HEX B0E6 3 MOVE DECIMAL

 

You will note that the "10E6h" mentioned above became "B0E6h" because the boot program started loading the resident dictionary at A000h, not 0000h. The 10E6h was from relocatable code. Also, note that there should be 2 spaces between ." and ok in the definition of ok . The AtariAge editor strikes again!

 

...lee

Edited by Lee Stewart

Share this post


Link to post
Share on other sites

Which screen would this feature be ideally put in?

 

It actually doesn't matter. It will take effect as soon as it is executed. Because it is so useful, it should probably be loaded right after any BLOADed screens somewhere on screen 3. You can probably make room there for all the code, but all you need to do is put the code on an available screen, say 89. Then, put the following code on screen 3 where you want screen 89 to LOAD :

In DECIMAL mode---

89 CLOAD ok ( Patch QUIT with new "ok:n")

In HEX mode---

59 CLOAD ok ( Patch QUIT with new "ok:n")

I have not tested this, yet. I screwed up my MESS installation and must re-install before I can actually write to my TI Forth Screens. I've only tested it from the command line after the system was already booted, where it worked very well. I don't anticipate a problem, but you never know.

 

...lee

Share this post


Link to post
Share on other sites

Regarding patching QUIT with the code in my previous post: Always keep careful records (preferably, in the code) of any direct memory references such as in this patch because, in later changes you might make, they will eat your lunch!

 

...lee

Share this post


Link to post
Share on other sites

I tried the patch as you suggested and it works great! Thanks :)

 

I should clean up the code to avoid surprises. In TI Forth screens that are LOADed by other screens, you should always start the screen with BASE->R and end it with R->BASE . Then, in between, you can change the base to your heart's content because it will always be restored to what it was coming into the screen! You should also probably restore any BASE->R temporarily prior to a CLOAD and putting it back to the return stack after the call because weird things can happen if the conditional LOAD ( CLOAD ) is aborted for some reason. So here's the "clean" code for screen 89 in my example scenario:

( Patch QUIT with new "ok:n")
BASE->R
: DEPTH [email protected] S0 @ SWAP - 1 SRA ;
: ok ." ok:" DEPTH . ;
' NOP CFA DUP ' ok CFA [email protected] HEX B0E6 3 MOVE
R->BASE

And, here's the conditional LOAD on screen 3, which presumes an opening BASE->R ahead of it:

R->BASE DECIMAL 89 CLOAD ok ( Patch QUIT with new "ok:n") BASE->R

 

...lee

Share this post


Link to post
Share on other sites

Watching the debate and playing around with TurboForth.

 

I am back on http://turboforth.ne.../tutorials.html again.

 

I have to admit that I like how this was written for a beginner, while keeping programmers (C/Basic/Etc) in mind.

 

That's good to know, thank you. You'll hopefully have noticed that it was updated (Just yesterday, actually). I'll keep adding to it over the next couple of weeks.

Share this post


Link to post
Share on other sites

Sorry, I did not notice.. Do not feel bad though. Keep in mind that the first day I just glanced at it and tried a couple statements.

 

Yesterday I actually checked out conditional statements and loops.

 

I really have no desire to create games and I trying to figure out how I could apply it. You all really have an interesting hobby of maintaining a programming language on the TI. I never expected to find this out when browsing the web to see if the TI-99/4A still has any users in the hobby arena. I was just expecting Gamers and Hardware Hackers.. :-)

Edited by slinkeey

Share this post


Link to post
Share on other sites

Hi.

I wrote the following code in TI Forth as a quick test of bitmap mode:

 

GRAPHICS2
: CLRSCR HEX 2000 1800 0 VFILL DECIMAL ;
: TDRAW 160 70 190 130 LINE 190 130 130 130 LINE 130 130 160 70 LINE ;
: START BEGIN TDRAW CLRSCR AGAIN ;
START

 

Essentially draw a triangle in bitmap, erase the bitmap screen, do it again. Couldn't get simpler than that.

Well, the triangle gets drawn, but then only about 2/3 of the screen is erased and the computer locks up. When I checked how TIF sets up the bitmap mode in screen 54, the color table is at >0000, the PDT at >2000 and the SIT at >1800, so I don't understand why my CLRSCR word is acting up since I am zeroing >1800 bytes starting at address >2000...

Help please?

 

Sorry one more thing. What is wrong with the code below? I'm trying to load an array with a string of numbers (triangle vertices), and it's not working...

0 VARIABLE TRIANGLE 10 ALLOT
: TINIT 6 0 DO I 2 * TRIANGLE + SWAP ! LOOP ;
160 70 190 130 130 130 TINIT

Edited by Vorticon

Share this post


Link to post
Share on other sites

Hi.

I wrote the following code in TI Forth as a quick test of bitmap mode:

 

GRAPHICS2
: CLRSCR HEX 2000 1800 0 VFILL DECIMAL ;
: TDRAW 160 70 190 130 LINE 190 130 130 130 LINE 130 130 160 70 LINE ;
: START BEGIN TDRAW CLRSCR AGAIN ;
START

 

Essentially draw a triangle in bitmap, erase the bitmap screen, do it again. Couldn't get simpler than that.

Well, the triangle gets drawn, but then only about 2/3 of the screen is erased and the computer locks up. When I checked how TIF sets up the bitmap mode in screen 54, the color table is at >0000, the PDT at >2000 and the SIT at >1800, so I don't understand why my CLRSCR word is acting up since I am zeroing >1800 bytes starting at address >2000...

Help please?

 

You should probably avoid using a number base change inside a colon definition because it doesn't do what you think it does. The definition of CLRSCR actually uses what number base was in effect when the definition was compiled, i.e., likely DECIMAL . When CLRSCR executes, it puts TIF in HEX mode prior to writing to VDP RAM and then puts TIF in DECIMAL mode afterwards, accomplishing nothing more than slowing down CLRSCR . Your code actually wrote 1800 (708h) bytes starting at VDP RAM location 2000 (7D0h). If you put TIF in HEX mode before the definition of CLRSCR and restore DECIMAL after it, it works fine. Your code now looks like

 

GRAPHICS2
HEX
: CLRSCR 2000 1800 0 VFILL ;
DECIMAL
: TDRAW 160 70 190 130 LINE 190 130 130 130 LINE 130 130 160 70 LINE ;
: START BEGIN TDRAW CLRSCR AGAIN ;
START

 

Also, you do realize that START is an uninterruptible, infinite loop, right?

 

...lee

Share this post


Link to post
Share on other sites

...

Sorry one more thing. What is wrong with the code below? I'm trying to load an array with a string of numbers (triangle vertices), and it's not working...

0 VARIABLE TRIANGLE 10 ALLOT
: TINIT 6 0 DO I 2 * TRIANGLE + SWAP ! LOOP ;
160 70 190 130 130 130 TINIT

 

Remove the SWAP . Your calculated address is already in the correct position for ! .

 

...lee

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...