Addressing the stacks

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
Post Reply
JimBoyd
Posts: 931
Joined: 05 May 2017

Addressing the stacks

Post by JimBoyd »

My Forth, a Forth-83 Standard Forth, has the word SP@ . In "Starting FORTH" SP@ is named 'S .
Quote:
The stack pointer is fetched by the word 'S (pronounced tick-S).
Since 'S provides the address of the top stack location, the phrase
'S @
fetches the contents of the top of the stack. This operation, of
course, is identical to that of DUP.

The Forth-83 Standard has this entry for SP@ .
Quote:
SP@ -- addr 79 "s-p-fetch"
addr is the address of the top of the stack just before SP@
was executed.

The Forth-83 Standard makes no mention of the data stack pointer, only that SP@ fetches the address of the top of the stack just before SP@ was executed.

My Forth also has RP@ and AP@ . AP@ fetches the address of the top of the auxiliary stack. The phrase
AP@ @
fetches the contents of the top of the auxiliary stack. This operation is identical to that of A@ .
whether SP@ and AP@ can be thought of as fetching the address of the top of their respective stacks or fetching the stack pointer for their respective stacks doesn't really matter, the result is the same.

The exception, at least on the 6502, is RP@ . If the phrase
RP@ @
fetches the contents of the top of the return stack then RP@ does not fetch the return stack pointer, it fetches the return stack pointer plus 1. If RP@ does fetch the return stack pointer then the phrase
RP@ @
does not fetch the contents of the top of the return stack.
Which should it be? Should RP@ fetch the return stack pointer or the address of the top of the return stack?
Although the Forth-83 Standard mentions SP@ , it makes no mention of RP@ .
I personally think RP@ should fetch the address of the top of the return stack, which means the phrase
RP@ @
would fetch the contents of the top of the return stack. This operation would be identical to R@ .
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Addressing the stacks

Post by GARTHWILSON »

In spite of the way the 6502 works, I think RP@ should give the address of the top cell on the return stack, rather than the next byte address to be written to.  I see I have it that way in my '02 Forth but not in my '816 Forth, and I have not used my '816 Forth enough to expose this discrepancy.  Obviously I don't use RP@ much, and R> and R@, both being primitives, are not affected.  On the '816, they're just four assembly-language instructions each.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Martin_H
Posts: 837
Joined: 08 Jan 2014

Re: Addressing the stacks

Post by Martin_H »

I have never heard of SP@ or RP@, or used either of them. To me the stacks are black boxes with contents, and they don't need to have an address. So, I became curious why someone would want to use them. Unfortunately, I stumped both Google and the Forth-standard.org search functions. Gemini concluded that I was asking about R@ and gave me irrelevant information.

Your Forth is yours to customize however you like and have fun with. It's neat and I like hearing about it. I would also be curious why you find the idea valuable.

But here's why I'm twitchy about this concept. Andrew Holme built a TTL Forth computer* which has hardware stacks. Besides being an incredibly cool project, it demonstrated ideas that I think are valuable. First, hardware stacks physically isolate stack address space and contents from main memory, so a bug can't corrupt their contents. Second, they provide an address extension function. While the main memory address bus is 16-bits, the stack machine isn't limited to that. In theory both stack pointers could also be sixteen bits allowing for processing large amounts of data on the stacks. For example, a two stack Turing machine can process the contents of a file by moving data between the stacks.

My bucket list is to build a TTL stack computer with crazy big physical stacks. Multi-tasking could be achieved by partitioning these stacks by task, so a context switch would be done by reloading the stack pointers.

* http://www.aholme.co.uk/Mk1/Architecture.htm is a fun read.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Addressing the stacks

Post by JimBoyd »

RP0 and SP0 are user variables which point to the initial address of their respective stacks. On multitasking systems, each task has its own set of stacks; therefore, RP0 returns a unique address for each task. The same for SP0 . These words, along with RP@ and SP@ can also be used to write diagnostic tools for a Forth system.
Martin_H
Posts: 837
Joined: 08 Jan 2014

Re: Addressing the stacks

Post by Martin_H »

Jim, thanks for the explanation. I've never used a multi-tasking Forth which is likely why I'm unfamiliar with it.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Addressing the stacks

Post by JimBoyd »

I've fixed my Forth so RP0 , a user variable, now points to the initial address of the return stack and RP@ returns the address of the top item on the return stack.

With this change I've tried a variation on an idea from M.L.Gassanenko. I wrote a generic stack word, STACK , which iterates through a stack non-destructively, leaving one item at a time on the top of the data stack. Here is what I have:

Code: Select all

: STACK  ( ADDR1 ADDR2 -- )
   @  2DUP <>
   IF
      BEGIN
         2- DUP @ R@ ENTER
         2DUP =
      UNTIL
   ELSE
      ." EMPTY "
   THEN
   2DROP R> DROP ;

This word is always used in another colon definition. It takes the pointer (or address ) of the top element of a stack and a variable holding the initial address of that stack. STACK causes the threaded code fragment after it to be entered. This fragment of high level Forth needs to remove the item placed on the top of the data stack by STACK or get it out of the way because STACK keeps two items on the top of the data stack as it iterates over whichever stack it is working with. This is my Forth's definition for .S

Code: Select all

: .S   SP@ SP0 STACK . ;

This version of .S displays the items on the stack as signed numbers. The following version displays them as unsigned numbers.

Code: Select all

: U.S   SP@ SP0 STACK U. ;

And for my Forth's auxiliary stack.

Code: Select all

: .AS   AP@ AP0 STACK . ;
: U.AS   AP@ AP0 STACK U. ;


Now that I've changed my Forth so RP0 points to the initial address of the return stack and RP@ returns the address of the top element of the return stack, my Forth has this:

Code: Select all

 : .RS  ( -- )
   RP@ RP0
   STACK
   CR DUP U.W
   2- LFA?
   ?DUP ?STAY
   L>NAME ID. ;

to display the contents of the return stack.
U.W is

Code: Select all

: U.W  ( U -- )
   16BITS U.R SPACE ;

16BITS returns the maximum number of digits possible in a sixteen bit unsigned number for the current number base.
LFA? takes a number. If the number is an address outside the dictionary, it returns zero. If the number is an address in the dictionary, it returns the closest link field address below or equal to that number.
?STAY takes a number from the data stack and does nothing if the number is TRUE. It exits if the number is FALSE.
Executing .RS on my Forth from the command line prints the following:

Code: Select all

.RS 
21F4 QUIT
21AA INTERPRET
2162 (I/C) OK


NOTE: The Forth words in the following are not on my system. They are presented as examples.
I said the threaded code fragment STACK enters has to remove the item placed on the data stack by STACK or get it out of the way. One way to get the item out of the way is by using -ROT . Here is a word to copy all the items from the auxiliary stack to the data stack.

Code: Select all

: COPY.AUX>DATA
   AP@ AP0 STACK -ROT ;

And one to copy all the items on the data stack to the auxiliary stack

Code: Select all

: COPY.DATA>AUX
   SP@ SP0 STACK >A ;

Here are two words using those word to move all the items from one stack to the other.

Code: Select all

: MOVE.AUX>DATA
   COPY.AUX>DATA AP! ;
: MOVE.DATA>AUX
   COPY.DATA>AUX SP! ;

Post Reply