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.

=Description= The PC includes the IP latch, a dedicated ALU and some buffers as input selects. The functions of the PC are to:


 * Reset the IP (usually to 0000)
 * Increment the IP

If the CPU will allow branching, the PC also needs a minimum of one more function:


 * Set the IP to a value.

The design goal for this project is a 0-operand/load-store machine so all data is meant to be transferred via the data stack. The IP can be pushed and popped via the Data Stack. The

The PC includes an ALU simply to increment the IP, although it could be expanded later. This provides the function to increment the IP.

The PC must be closely linked to the RP to allow fast subroutine calls. The IP is latched then fed to the PROM and the PC's +1 input. The ALU will automatically begin incrementing this value immediately. The ALU's output is fed to the Return Stack input so the next instruction address may be pushed to the stack with minimal delay. A push to the return stack may be performed in parallel with many other instructions, some with zero additional delay!

The IP is the address latch for the PROM. It has multiple possible inputs with the default being the PC ALU output. It can also take the value from the Current Instruction, the Return Stack or the Data Stack. In addition to the PROM, it can be copied to the data stack.

- NOTE: The below is outdated ramblings... - This is where the PC can become complicated because we have to know what to set it to, or where to get this value. There are several PC addressing modes which are useful to a CPU and the designer has to decide which to implement. The most commonly used PC addressing modes and the related instructions are:


 * Immediate - used by JMP
 * PC relative - ised by BRA

JMP is typically used as an unconditional branch where the target address is predetermined and placed inline with the instruction. It expects an absolute address. The IP is loaded with this value.

BRA may be a conditional or unconditional branch and is a relative target address. It takes a value determined during compilation, adds (subtracts) it to the current IP value and the new value becomes the new IP value.

JSR or BSR are the possible instructions for executing subroutines. The PC functions may be the same as above but two additional PC functions are required:


 * Save IP
 * Restore IP

In order to return execution properly upon returning from the subroutine, the current IP must be saved somewhere while the subroutine runs, then loaded back into the IP. Where it is stored may be different depending on the system specifications and design. Typically the system includes a "Return Stack" to hold several of these return addresses. In this case, the IP is saved on the return stack.

There are functions included to support other needs as may be necessary during software development and debugging.


 * Disable Output - forces the IP to '0000' to allow the debug station to have control.

=Design Requirements= To implement the functions listed above, the PC is built upon an Adder module. Although most of the time it is incrementing by one, the adder can do this and much more. There are two operand inputs to this adder and we can consider them as 1) Target + 2) Offset.

The TARGET input is most often the current IP, while the offset is most often +1. This gives the PC the 'normal' function of a simple increment. The other primary source of the TARGET input is the Return Stack. This provides the subroutine RET function. Depending on system requirements, there may be other potential sources such as the instruction itself, the ALU output (which may be an accumulator register or the top of the Data Stack), the data bus, or another internal register.

The OFFSET input is most often simply a constant '1'. Other constants may be required by the system needs. A '0' offset is necessary and a +2 is quite frequently needed. When the system uses PC-relative addressing, the offset value may be included in the instruction itself, so we need to allow the instruction decoder as an input here, as well as into the TARGET input. (Never at the same time!)

Implementing the required functions is simply a matter of designating the sources for the input multiplexers. Some of the above functions may require other CPU components to be involved. For example, a BSR is the same as a BRA, but the current IP is saved before the branch. The following list covers all the needed PC functions.

IDLE: IP + 0 INC: IP + 1 DEC: IP - 1 JMP-Immed: Opcode + 0 JMP-Offset: TOS + 0 BRA-Immed: IP + Opcode BRA-Offest: IP + TOS RSET: '0000' -> IP

This PC runs asynchronously meaning it updates after every function code change without reference to any system clock (other than the internal environment 'tic' clock). The IP register is latched automatically when it's stable. A latch control signal is generated with a fixed delay of 6 tics after the function code changes and a pulse width of a single tic. This delayed latch control signal will be output to allow other components (notably the program ROM) to know when the new instruction address is available. =Components=

Input Selectors
These are simply multiplexers with a common output. In SCE, we can add any number of inputs without degrading performance, simply by connecting their outputs together and making sure they are never enabled at the wrong times. There is but a single gate delay, regardless of the number of inputs.

Adder
Since the PC is the very heart of the execution process of the computer, it must be as fast as possible. Unfortunately in SCE, we have few options for speeding up this circuit. Each gate including the PLD (Memory Bank) costs one tic to present its output. But, since SCE operates on 4-bit Hex signals, we don't use up 16 tics for the carry to ripple through the adder. A 16-bit adder requires only 4 stages and takes 5 tics to complete. Common methods of speeding up an adder circuit are not useful here.

See the Adder page for the basic design.

Latch Control
The adder module's output must be latched to prevent the circuit from simply constantly running. It is automatically latched in this design after the adder is done, which is 6 tics. The delay gate presents a delayed function code to the following memory bank. This bank compares the delayed (old) function code to the current code and decides whether a latch signal is needed. Generally, this will be at every function code change.

A more advanced and faster control could be designed. Some of the PC functions do not require the addition function at all, such as when a JMP-immediate instruction is executed. The output during these functions may be available as soon as 2 tics. By adding more circuitry to the latch control, we can latch the output as soon as possible. In this situation, it may be necessary to output the latch signal, so the rest of the system can know when the new address is ready...

=Design= The block diagram for the PC in this project looks like this

The design takes advantage of the 4-bit hex signal and the PLD nature of the memory banks. The encoded function code is connected to only bank inputs in this circuit. Therefore the banks actually do the decoding internally, significantly reducing delay times. This also allows the encoding to be reprogrammed if needed. The function code can be up to 4 bits wide.

Note that the IP that is fed to the instruction memory is not taken from the adder's output. The current IP is latched into the IP register while the instruction is being fetched. It is this latched IP that is fed back into the PC in order to compute the location of the next instruction. If the IP were not latched, the PC would just race away without waiting for the system to read the instruction.

The functional block at the top-left is the DIRECT input multiplexer. The latched IP feeds into this mux.

At the bottom-left is the OFFSET input mux. This block contains the "+1", "-1", etc. These constants are not actual inputs, but are output by this block according to the function code input.

The adder module is the final design shown in  this article.

=Build= Here's a picture of a build of this PC. The latched outputs are seen coming toward the viewer in a vertical column. The sign "l out" is the top of the column. They will be connected to the memory banks on the left in the image.

The left and right sides perform the various selections to the addition module inputs. Any external inputs for these functions are on the rear in this perspective.