Program Counter

The terms program counter and instruction pointer are often used interchangably and this can cause some confusion. The instruction pointer is simply a register that holds the address of the next (or current) machine code instruction. The program counter includes the instruction pointer (IP) and the circuitry surrounding and controlling it. In this case, it also includes the Return Stack sub-system.

# Description

The Program Counter is like the heartbeat of the CPU. It fetches and holds the instruction for the execution module to act on. There are 4 components in this PC - the Instruction Pointer and its controls, the IP+1 circuit (adder), the Return Stack with its controls and the Codespace ROM and its controls. Of course the PC has its own micro-sequencer to run all its controls and its sequencer will be different that any other because its timing is special to the CPU.

## Components of the PC

As seen in the block diagram above, the full PC is mostly input selects and latches. The IP and IR are the core registers (latches) in the PC and interface with the program ROM. The sequencer is not shown but is detailed below and the several bits of extra support circuitry are also defined.

### Instruction Pointer Register/Latch

The Instruction Pointer is basically a latch with selectable inputs. The primary input is the IP+1 value - the usual "next instruction location". The other inputs allow conditional execution and are the Return Stack, the Data Stack and (a portion of) the Instruction Register. The functions of the IP circuitry are to:

* Reset the IP (to '0000')
* Increment the IP
* Set the IP to a value from other sources.

### PC Adder

The adder in this PC allows a +1 to +15 in the same time delay. Its primary input is always connected to the IP Register output so it will begin computing as soon as the current IP is latched. The second input may be left open or '0' (or '1') to compute a +1, or it may be taken from 4 bits in the instruction. This allows for a quick tho very close conditional, IP-relative branch for program execution control. If longer conditional branches are needed, this instruction may use a +2 conditional branch, followed by a JUMP. The JUMP uses a full address for a longer "branch" but it must be calculated at compile time.

### Return Stack

In addition to the IP and its inputs, the Return Stack is a part of the PC. The functions of the Return Stack are to:

* Push the value of IP+1 onto the stack
* Pop the value from the stack to the IP Register input
* Maintain a stack pointer, which points to the \*\*CURRENT\*\* Top of Return Stack

By designing the opcodes well, a push to the return stack may be performed in parallel with many other instructions, some with zero additional delay! For more information, see the Return Stack article.

### Codespace ROM

Most CPU descriptions consider this as separate from the PC but it is really just another part of it. The ROM in this system is completely separate from the parameter RAM and is not writeable by the CPU itself. The PC can only read from it. For more information, see the Main Memories article.

### Sequencer

As with every other sub-system the PC has its own micro-sequencer, however it is unique since it controls the flow of execution. Rather than a BUSY signal being generated as in all other sequencers, this one generates a pulsed READY, timed to the IP\_latch control. The PC sequencer responds to the BUSY/DONE signal generated by the other sequencers, instead. An edge detector is included to create the DONE pulse from the BUSY signal, and a latch is included to implement the HALT control. See the hardware section for details on these circuits.

## Addressing Modes

There are two PC addressing modes implemented in this CPU.

* Immediate - The target of the jump is completely defined in the instruction, itself. I.e., the entire address is held within the instruction.
* IP relative - The target of the branch is determined by adding the current IP value to an offset that is held in the instruction.

IP relative addressing may be used but it provides no benefit to the program other than ease of computation during compile. Instead of determining a final complete address, the offset is usually much easier to determine! However it comes at a speed cost. In immediate addressing, the next IP is loaded right from the instruction which is immediately available to be read. In IP-relative addressing, the next IP must be calculated from the current IP so it is not immediately available.

## Subroutines

Subroutines are a type of execution control and can be extremely important in any modern software, so are supported in this CPU. TO implement subroutines, additional instructions are needed. These are JSUB / BSUB and RETN. JSUB or BSUB are the instructions for initiating subroutines and mirror the JUMP and BRAN instructions RETN is the instruction to return to the main execution flow. The PC functions similar as when executing JUMP or BRAN but two additional PC functions are required:

* Save next-IP
* Restore IP

In order to return execution properly upon returning from the subroutine, the next-IP must be saved somewhere while the subroutine runs, then loaded back into the IP. The system includes a "Return Stack" to hold several of these return addresses. This system allows for up to 16 levels of nested subroutines, which is plenty for any potential software to run on this machine.

The JSUB simply PUSHes the next-instruction-location (IP+1) onto the Return Stack then loads the complete address value in the instruction (IR) into the IP Latch and continues execution at the new instruction-location. A BSUB is the conditional equivalent of the JSUB. The RETN POPs the next-instruction-location from the Return Stack, latches that in the IP and continues normal execution from that point.

# OPERATION

The PC and the execution hardware comprise the core operation of the CPU. The sequence of operation is described here. For a more detailed description of each local command, see the Instruction Sequences article.

## Notes

* A pair of handshake signals is used between the PC (Program Counter) and EM (Execution Module). They are READY (from the PC) and BUSY (from the EM).
	+ READY is a short pulse generated by the PC, that indicates a new instruction is in the Instruction Register.
	+ BUSY is created by every sequencer that is processing the current instruction. Each one will hold it high ('F') until it is finished. Every BUSY signal from every micro-sequencer is tied together and is input to the PC. Only when this common BUSY signal goes to '0' is the execution module considered finished processing the instruction. Circuitry will detect this transition and apply a 1-tick pulse (DONE) to the PC.

* The machine instructions are stored in Code ROM. These are generally decoded for the local micro-sequencers. This decoded value is called the local 'command'. The micro-sequencers are composed of individual controllers and their outputs are called 'controls' or 'control signals'. The instruction is latched in a register and is constantly present until the next instruction is latched. This register is available globally. The commands are a simple decoding of this instruction register and thus are "latched", as well but they are local to their associated function block. They will also be present until the next instruction is presented.
* If an instruction is not relevant to a particular micro-sequencer, the local command will be '0'. So, the '0' local command is always a NOOP.
* Each micro-sequencer that processes an instruction goes into a local wait state when it has finished processing. The READY signal from the PC forces every other micro-sequencer into a "starting" state where it can then respond to a new local command if one is present.

## Startup

On system startup, the Instruction Pointer = '0000'h and '0000'h is latched in the Instruction Register. This causes all sequencers, including the PC to wait in NOOP mode and no micro-sequencer is holding BUSY active. This NOOP mode stays stable until the startup command is forced on the [Instruction Register output | PC sequencer command input].

The actual hardware input sets an SR latch high. This forces the START command on the PC's command input (which had '0') and this begins the START sequence. First, '0000'h is latched into the Instruction Pointer (to be certain of the startup conditions) and the Data RAM is instructed to read from that location. When the RAM is ready (there is no BUSY handshake to contend with), the output is latched into the Instruction Register and the READY signal is pulsed by the PC sequencer. The READY signal resets the SR latch signaling the end of START sequence, it tells the Execution Circuit (micro-sequencers) to begin executing the current instruction and because it feeds back to the PC sequencer, it naturally releases the READY signal.

The READY pulse is thus a one tick long 'F' pulse, and is 'wire-OR'ed onto the micro-sequencer command input line. It causes the micro-sequencer to begin the 'F' sequence, which immediately sets the step counter to '0' for the incoming command and 'F0' is the NOOP wait state. When READY returns to inactive, the command line will have the new command present on it.

The Program Counter also gets its first command from the first instruction. This is either the normal STEP command or a JUMP.

## The Fetch/Execute Cycle (STEP command)

The cycle starts when DONE is pulsed 'F'. It is wire-ORed with the local command code for each micro sequencer including the PC sequencer (making sure the different sequencers are still kept isolated). This forces the sequencers to the startup state (the local step count goes to 0). When this signal is released TO '0' (the trailing edge), the local command is allowed through and the sequencers begin to process it.
In the first tick, any micro-sequencer involved, including the PC activates their BUSY signal. This is held high as long as the circuitry, including the PC is processing the command so every sequencer will be in NOOP or WAIT as it is released. This BUSY signal is processed and when it is released (to '0') by all sequencers, a short 1 tick pulse is created. This is the DONE signal that begins the cycle.

### The START, STEP and HALT Instructions

These are the three core instructions that control sequential program flow and thus the operation of the CPU.
The decoder for the PC decodes 'every possible instruction'. Unless the instruction is specifically for the PC, it outputs the STEP command, which is detailed above. The STEP process always uses IP+1 for the next instruction location. This is fine during normal operation but is not OK for the very first instruction, which is at address '0000'. Also, any jump or branch uses a different target other than the IP+1. Additional PC commands are used for these cases.

* START (2) - latches '0000' into the IP, waits for the code ROM, latches the instruction at that location into IR, then waits. It is only called by an external trigger (the 'RUN' button).

Show
1. Set IP\_Input to "0000" (input "IP+1" is present by default)
2. Enable IP\_latch
3. Release IP\_latch
4. (wait)
5. Send 'READ' to Code\_ROM
6. Send 'READ' to Code\_ROM
7. Send 'READ' to Code\_ROM
8. Send 'READ' to Code\_ROM Enable IR\_latch

* STEP (1) - This latches IP+1 into IP, waits for the code ROM, latches the new instruction into IR, then waits. The decoding and execution circuitry do their stuff at this point and BUSY is held high until it is finished executing. Once BUSY is released, this triggers the PC to 'read' the next PC command and begin executing it.

Show
1. Enable IP\_latch (IP+1 is input to the latch by default!)
2. Release IP\_latch
3. (wait)
4. Send 'READ' to Code\_ROM
5. Send 'READ' to Code\_ROM
6. Send 'READ' to Code\_ROM
7. Send 'READ' to Code\_ROM Enable IR\_latch
8. WAIT

* HALT (7) - This is used at the end of every program to stop the PC from executing continuously. It can also be inserted into a program for debugging purposes. It forces an 'F' on the BUSY signal that comes from the execution circuitry. This allows the current instruction to be executed, so the HALT instruction may actually do things before the system is stopped. Then the system does not continue to fetch additional instructions, until this signal is released. That is normally done using circuitry outside of the CPU itself (a 'GO' button). I.e., the HALT output sets an S/R flip flop which forces the 'F'.

Show
1. Enable\_Halt
2. WAIT

### Conditional Execution

There are several instructions to alter the flow of execution of the CPU. All these are implemented in the PC subsystem.
- All destination addresses will be generated during 'compile time' so they are included in the instruction itself.
- There is no full adder in the PC, as there is in many CPUs. The reasons are multiple - the 0-operand machine allows addition of target addresses using the primary ALU and data stack, the delay cost of a full adder is prohibitive and the design environment provides a handy and fast 1 to 15 addition, instead. A +1 addition is necessary and making it into a +1to+15 is pretty simple. The design decision is made to have all conditional branches use this feature and only the JUMP(always) instruction will allow full 16 bit destination encoding.
? - There is only 1 base conditional jump and the condition is always the same - it is a "branch on 0 on the stack" - ???

* JUMP-Imm (always) - Takes the 16 bit ADDRESS in the instruction and latches it into the IP.
* JUMP-Rel (always) - Takes the 16 bit OFFSET in the instruction and adds it to the current IP then latches that into the IP.
* BRAN-Imm (conditional) - Compares the 4 bit conditions with the CC and if it matches, takes the 16 bit ADDRESS in the instruction and latches it into the IP.
* BRAN-Rel (conditional) - Compares the 4 bit conditions with the CC and if it matches, takes the 16 bit OFFSET in the instruction and adds it to the current IP then latches that into the IP.
* JSR-Imm (A) - PUSHes the value IP+1 onto the Top of the Return Stack then loads the 16 bit ADDRESS in the instruction into the IP.
* JSR-Rel (adr) - PUSHes the value IP+1 onto the Top of the Return Stack then takes the 16 bit OFFSET in the instruction and adds it to the current IP then latches that into the IP.
* RTS (B) - POPs the value from the Top of the Return Stack and loads it into the IP.

# HARDWARE

## Program / Codespace ROM

This is called "ROM" because the CPU itself has no means to write to it. The input and output data lines are not connected together as with the bidirectional data buss. Only the debug and programming stations can write to this memory. The design is a standard array of memory banks with address and control signal decoding.
As designed, there is a 4 tick delay from when the higher address lines are settled and the instruction data can be latched into the IR. Furthermore, there is a 3 tick delay from the Control signal to a stable output and 2 ticks from the low order address bits to stable output. For more information, see the Main Memories article.

## PC Adder

The adder is "almost" a full 16 + 16 addition module. This provides support for full IP relative addressing for JUMPs and BRANches. The default of the adder is to create the IP+1 value for the instruction fetch so even if the offset input is '0', the output will be IP+1. That's the only difference from a normal full adder module. (And it does not use the carry in/out.)

## Return Stack

The return stack is much simpler than the parameter stack since all it needs to do is simple POPs and PUSHes. See Return Stack.

## Sequencer

The micro-sequencer in the PC is only functionally different than the other ones because it is part of the fetch phase rather than the execute phase. It responds to the instructions for program control while the other sequencers respond to the instructions for data control and processing. There is no BUSY generator in the PC since it will output a READY signal at the appropriate time. The several program control inst ructions are decoded for the PC to act upon. All other instructions are decoded to the local STEP command.

### START Circuit

The CPU begins operation with the START command but there is no START instruction since the CPU cannot execute an instruction before it begins executing instructions! This command is currently only initiated by the Debug Station or a local physical pushbutton. There is a micro-sequence for the START command, so the button or input simply initiates this local command. 'The duration of this input may be critical...'

### HALT circuit

The HALT signal from the PC is fed into the Set input of an S/R flip-flop. The S/R output is tied with the BUSY signal from the execution circuitry. This allows the CPU to finish executing the current instruction but it will not fetch the next one. At this time, the only way out of this HALTed state is by a signal from the Debug Station, or a local physical pushbutton.

### BUSY to DONE

The execution hardware generates a BUSY signal while it is processing a command. When all sequencers are finished, this signal returns to '0'. This change is used to create the DONE pulse used by the PC to begin processing its next command. The circuitry to create DONE is just a single M.Bank with an OR gate for a delay. The output of the M.Bank goes high one tick after the BUSY signal goes low. Since BUSY is generated by the micro-sequencer in each sub-system, its timing may be adjusted to precisely match the completion of execution, including this delay.