Jump to content
  • entries
    4
  • comments
    13
  • views
    6,970

Lesson 2: More fbForth 2.0 Fundamentals


Lee Stewart

1,318 views

This lesson will discuss more of the details of RAM organization, working with the stack and some minimal Forth programming.

The 32 KiB expansion RAM on the TI-99/4A is organized as follows in fbForth 2.0: The 8 KiB lower RAM (2000h – 3FFFh) contains four fbForth block buffers, low-level Assembly Language support, system global variables (termed “user variables”) and the return stack. You will notice here that hexadecimal numbers in this discussion (not in actual Forth code!) have a trailing ‘h’. The return stack starts at the top of this space at 3FFEh and grows downward toward the low-level support code, which currently ends at 3A03h. This allows 766 cells for address storage for deeply nested code. Colon ( : ), introduced in the last lesson, makes extensive use of the return stack. Your code can make use of the return stack as well; but, you must be very, very careful when you do, that you do not interfere with the return scheme of fbForth. In a later lesson we will discuss how to safely use the return stack because it certainly can be useful.

The 24 KiB upper RAM (A000h – FFFFh) is almost entirely free for your Forth programming pleasure. This is due to the fact that the entire resident dictionary of fbForth 2.0 resides in the 32 KiB ROM of the cartridge. The last word of the resident dictionary is TASK and resides at A000h for reasons that will be explained in a later lesson. The next available address is A00Ch. This is the beginning of the user-definable dictionary. Any words defined after this point are still part of the dictionary and, as a result, become part of the language. This is what makes Forth extensible.

The top of memory in the upper 24 KiB area contains the Terminal Input Buffer (TIB) and the base of the parameter stack at FFA0h. This means that all but 108 bytes of the upper 24 KiB area is available for your programming. This, of course, includes the parameter stack, which grows downward toward the dictionary, which grows upward toward the stack.

Now is a good time to elaborate on a comment Owen left on the last lesson, viz., verbalizing or pronouncing Forth words. Forth was intended to be a language you could speak. That is pretty much why Forth functions, routines, constants and variables are called “words”. I will try to remember to include the usual pronunciation of standard Forth words as we discuss them. A very good source for such pronunciations is Derick and Becker’s FORTH Encyclopedia: The Complete FORTH Programmer’s Manual, 2nd Edition. The words appear in ASCII order, so they are easy to find. Each of the entries includes the word’s pronunciation. An example from the last lesson is SP! , which is usually pronounced “S-P-store”. The “SP” part happens to refer to the stack pointer, which is why I had said “stack pointer store”. Another example, as Owen mentioned, is “dot-quote” for ." and “quote” for " .

Most words’ pronunciations are not difficult to figure out; but, there are a couple of heavily used words that are not obvious. One is @ , which is pronounced “fetch” because it pops an address from the stack and fetches its contents to the stack. Another is ! , which is pronounced “store”. It requires two numbers on the stack: the number to store and the address in which to store it. We will discuss these in greater detail ere long.

We turn our attention, now, to working with the stack. As mentioned last time, it operates in a LIFO mode. To show you how it works, we will use . and a new word, .S (pronounced “dot-S” and means “print stack”). .S will non-destructively print the stack contents from the bottom up (left to right), with ‘|’ representing the bottom of the stack. Recall that . pops the top number off the stack and prints it:

blogentry-29677-0-85051100-1436976895.png


You will see that the system response of “ok:5” displayed after .S is executed shows the stack to have the same depth as before it was executed. Notice that the last of the five numbers entered is on top of the stack, that it is the first one popped and printed by . and that the system response shows the depth to be one less after each . . The last line demonstrates what happens when you execute a word requiring a number on the stack but with nothing on the stack. The number 11776 (2E00h) printed is significant because the bottom edge of the stack is the start of the TIB and the last thing entered at the terminal (console) was ‘ . ’, which has an ASCII code of 2Eh.

A Forth convention when defining or listing words is to show the state of the stack before and after the word executes. The stack effects (also, stack signature) are indicated by showing within parentheses what the word expects on top of the stack before it executes to the left of an em-dash (—) (or two or three dashes [--]) and what it leaves on the stack to the right. Also, the most accessible number is always on the right on either side of ‘--’, which represents execution of the word. For example:

!   ( n addr -- )

shows that the stack effects of ! , which requires the storage address addr to be on top of the stack and the number n, which will be stored at addr, below it. The absence of anything to the right of the execution indicator (--) shows that ! leaves nothing on the stack.


Let's do a little math with the stack. We will start with the basic four: addition, subtraction, multiplication and division. Here are those definitions with their stack effects:

+   ( n1 n2 -- sum )    pronounced “plus”
-   ( n1 n2 -- diff )   pronounced “subtract”
*   ( n1 n2 -- prod )   pronounced “times”
/   ( n1 n2 -- quot )   pronounced “divide”

Each of these operators requires two numbers on the stack and leaves the result on the stack when it is done. Below are examples of each operation, showing the result printed with . :

 

blogentry-29677-0-38047400-1436976896.png

 

As you type the above at the terminal, you will see that the operator is after the numbers it operates on. This is an example of postfix notation or RPN (Reverse Polish Notation). You are probably more familiar with infix (algebraic) notation:

1 + 2 = 3
where the operator is between the two numbers it operates on. The postfix nature of Forth is the highest hurdle you will likely need to get over. Words in Forth can certainly be defined in an infix way; but, postfix is more efficient and easier to implement.


An interesting bit of history regarding RPN: Reverse Polish Notation implies that there is a Polish Notation, which, of course, there is. Polish logician Jan Łukasiewic (yahn woo-kah-SHEH-vitch) invented prefix notation to simplify a branch of mathematical logic. The operator precedes its two operands in prefix notation. It became known as Polish Notation (PN) due to the nationality of Łukasiewic. Quite naturally, when postfix notation arrived on the scene with the exact opposite form, it became known as Reverse Polish Notation (RPN).

At the top of this lesson, we discussed memory organization, stating that virtually all of the available programming memory is one chunk between the top of the parameter stack and the most recently defined word in the dictionary. Each of these locations is readily available with resident fbForth 2.0 words:

 

SP@   ( -- addr )   pronounced “S-P-fetch”; leaves on the stack the address of top of stack
HERE   ( -- addr )   pronounced “here”; leaves on the stack the address of next available dictionary location

The available RAM is the difference between these two addresses. Since the stack is at the higher address, we want to subtract HERE from the top-of-stack address:

 

blogentry-29677-0-88004400-1436976896.png


We can make a couple of useful definitions from this:

: SIZE   ( -- n ) 
   SP@ HERE - ;

: .SIZE   ( -- ) 
   SIZE . ." bytes free" ;

 

blogentry-29677-0-57223500-1436976897.png


The first one leaves the size in bytes of free RAM between the top of the stack and HERE . The second prints that number followed by “bytes free”. You may have noticed that I slipped in another word in the definitions above, viz., ( . Pronounced “left paren”, it begins a comment, which is terminated by ‘)’. Comments are ignored by the text interpreter. Obviously, the comments above are not necessary for the definitions to work. You can enter the above definitions without them. They help us to remember what the words do. We will make it a habit to include the stack effects in this way when we actually begin storing our new words in a blocks file a lesson or two hence.

We will conclude this lesson by defining one more useful word. CLS is a resident fbForth word that clears the screen but does not move the cursor. To also move the cursor to the top of the display screen, we will define PAGE for which we need another fbForth word that sets the cursor:
 

GOTOXY  ( x y -- )   
sets the cursor to the x-y coordinates on the stack. The upper left corner of the display screen is at = 0= 0.


To show GOTOXY in action, we will place the cursor somewhere in the middle of the screen and print an ‘X’ there:

 

blogentry-29677-0-84983100-1437046367.png


And, now, our definition of PAGE :
 

: PAGE ( -- ) 
   CLS 0 0 GOTOXY ;
clears the screen and sets the cursor to the top left corner of the display screen.


Here is the screen after the definition and just before execution:

 

blogentry-29677-0-08494300-1436976898.png


and after execution:

blogentry-29677-0-59881300-1436976898.png


That’s it for this session. We will do more stack manipulation and programming next time.

  • Like 3

3 Comments


Recommended Comments

I think my head just exploded (at first glance anyway). ;)

I'll print this up after I get home tonight and try to dive in this weekend.

 

*** EDIT ***

 

BTW - I took your advice and got your manual printed up.

med_gallery_35324_1027_73660.jpg

Link to comment

I edited the section between GOTOXY and PAGE :

  • to show GOTOXY in action by itself and
  • to correct the stack effects for PAGE .

...lee

Link to comment

Fantastico!!!!!

 

And really nice bind/print there, Ohm.

 

We are getting through some solid basics pretty quickly now. :)

 

Next, stack manipulation words?? ;) love me some DUP SWAP ROT commentary.

 

Hey Lee, really dig the SIZE word. I hadnt really put much thought into the stack pointer (SP) and HERE being the elements to the SIZE formula. It truly is amazingly simple, and I am glad to see that here. :)

 

Now, @ me some more FORTH knowledge so I can ! it in memory!!!

  • Like 1
Link to comment
Guest
Add a comment...

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