Return Stack

A return stack is used by the CPU core to facilitate subroutine use. It is tightly tied to the  program counter/instruction pointer. The current IP may be pushed (saved) onto the stack before entering a subroutine and later popped (recalled) from the stack when returning from the subroutine.

In a subroutine threaded execution design such as this, it is critical to keep the delay times of the return stack and Program Counter to an absolute minimum. The CPU spends a great deal of time threading in and out of the nested subroutine calls. The design which follows is the fastest possible in the SCE environment.

# Design Factors

The stack uses an independent memory array, so avoids any possibility of a stack overflow corrupting other memory. It holds up to 256 elements. Since this is so large, I will assume no proper program will approach this limit. There is no overflow or range checking done, to save on time and system complexity! The programmer must assure that the stack does not over/under flow. To help facilitate this, the stack pointer (RP) may be read onto the Data Stack (&/or the data bus???). There is no provision to explicitly write the return stack pointer.

The return stack does not need the same flexibility as a parameter stack. However, it still performs 10 functions:

1. IDLE - Does nothing to the pointer or memory. Does NOT update the stack output.
2. POP - Delete an element from the top of the stack (DEC the pointer). Update the stack output.
3. PUSH - INC the pointer and store an element to the new top of the stack. Update the stack output.
4. R@ - Read the top of the stack (without changing the pointer). Update the stack output. Since the output is ALWAYS latched at the end of the primary functions, this is superfluous and may be left out of the final design.
5. R! - Write to the top of the stack (without changing the pointer). Does NOT update the stack output. Without additional external circuitry, this will ALWAYS write the current IP value.
6. RP+ - INC stack pointer (without modifying the memory or output).
7. RP- - DEC stack pointer (without modifying the memory or output).
8. RP0 - Zero stack pointer (without modifying the memory or output).
9. RP@ - Read stack pointer (to where?).
10. RESET\_R - Sets the stack pointer to '0', writes '0's to this location and updates the stack output. (?)

As hinted above, this is a pre-increment write PUSH design. This means the stack pointer always points to a valid address on the top of the stack.

## Notes

?-In this design, the top of the return stack may also be pushed or popped from/to the Data Stack (& the system data bus???). This allows other critical information to be saved on this stack as well.

The fastest access is obtained with only a 16 word deep stack. However to gain 256 word depth, the access time is only 2 tics more. This system will initially be designed with the greater depth. As testing progresses it may be found that either a 16 word depth is sufficient or the extra 2 tics is significant. In that case the changes will be manageable to shrink the stack to 16 locations.

?-The Return Stack data is not accessible to other parts of the system - only to/from the Program Counter. This minimizes access times. So, it is not connected to any bus. Instead, the stacks's data output connects directly to an input of the PC and the data input comes only from the PC. [Is this the latched IP - or the "Next Instruction" address?????]

# Components

There are three components in the stack controller - the stack pointer, the stack memory and the controller. The pointer is a dedicated, specialized, fast counter. The memory is a small and fast RAM system. The controller is a small, fast micro-sequencer.

## Return Stack Pointer

The stack pointer is a very fast dedicated counter. The control functions are +1, +2, -1, -2, IDLE and RESET. This counter is implemented with a single Memory Bank. The function input (high address) and I/O control (clock) of the M.Bank may be initiated in the same tic and the proper output will be present for the next tic.

The function input is fed to both the high address and the clock input. Connecting to the clock input forces the M.Bank into synchronous mode so the output will not change until another READ command is received. For the clock to perform a read, the high bit must be '1'. (There is no write function for these M.Banks.) So the total number of possible functions available is 8. The pointer only uses 5 as listed above. The clock input must also return-to-zero before being activated again. This is the IDLE command then ('0').

### Stack Pointer Commands

The M.Bank in the pointer is programmed to accomplish its necessary functions as follows.

* IDLE ('0') - This row is actually all "don't cares" because the M.Bank's output will not change from this command. This command is intended for the clock input. It must be set to '0' before any other command can be executed.
* RESET ('F') - This row must be all '0's so that no matter what the current state of the pointer is, the next value output will be '0' resetting the stack to its beginning address.
* +1 ('9') - This row is programmed with the value of the low-order address + 1. "123456789ABCDEF0"
* +2 ('B') - This row is programmed with the value of the low-order address + 2. "23456789ABCDEF01"
* -1 ('A') - This row is programmed with the value of the low-order address - 1. "F0123456789ABCDE"
* -2 ('C') - This row is programmed with the value of the low-order address - 2. "EF0123456789ABCD"

## Stack Memory

This is a dedicated and isolated RAM space, 16 bits wide and 256 words deep. If necessary it may be reduced to use only the low address limiting the depth to 16 words. The R/W control will come from the sequencer.

Because the output is latched, when the stack is POPped the new location must be read to update the output. An output enable is not necessary. It is assumed that the address input will always come from the same source - the stack pointer - so there is no input select. Likewise the data will always come from the internal data bus so there is no input select for data either. This saves delay time but does mean that the data on the bus must stay steady while being pushed onto the stack.

The Memory Bank used requires an RTZ (Return To Zero) control signal. On the first tic following the rising edge of this signal, all appropriate inputs are read, the specified command is performed and the output is updated and latched as necessary. This means that a WRITE-THEN-READ function (as used in the PUSH and POP commands) requires 3 tics to execute.

### Stack Memory Commands

* IDLE ('0') - The input on the M.Bank *must* return to zero for a minimum of 1 tic after every READ or WRITE function, before another function can be initiated.
* READ ('8') - When this command is received, the M.Bank accesses the data stored at the location specified by the address input and latches it into the M.Banks's output. The output will remain steady until the next READ command is executed.
* WRITE ('4') - When this function is received the M.Bank takes the data on its input and stores it at the location specified by the address input. This does *not* change the output of the M.Bank.

## Microsequencer

The Return Stack functions require the pointer and memory controls to be activated in specific sequences. A small microsequencer controls the timing of the command signals going to the pointer control and the memory. The sequencer may also output a 'DONE' signal if it will be useful.

### Control Sequences

* IDLE ('0')

During the final state of each function the feedback address is set to 'F'. This 'F' directs the sequencer to execute the commands at the function's 'F' location. This location outputs IDLE commands to all components that it controls. The stack system will wait in this state until the IDLE function is received. This means the stack function is a RTZ input (as is the M.Bank's 'clock' input).

When the IDLE function ('0') is input all outputs are kept at their respective IDLE values. Every feedback address location in the IDLE function sequence will have '0'. This forces the sequencer into an infinite loop that will only change when the input function code changes from IDLE. Then it will begin execution of that function. The value '0' is necessary for the IDLE function rather than an 'F' because when the new function code is received, this determines the starting point of that function.

* PUSH

1. The command to INCrement is sent to the stack pointer.
2. The IDLE command is sent to the stack pointer.
3. The sequencer waits for 2 more tics while the pointer is updated.
4. "
5. The WRITE command is sent to the memory.
6. The IDLE command is sent to the memory.
7. The READ command is sent to the memory. The Enter\_Wait signal is activated which puts the sequencer into WAIT during the next tic. This will also send the IDLE command to the memory.

* POP

1. The DEC command is sent to the stack pointer.
2. The IDLE command is sent to the stack pointer.
3. The sequencer waits for 2 more tics while the pointer is updated.
4. "
5. The READ command is sent to the memory. The Enter\_Wait signal is activated which puts the sequencer into WAIT during the next tic. This will also send the IDLE command to the memory.

* R@
* R!
* RP+
* RP-
* RP0
* RP@
* RESET\_R

# Implementation

The stack consists of the pointer or counter and the memory array. The counter is a fast 8 bit inc and dec circuit. This design has an independent dedicated memory for this stack.

## Stack Pointer

The pointer is essentially an up/down counter. This one is used in this design:

It has a delay of 3 tics to the high hex output and only 1 to the low. The input at the bottom is the function code and must be >= 8. The lowest bank computes the next state low-hex. The middle one determines if a carry or borrow is needed and sends the appropriate code to the high-hex stage (the top bank).

## Stack Memory

The memory bank has a capacity of 256 locations which is more than enough for a return stack, so there will be no overflow detection. This simplifies the control circuitry considerably. The inputs have a single source (as seen by the stack) so no provision for input selct is necessary. The output is always latched and enabled because it is assumed to feed a single destination. If a READ-STACK funciton is desired, a separated enable will be necessary but this is not an internal function of the return stack module.

 File:Placeholder.jpg

## Sequencer

A free-running counter is used to step through the states of the sequencer. Two output M.Banks are used to create the control signals for the pointer and memory. An additional M.Bank is included to indicate the completion of any stack functions. It may not be needed in the final design.

The WAIT state is implemented by having the final feedback address set to 'F' and the feedback address at 'F' is also 'F'. Every unused location in the M.Bank will also have an 'F'. So each function will stay in this state until the input command is IDLE ('0').