Page 1 of 1
Addressing the stacks
Posted: Mon Mar 02, 2026 8:36 pm
by JimBoyd
My Forth, a Forth-83 Standard Forth, has the word SP@ . In "Starting FORTH" SP@ is named 'S .
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@ .
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@ .
Re: Addressing the stacks
Posted: Tue Mar 03, 2026 7:54 am
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.
Re: Addressing the stacks
Posted: Thu Mar 12, 2026 4:36 pm
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.
Re: Addressing the stacks
Posted: Fri Mar 13, 2026 8:39 pm
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.
Re: Addressing the stacks
Posted: Sat Mar 14, 2026 12:44 am
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.
Re: Addressing the stacks
Posted: Sun Mar 29, 2026 10:45 pm
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
This version of .S displays the items on the stack as signed numbers. The following version displays them as unsigned numbers.
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
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! ;