Jump to content
matthew180

Forth Tutorials

Recommended Posts

2- If I EDIT block 1, and I reach the end of it's 1K, what happens then if I still have more program commands to enter? Does it automatically flow into block 2 or do I have to manually perform a 2 EDIT etc...?

 

Excellent question.

 

When you get to the end of a block, you can use the word -->

 

The word --> when encountered at load time, will automatically pull in the next block from disk and continue loading. You can chain blocks together like this indefinately.

 

post-24932-0-98353400-1330008533_thumb.png

 

Note, you can use --> in the middle of a colon definition (i.e. a colon definition can span more than one block, but it's very very bad practice and liable to get you shot by the Forth Police, so don't do it!)

 

When you're in the editor, you can use CTRL O and CTRL P to move to the previous, and next block respectively.

 

Now is probably a good time to introduce you to block buffers. Most Forth systems, including TurboForth, have the notion of block buffers. The basically work like a block cache. When you request a block (with EDIT, or with LOAD, or with LIST or whatever) the requested block is loaded into (in TurboForth's case) one of six buffers (in TF these buffers are in VDP memory to keep CPU memory free for your code).

 

You can see the 'block cache' in action by typing the following (it's VERY obvious if you're using a REAL TI machine with floppy drives).

 

1 LIST

2 LIST

3 LIST

4 LIST

5 LIST

6 LIST

 

See how each request caused a trip to the floppy disk drive? Now type, say, 4 LIST again.

 

Notice how there was no round-trip to the floppy disk? That's because TF knew that block 4 was already in its cache, so it didn't bother going to the floppy disk for it.

 

When you EDIT a block, it brings it into one of the six buffers and invokes the editor. The moment you make a change in the editor (by changing the source code in any way) the buffer in which your block resides is marked as dirty (because it has been changed, so the version on disk is 'out of date' with the version in memory).

 

When you exit the editor with FCTN 9 the editor block is in the cache and will NOT be written to disk until it is FLUSHed. A flush happens under two circumstances:

  • You type FLUSH on the command line.
  • All six buffers are in use and you request a new block (that is not in the cache)

At this point, any buffers that are dirty are flushed to disk, and all the buffers are marked as clean again.

 

You'll get into the habit of exiting the editor and typing FLUSH to make sure you're edits are saved back to disk (it's fairly easy to crash all Forth systems, since you are completely free to screw up in any way you see fit!)

 

Note that you can also load code directly from the cache! You don't have to do anything special to do that; if the block requested is in the cache then it gets served to the compiler/editor/whatever from the cache.

 

Finally, if you are editing a block and you screw up, just press FCTN =. This will exit the editor but it will NOT mark the buffer/block as dirty. It will actually mark the buffer in which that block was residing as empty, which will force the original block to be re-loaded when you edit it again.

 

Okay, that's probably quite a lot to digest in one hit! I hope this makes sense. It's actually very natural... There's a cache between you and the block hosting device; be that a ram disk, hard disk, floppy disk, CF7, whatever...

 

Please feel free to ask further questions!

Share this post


Link to post
Share on other sites

@Vorticon...

 

One point to always keep in mind when editing Forth blocks: Within a Forth block, the only "white" space that separates one Forth word (or other Forth entity) from its neighbors is one or more spaces. In particular, there are no embedded carriage-return characters at the ends of lines that could act in this capacity, as they do in other programming languages. When you get to the end of a line, your typing character-wraps around to the next line until you get to the end of the block, at which point it jumps back to the first position of the same (last) line.

 

As long as I have been programming in Forth, I still trip over this gotcha. It has caused insidious bugs in my programs that always prompt me to smack my forehead when I realize what I have done!

 

Again, if there is no intervening space between the string of characters at the end of one line and the string of characters at the beginning of the next line, the latter string is the continuation of the former and, thus, part of the same word.

 

...lee

Share this post


Link to post
Share on other sites

Indeed. Well put, Lee. Simply put, a block is *displayed* for human convenience as 16 lines of 64 characters, but forth sees it as a single 1024 character long line.

Share this post


Link to post
Share on other sites

Forthies,

 

I want to draw bit mapped images using TF which I assume can be done by putting the right data in the right VDP memory locations using v!. Could anyone reply with a short tutorial on drawing a bit mapped line, square, or a circle using forth?

Share this post


Link to post
Share on other sites

Forthies,

 

I want to draw bit mapped images using TF which I assume can be done by putting the right data in the right VDP memory locations using v!. Could anyone reply with a short tutorial on drawing a bit mapped line, square, or a circle using forth?

 

Uh...not so much, unfortunately. Mark has not implemented bitmap graphics for Turboforth. That is one thing you can do in TI Forth that you cannot easily do in Turboforth. The biggest problem with implementing bitmap graphics is that VDP memory has to be organized significantly differently from what it is in the other text and graphics modes. To get an idea of the difficulty, look at the "Section 21 Color, Graphics and Sprites" in the TI Editor/Assembler Manual and the VDP Memory Map in Chapter 4 of the TI Forth Instruction Manual. We could write some Forth code to do it, I am sure---but it is not trivial. In particular, disk buffering gets short shrift as do some other buffers.

 

You could do some rudimentary plotting by manipulating the available characters in clever ways as is done in pretty much all the games written in TI BASIC and TI Extended BASIC; but, you cannot plot one pixel at a time without putting the 9918A into bitmap mode.

 

...lee

Share this post


Link to post
Share on other sites

I am having a problem when I try to increment a variable I am using as a counter. When I execute this code I expect to have 10 printed to the screen but what I get is ERROR:COUNTER not found. Anyone know what I am doing wrong here?

 

VARIABLE COUNTER
0 COUNTER !
10 0 DO COUNTER @ 1 + COUNTER ! LOOP ;
COUNTER @ .

Edited by idflyfish

Share this post


Link to post
Share on other sites

The loop needs to go inside a colon definition. Some words, like DO etc can only be compiled - not executed on the command line...

 

 

VARIABLE COUNTER

0 COUNTER !

: TEST 10 0 DO COUNTER @ 1 + COUNTER ! LOOP ;

TEST

COUNTER @ .

 

Share this post


Link to post
Share on other sites
Uh...not so much, unfortunately. Mark has not implemented bitmap graphics for Turboforth. That is one thing you can do in TI Forth that you cannot easily do in Turboforth. The biggest problem with implementing bitmap graphics is that VDP memory has to be organized significantly differently from what it is in the other text and graphics modes. To get an idea of the difficulty, look at the "Section 21 Color, Graphics and Sprites" in the TI Editor/Assembler Manual and the VDP Memory Map in Chapter 4 of the TI Forth Instruction Manual. We could write some Forth code to do it, I am sure---but it is not trivial.

It's not for Forth, but for Pascal and the p-system, but you can get an idea of the complexity of forcing such functionality onto a system not really desgined for it by looking at what I did to implement bit-map graphics in the p-system. You can also see routines for drawing straight lines and writing characters anywhere on the screen (not limited to the normal 32*24 positions, but where a character can have it's upper left corner at any pixel)

 

Link here

Share this post


Link to post
Share on other sites

It can be done in TurboForth, however it would seriously impact on the block buffer functionality, since the screen and block buffers would overlap.

 

That might not really be a problem though; If your program doesn't access the disk drive after it has loaded, then you could safely invoke bitmap mode and have at it, without a care in the world for the block buffers. At the end of your program, a simple COLD command would restore the system.

 

However, I personally have never done any work in bitmap mode; I would need someone to write optimised line drawing routines (Bresenham for diagonal lines and optimised routines for horizontal and vertical would be best) and circle drawing.

 

Probably the best person for that job is Sometimes, as he has done a lot of bitmap work over the years.

 

It could exist as a simple loadable extension.

 

Mark

Share this post


Link to post
Share on other sites

Feel free to use the simple straight line routines that are in my files, which I linked to above. I didn't bother with circles at that time. I don't think I was aware of the Bresenham algorithm when I did my implementation, but just did the first that came to my mind. Internet as we know it didn't exist back then, so finding information was slower.

 

A good feature with the p-system, when doing modifications like this one, is that it's from the beginning designed to be portable. I don't think there's any data anywhere in that system that's not referenced via some pointer, so you can easily move whole chunks of system data if you need to.

Edited by apersson850

Share this post


Link to post
Share on other sites

How does one clear the stack short of using ABORT" ?

 

 

 

S0 SP!

 

will do it. S0 (0 is "zero") is the address of the base of the stack and SP! uses it to reset the stack. You can actually put the stack somewhere else, if you like. Just be sure there is enough room for the stack to grow upwards in memory for a reasonable distance.

 

...lee

Edited by Lee Stewart

Share this post


Link to post
Share on other sites

OK I think this Forth thing is going to take me a while to wrap my head around... I REALLY need a complete TF manual Willsy!!!

In any case, I was creating an extremely elemental test program just to get used to TF a bit, and immediately ran into trouble. The program below is supposed to clear the screen, set the background color to dark green, define a sprite, display it and wait for a key press before exiting. Couldn't be simpler, right? WRONG!!!

 

PAGE

1 GMODE

12 SCREEN

DATA 4 $18BD $FFBD $3CBD $FFBD 384 DCHAR

0 15 10 384 15 SPRITE

: WAIT BEGIN KEY? -1 = UNTIL ;

QUIT

 

I keep getting a stack underflow error. Furthermore, when I define the WAIT word on the command line as above, I expect for the system to wait for a key press, but I simply get OK:0 and I'm back at the command line.

Can someone please point out to me where I'm screwing up?

If I can't even get something so simple to work, how can I possibly expect to write more complex programs? Maybe I'm too old to learn something so deviant from the classic languages I cut my programming teeth on. Heck even assembly was simpler...

Share this post


Link to post
Share on other sites

OK I think this Forth thing is going to take me a while to wrap my head around... I REALLY need a complete TF manual Willsy!!!

In any case, I was creating an extremely elemental test program just to get used to TF a bit, and immediately ran into trouble. The program below is supposed to clear the screen, set the background color to dark green, define a sprite, display it and wait for a key press before exiting. Couldn't be simpler, right? WRONG!!!

 

PAGE

1 GMODE

12 SCREEN

DATA 4 $18BD $FFBD $3CBD $FFBD 384 DCHAR

0 15 10 384 15 SPRITE

: WAIT BEGIN KEY? -1 = UNTIL ;

QUIT

 

I keep getting a stack underflow error. Furthermore, when I define the WAIT word on the command line as above, I expect for the system to wait for a key press, but I simply get OK:0 and I'm back at the command line.

Can someone please point out to me where I'm screwing up?

If I can't even get something so simple to work, how can I possibly expect to write more complex programs? Maybe I'm too old to learn something so deviant from the classic languages I cut my programming teeth on. Heck even assembly was simpler...

 

What you have done is issue a series of commands and defined one word (WAIT). A program in Forth is actually a word that you usually write other words to support.

 

You cannot use DATA outside a colon definition---probably the cause of the underflow. Also, contrary to the TF Wordlist document, UNTIL repeats the BEGIN ... UNTIL block on a false flag. UNTIL is looking for a true flag to exit the loop.

 

You could write something like the following:

 

: SPR0 DATA 4 $18BD $FFBD $3CBD $FFBD 384 DCHAR ;

: SHOW0 0 15 10 384 15 SPRITE ;

: WAIT BEGIN KEY? 13 > UNTIL ;

: DOSPR0 PAGE 1 GMODE 12 SCREEN SPR0 SHOW0 WAIT ;

 

Then, run the "program" DOSPR0 by typing it on the command line. You do not need QUIT here.

 

I changed -1 to 13 (ASCII code of <Enter>) because the loop in WAIT (in Classi99, at least) is fast enough to catch <Enter> bouncing. Of course, <Enter> won't stop the loop, now.

 

...lee

Share this post


Link to post
Share on other sites

What you have done is issue a series of commands and defined one word (WAIT). A program in Forth is actually a word that you usually write other words to support.

 

You cannot use DATA outside a colon definition---probably the cause of the underflow. Also, contrary to the TF Wordlist document, UNTIL repeats the BEGIN ... UNTIL block on a false flag. UNTIL is looking for a true flag to exit the loop.

 

You could write something like the following:

 

: SPR0 DATA 4 $18BD $FFBD $3CBD $FFBD 384 DCHAR ;

: SHOW0 0 15 10 384 15 SPRITE ;

: WAIT BEGIN KEY? 13 > UNTIL ;

: DOSPR0 PAGE 1 GMODE 12 SCREEN SPR0 SHOW0 WAIT ;

 

Then, run the "program" DOSPR0 by typing it on the command line. You do not need QUIT here.

 

I changed -1 to 13 (ASCII code of <Enter>) because the loop in WAIT (in Classi99, at least) is fast enough to catch <Enter> bouncing. Of course, <Enter> won't stop the loop, now.

 

...lee

Thanks Lee. I apologize for my obvious frustration last night, but you can see why... Without a proper manual to guide the Forth newbies, this can devolve into a very discouraging experience. Nowhere have I come across your explanation above which by the way is nice and clear, and I certainly did not know about the error in the TF wordlist document regarding BEGIN-UNTIL, which is the only document I have on TF. I did read Brodie's book (1st edition) and it's a nice introduction to Forth in general, but it has too many diversions from TF to make it a useful manual or practical.

TF is clearly a very powerful language which from the looks of it is continuously being improved, but I don't see it broadening its user base aside from a select few already heavily versed in Forth like yourself, Rod and a handful of others without solid documentation.

Willsy did give me a glimpse of his early TF manual, but it's still very incomplete, although an extremely easy read.

OK I'm done whining now. I'll work on it some more tonight.

Share this post


Link to post
Share on other sites

Hi guys

 

With reference to documentation, I stand guilty as charged. I've done the best I can do without actually publishing the book. There is a word glossary on the TF website (sorry about the UNTIL error :dunce: I'll fix it) and there is also a growing list of tutorials on the site.

 

Short of that, just ask. We really really don't mind. I *fully* understand your frustration. I was exactly the same about three years back when I started to look at the language just out of idle curiosity. Then I had a massive "oh! I get it!" moment.

 

You were getting tripped up by not using DATA in a colon definition. On that one, "Not guilty your honour!" - It does say on the TF website that it should only be used in a colon def.

 

You're probably wondering why some words have to be used in a colon definition? Well, to cut a long story short, these words are macro's. They often compile some code into your colon definition in the background, as it is being compiled, so to speak. DATA is a good example. It compiles code into your colon definition such that, when your colon definition *executes* the number of data items, and the address of the start of those data items is pushed to the stack. In Forth, these 'magic' words are known as immediate words. Immediate words are covered in the book.

 

I know I know... where is the book!????!!! Well, it's on hold until V1.2 is finished. V1.2 is very close to being finished. This *will* be the last revision of TF. So the book will be targeted to V1.2. This means re-visiting previously completed chapters and revising them, so I've held off completing the book until it's done and frozen. As soon as I've finished tinkering with V1.2 I'll be straight onto the book.

 

You're gonna love it! Just hang in there a bit longer!

 

Mark

Share this post


Link to post
Share on other sites

Some comments on your test program. I know you're only taking tentative steps, so this is not a criticism - just little pointers here and there...

 

GMODE clears the screen for you, so no need for PAGE (though of course it doesn't do any harm).

 

If all you want to do is pause the program until a key is pressed, then use KEY and DROP the result:

 

: WAIT KEY DROP ;

 

Though, as Lee pointed out, it might be too fast - the entire program may have executed before your finger comes off the enter key... Nice that we can say that for once about the TI in anything other than assembly language, huh? :-D

 

Mark

Share this post


Link to post
Share on other sites

: WAIT KEY DROP ;

 

There is a cosmetic problem with this solution: KEY displays a blinking cursor, whereas KEY? does not. Of course, that may, in fact, be desirable.

 

...lee

Share this post


Link to post
Share on other sites

There is a cosmetic problem with this solution: KEY displays a blinking cursor, whereas KEY? does not. Of course, that may, in fact, be desirable.

 

...lee

 

Yes, that is why I chose KEY? instead of KEY. It's just neater :)

Share this post


Link to post
Share on other sites

Hi guys

 

With reference to documentation, I stand guilty as charged. I've done the best I can do without actually publishing the book. There is a word glossary on the TF website (sorry about the UNTIL error :dunce: I'll fix it) and there is also a growing list of tutorials on the site.

 

Short of that, just ask. We really really don't mind. I *fully* understand your frustration. I was exactly the same about three years back when I started to look at the language just out of idle curiosity. Then I had a massive "oh! I get it!" moment.

 

You were getting tripped up by not using DATA in a colon definition. On that one, "Not guilty your honour!" - It does say on the TF website that it should only be used in a colon def.

 

You're probably wondering why some words have to be used in a colon definition? Well, to cut a long story short, these words are macro's. They often compile some code into your colon definition in the background, as it is being compiled, so to speak. DATA is a good example. It compiles code into your colon definition such that, when your colon definition *executes* the number of data items, and the address of the start of those data items is pushed to the stack. In Forth, these 'magic' words are known as immediate words. Immediate words are covered in the book.

 

I know I know... where is the book!????!!! Well, it's on hold until V1.2 is finished. V1.2 is very close to being finished. This *will* be the last revision of TF. So the book will be targeted to V1.2. This means re-visiting previously completed chapters and revising them, so I've held off completing the book until it's done and frozen. As soon as I've finished tinkering with V1.2 I'll be straight onto the book.

 

You're gonna love it! Just hang in there a bit longer!

 

Mark

 

Thanks Willsy. I know I'm gonna love it, which is why the wait is so darn hard!

Please don't let my newbie frustration imply that I do not appreciate the immense effort you put into developing TF (what were you thinking???!!!). It's blazing fast and relatively easy to interface with assembly, and I have great plans for it :)

Share this post


Link to post
Share on other sites

OK I have a few more questions:

 

Since most programs will span more than one screen, how does one load all the screens at once? Also, when I edit a particular screen, I have to reload it and as expected I then get a string of redefined warnings. Is there another way to do this?

Finally, I'm not completely clear on SMLIST and SPRMOV:

 

0 -2 0 SMLIST should set up a movement vector straight up for sprite 0

0 1 SPRMOV should move ONLY sprite 0 according the its previously defined SMLIST vector

Am I correct so far? Now if I change SMLIST, do I need to issue another SPRMOV or does the sprite simply change direction and/or velocity?

 

As you might have guessed, I'm having problems getting sprites to move and I wanted to double check that I understood the above words correctly...

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...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...