System Architecture

# Simulation Environment

This project is being designed for implementation in a unique simulation environment which provides certain benefits and restrictions not usually found in a real world implementation.

* In physical designs, the delay time for a signal through a single gate is nigh infinitesimal compared to the period of the system clock. That is simply not the case in the SC environment. The Memory Bank is the most complicated logic device and it may be treated as programmable logic array and it has exactly the same latency as a single AND gate. The system updates the gate outputs 100 times per second, regardless of the complexity of the gate.
	+ However, each wire connection takes another system update *after* the gate output is updated, so unless components are spaced without the use of any wire between them then they will always take 2 of the system ticks to propagate a signal change from one gate input to the following gate input. This gives an update 'tick' frequency of 50 Hz for this project.
	+ Overall system timing and synchronizing is achieved through its use of asynchronous sequencers running at the same tick speed and initiated by the same trigger signal. All relative timing is set by the programming of the sequencers.
* There is no fanout limit in this virtual environment and no inductive/capacitive effects of long circuit traces (signal lines). Signal timing is identical for the shortest connection and the longest and there is no signal degradation.
* Likewise there are no fan-in limitations, either. Any number of components may have their outputs tied together and the result will always be the logical, bit-wise 'OR' of all outputs.
* The previously mentioned Memory Bank is at the core of most circuitry. It is, in effect, an 8 bit input to 4 bit output, clockable Field Programmable Logic Device. Its use goes far beyond a basic memory block, as will be seen throughout this project.
	+ It has separate, isolated data input and output which may be used to simplify circuitry, or they may be tied together to create a bidirectional data bus.
	+ If the clock input is not connected, the output updates as fast as the system update clock. Otherwise a read is 'edge triggered' by the clock input going to one particular value.
	+ This clock input doubles as the Read/Write control. If it goes to another specified value, then a write from the data input is performed.
* The individual gates have isolated dual outputs that may be taken advantage of.

# Design Model

The basic design model for this project uses a modified Harvard - Von Newmann memory architecture with 64K cells each for data and instructions. It uses a 16 bit wide, 0-operand, load/store data processing path with a 256 cell deep data stack closely bound to a fast 16 bit ALU. The 24 bit wide instruction path uses distributed microcoded sequencers for instruction execution and includes a 256 cell deep return stack which may be used for subroutine calls and other system needs. A 8 or 16 cell, 16 bit wide general purpose register bank is included and any cell may be used as a pointer into data RAM, in addition to either of the top two parameter stack cells.

One core goal of this design is a hardware implementation of the Forth Virtual Machine, the 'inner interpreter'. The threading mechanism implemented here is the 'natural' choice of sub-routine threading. Subroutine calls and returns must therefore be as fast as possible. The Return Stack is integral to the Program Counter so they can swap values very fast.
In addition to the Return Stack, the Forth virtual machine requires at least one register that can be used as an index into codespace memory. Forth calls this the 'W' or 'Word' register. This can be any register in the general purpose register bank.

The instruction set includes commands to quickly move data between data RAM, the register bank and the top 2 locations on the data stack as well as memory-to-register transfer, using at least direct and indexed memory access modes. The TOS (TopOfStack) is typically used as the memory pointer and will have a very fast access time. The register bank can also be used as pointers into memory.

This means the RAM address has input selects and perhaps a latch. And the minimum inputs are the TOS and GPRx. Perhaps the NOS could be routed?

Additional hardware is included for automatic INCrementing of an accessed register. This is tied directly to the register's data out and connects to the register's data in through an enable gate.

## Differences

* In the standard forth model the pointers to both the data stack and return stack may be manipulated by the code. This will not be allowed in this system. The pointers may be INIT'd, INC'd or DEC'd but their actual values cannot be read nor changed (by instructions meant for programmer's use). The stacks are NOT a part of data memory, as in most designs. Rather they are dedicated hardware memories and so there is no need or provision to directly access them.

Instructions *may* be included in the set to do these functions but they will be meant for testing and debugging *only*.

* Because the Design Model is an extensible language it will be necessary to modify codespace ROM. Instructions to do so will be very limited and only to facilitate implementation of the design model (Forth machine). The actual instructions are YTBD...

## Opcode Design

There are 24 bits available to the machine code. This provides for a 16 bit address or data field, plus a 3 or 4 bit register address field but this limits the instructions that require both fields. The ALU functions can use a 16 bit field for constant use or as target for its output. The ALU also requires a 4 bit function input to select the desired operation. All ALU variations therefore must also encode within this 4 bits!

These are the several instruction variations that require all 12 bits of parameter field, thus are limited in only having the top hex to decode them.

* MOVE GPRx->RAM - Copy value in Register(x) to RAM cell specified in instruction
* MOVE RAM->GPRx - Copy value in RAM cell specified in instruction to Register(x)
* MOVE RAM->@GPRx - Copy value in RAM cell specified in instruction to location pointed to by Register(x)
* MOVE @GPRx->RAM - Copy value in location pointed to by Register(x) to RAM cell specified in instruction
* CONST GPRx ABCD - Place constant ABCD into Register(x)
* CONST @GPRx ABCD - Place constant ABCD into location in RAM pointed to by GPRx
* ALU FCN ABCD - PUSH the constant ABCD into TOS, perform the ALU function(FCN) and save the result in TOS
* ALU! FCN ABCD - Perform the specified ALU function on the current inputs and save the result to the RAM cell (ABCD)

Other possibilities using the 2 fields:

* 0branch to spec register instead of assuming T?

### Canonical Stack Machine Instructions

The minimum instructions needed for a stack machine follow. These are implemented as machine instructions in this CPU. In typical stack machine fashion, all parameters are found on the data stack. The exception to this are the target addresses for the runtime conditional instructions. The addresses are normally inline in the machine code. This CPU allows them to be a part of the conditional instruction itself.

* !
* @
* >R
* R>
* DROP
* DUP
* OVER
* SWAP
* AND
* OR
* XOR
* +
* -
* [IF]
* [CALL]
* [EXIT]
* [LIT]

All CPU instructions fall into 3 basic types - Data Processing, Data Transfer and Program Control.

### Data Processing Instructions

The data stack and ALU comprise the math and logic processing subsystem. This is a '0-operand' machine so the top 2 cells of the data stack are the inputs to the ALU. For processes that only use 1 input, the Top Of Stack is used. To save time these cells are always connected and thus the ALU is constantly 'processing' these data. This is irrelevant until the ALU output is actually needed and then the sequencer will save the it to the top of the data stack, after waiting the appropriate time for the ALU to process it. The sequencer will also adjust the stack pointer appropriately.

The ALU instructions are indicated by a single value in the top hex of the instruction. The 2nd hex is tied directly to the ALU function input to specify which ALU function is desired. The ALU will constantly attempt to provide this function as stated above.

* The remaining 16 bits of the ALU instruction are reserved to specify a constant to be used in the calculation.

But, WAIT
Is this really useful? Not in this system? This just replaces using a CONSTANT instruction before the ALU instruction. Is it helpful enough to justify reserving the 16 bits? Or figure other reasons to keep this 16 bits. Could it be an address? Or does it not matter and they may as well be used for *something*?

* To keep the 0-operand architecture and the direct connect between the ALU and Stack, both ALU inputs can *only* be the two stack cells. To avoid multiplexing the ALU inputs!

### Data Transfer Instructions

All data processing is via the Data Stack as per the 0-operand model. This gives a data flow similar to accumulator-based models. The Top Of the data Stack (TOS) may be thought of as the ACCumulator register. All computations are done with the TOS as one operand. The next item on the data stack (NOS) is often needed for math operations, so it is also wired directly to the ALU as 'input B'. Together, they are effectively the input 'latches' for the ALU operations. Data must be transferred between TOS and the register bank or data memory as fast as possible.

To assist in higher level data stack manipulation, it is often helpful to save the TOS in a temporary location. In many stack machines the Return Stack is used. Doing so is valid as long as the item is removed from the Return Stack promptly and properly. This design allows for quick transfer of the TOS to the Return Stack, and vice versa, which will help support smooth code.
OR----since this return stack is limited, have another stack specifically as a secondary data stack? A 16 value one like the return stack would work... The standard words can just be written to use it.

There is also a 'temporary' transfer register in the data stack circuit, used to facilitate stack manipulation. Instructions and hardware may be included to access this register as well, if a need for that is determined. Using this rather than the return stack is not plausible for higher level code since this can only be used reliably within a single machine instruction and it will only hold a single value. Perhaps this will prove a useful idea. . . .

The 0-operand minimal model includes very limited data transfer instructions. These are the typical stack PUSH and POP (! and @) and the temporary use of the return stack (>R and R>).

* @ - Copy the data in the memory location specified in the Top Of the Stack onto the stack
* ! - Using the data in the TOS as the address, copy the next cell (NOS) to that memory location
* >R - Pop the value from the data stack and push it onto the 'return stack' (this is actually a separate stack in this system)
* R> - Pop the value from the 'return stack' and push it onto the data stack

Because this machine includes a bank of registers, there is a complete set of data movement instructions to utilize them. Every register in the bank may be used as a pointer into data memory, as well as an index added to a specified base address. This base may be inline and thus included in the instruction itself. Very fast data transfer is achieved this way.
A set of instructions for this purpose has been proposed previously \*REF\*. A modified version of that set is included in this machine. These are in addition to the standard @ and !.

* Rx> - Pushes the data in the register(x) to the stack
* >Rx - Pops the data on top of the data stack to register(x)

* Rx@ - Pushes the data in the memory location specified in register(x) to the stack
* Rx! - Pops the data on the top of the data stack to the memory location specified in register(x)

* Rx@+ - Pushes the data in the memory location specified in register(x) to the stack then increment the value in register(x)

```
 Rx!+   -   Pops the data on the top of the data stack to the memory location specified in register(x) then increments the value in register(x)

```

* Rx@- - Pushes the data in the memory location specified in register(x) to the stack then decrement the value in register(x)

```
 Rx!-   -   Pops the data on the top of the data stack to the memory location specified in register(x) then decrements the value in register(x)

```

* nRx@ - Adds the literal (n) to the contents of register(x) and uses that as address to push the data there onto the stack.
* nRx! - Adds the literal (n) to the contents of register(x) and uses that as address to pop the data on the stack to that location.

A group of instructions will move data between the register bank and data memory directly.

* Rx@n - Copies the data in register(x) to the memory location (n)
* Rx!n - Copies the data in memory location (n) to register(x)

Those are the only ones using 11 bits. ? How many more do I want? Cuz it can get ridiculous! (Two indexes? NO - there's only one adder) Think on this . . . .

Additional instructions that don't use the register bank are also included in this design. These can be used to access constants or variables whose absolute address is known at compile time.

* n@ - Pushes the data in the memory location specified in the instruction to the stack (read from variable)
* n! - Pops the data on the stack to the memory location specified in the instruction (write to variable)
* !n! - Pushes the data in the instruction to the data stack ('read' constant)

### Program Control Instructions

This design uses a single processor core without instruction pipelining to keep the design simple and fast. It includes a return stack to provide for subroutine calls and returns. The general purpose registers may be used by jump, branch or call instructions. This allows for common and complex branching, including indexed subroutine calls. Task switching (multitasking) is also possible with this design but will likely never be utilized.

The base instructions for the design model as shown above support the core of the 0-operand model. In this model, the source for all conditionals is again, the data stack. The target address for all flow changes -

# Functional Blocks

## Program Counter

The Program Counter and Return Stack are tightly coupled and they operate simultaneously while the current instruction is being executed. It does not use resources such as the ALU, that may be used in execution. This allows for full parallel operation to maximize execution speed. This sub-system reads the next instruction and has it ready for when the execution sub-system is finished with the current instruction. See the Program Counter article.

## Return Stack

The Return Stack is tightly bound to the Program Counter for fastest performance. See the Return Stack and Program Counter articles for details.

## Instruction Decoder

Decoding in this design is done by a group of asynchronous micro-coded sequencers. Synchronization of these sequencers is accomplished by a common 'starting' signal and step clock. Every sequencer includes means to control a system-wide BUSY signal and the control circuitry waits for this BUSY to become inactive in order to initiate the execution of the next instruction. See the Instruction Decoder article for more details.

## Data Memory

Data memory is 16 bits wide and 64K cells deep. See the Main Memories article for more details.

## Program Memory

Program memory is 24 bits wide and 64K cells deep. See the Main Memories article for more details.

## Register Bank

The design includes a general purpose register bank that is 16 bits wide by 8 cells deep. See the Register Bank article for more information.

## Parameter Stack

The Parameter or Data Stack is 16 bits wide and 256 entries deep. See the Data Stack article for more information.

## ALU

The top 2 elements of the data stack are hardwired to the 2 inputs of the ALU for the fastest execution time. This eliminates the delay through an enable gate (for multiplexing). The ALU functions are paralleled and every function is constantly calculating its output based on the current values in those stack elements. When one of the function results is needed, then its outputs are enabled by the stack/ALU sequencer at the proper time. These outputs normally go back to the top 1 or 2 stack elements but instructions may be included to send them to a general purpose register or data RAM without incurring extra delay. See the ALU for more information.

## Debug Station

This is not a component of the processor but rather a tool included to provide for programming and inspecting the main memories. See the Programmer's Interface article.

## User I/O

I/O will be TBD... At present there is a full ASCII keyboard and character display in development. The level of autonomy and interface have no been determined.

# Design Issues

* The stacks use a pointer which is not readable or writeable by the software. Hardware only INCs and DECs or RESETs them. Is this Forth compatible?

* The contents of the Return Stack are not directly accessible by the software except by PUSHing the top entry to the data stack. Is this Forth compatible?

* The top 2 items on the data stack may be accessed directly at the 'command' level without needing stack manipulation instructions. Variations of the PUSH and POP instructions provide this flexibility. Add actual instructions to make use of this!