Tuesday 31 December 2013

Register Design v0.1

The Juno has the following registers
  • A - General purpose register
  • B - General purpose register
  • IX(L) - Index Register low byte
  • IX(H) - Index Register high byte
  • SP(L) - Stack Pointer low byte
  • SP(H) - Stack Pointer high byte
  • PC(L) - Program Counter low byte. 
  • PC'(L) - Copy of the Program Counter low byte. Connected to the Address bus.
  • PC(H) - Program Counter high byte.
  • PC'(H) - Copy of the Program Counter high byte. Connected to the Address bus.
  • MAR(L) - Memory Address Register low byte. Not visible to the programmer.
  • MAR(H) - Memory Address Register high byte. Not visible to the programmer.  
  • Status Register 
  • T - Temp Register. Not visible to the programmer. Connected to the ALU Right Bus.
The register inputs are connected to the ALU Z Bus and the outputs to the ALU Left Bus unless stated otherwise above. Memory to register operations require data to pass through the ALU therefore a logical OR operation with zero is performed if the data is to be loaded into the register unmodified (internally the ALU has the ability to select zero as an input).



Register Descriptions

A and B - General Purpose registers
The A and B registers are 8 bit general purposes registers implemented using octal positive edge triggered flip flops with 3 state outputs.

IX(L) and IX(H) - Index register
The Index Register is implemented using a pair of octal Positive edge triggered flip flops with 3 state outputs. The Resultant Address of an instruction using the index register is calculated and stored in the MAR Register for output onto the Address Bus.

SP(L) and SP(H) - Stack Pointer register
The Stack Pointer is implemented using a pair of octal positive edge triggered flip flops with 3 state outputs. The Resultant Address of an instruction using the stack pointer is calculated and placed into the MAR Register. The shift register has separate load enable control lines, see below, which allows the microcode to implement automatic increment and decrement when a PUSH or POP instruction is being performed.

PC(L) and PC(H) - Program counter
The Program Counter holds the address of the next instruction or operand to be fetched from memory and is incremented by one on completion of the fetch operation.

The Program Counter is implemented using two 8 bit counters whose outputs are connected to the 16 bit Address Bus. In order to support ALU calculations involving the PC and reading and writing the PC to memory the PC output also needs to be connected to the Left ALU Bus. The approach chosen for doing this, which requires the fewest ICs, is to implement a second PC named PC' whose output is connected to the Left ALU Bus. The inputs to the PC and PC' registers are tied together so that they always hold the same value. 

MAR(L) and MAR(H) - Memory Address Register
The Memory Address Register implemented using a pair of octal Positive edge triggered flip flops with 3 state outputs whose outputs are connected to the 16 bit Address Bus. The MAR is not visible to the programmer.

Status Register
The status register is a special 8 bit register implemented using 8 D flip-flops so that bits can be set individually.

The Status Register is connected to the Z Bus and the Left ALU Bus so that its value can be written and read to and from memory.

Four of the bits that represent the ALU flags are also connected directly to the ALU so that they can be individually set by the result of ALU operations.

The 8 ALU bits are also connected directly to the Micro-code decoder so that it can test their values e.g. to test the Negative Flag when executing a Branch on Zero instruction.

T - Temp Register
The Temp Register is implemented using an octal Positive edge triggered flip flop with 3 state outputs whose output is connected to the Right ALU Bus.

The T register is the only register whose outputs is connected to the Right ALU Bus and is used for performing register to register operations with the ALU. The Temp Register is not visible to the programmer.

Buses

The Juno CPU has three CPU buses that are completely internal to the CPU and connect the registers to the ALU. 
  • Left Bus - controlled by the 'L Bus Device Select' decoder
  • Right Bus - controlled by the 'R Bus Device Select' decoder
  • Z bus - only the ALU output can drive the Z bus therefore no device select decoder is required.
The Juno has two internal buses that connect the CPU to internal devices such as memory. 
  • Address Bus - controlled by the 'Address Bus Device Select' decoder
  • Data Bus - controlled by the 'Data Bus Device Select' decoder

The internal buses operate at CPU clock speed and are connected to external buses for communicating with slower external devices such as serial IO ports. 

Loading a register from the Z bus

A rising edge on a Register's CP (clock) input causes it to latch the value present on its inputs. As all the  registers are connected to a single bus there needs to be a way of ensuring only the desired register(s) receive the clock pulse.

This is done by using a decoder to gate the clock signal so that only the selected register receives a clock pulse and is loaded. When the /E line of the decoder is low it outputs '1' on the currently selected line and all other lines are '0'.

The Juno CPU is designed to change state on the rising edge of the clock pulse therefore the CPU clock to the decoder is inverted so that /E goes low on the rising CPU clock edge.

The Z bus load decoder is a 4-to-16 decoder and is used to select which register is loaded from the Z bus apart from the MAR(H+L) registers which have separate load control lines. This is to enable to certain operations to be implemented with fewer lines of micro-code and hence fewer clock cycles.

For example, the instruction PUSH A requires the Stack Pointer to be decremented by 1 and then loaded into MAR. By having separate load controls on MAR this can be done in two clock cycles
SP(L) - 1 -> SP(L), MAR(L)  << SP(L)-1 is loaded into SP(L) and MAR(L) simultaneously
SP(H) - carry -> SP(H), MAR(H)

Outputting a register onto a bus 

A register can place its contents onto the bus it is connected to but only one register can drive the bus at any single point in time and the outputs of the other registers must be in their high impedance state (hi-Z).

A simple way to ensure this is the case and avoid mistakes e.g. in the microcode is to use a decoder to select which device is driving the bus. As the output enable of the registers is active low (/OE) an output inverting decoder is required which drives the selected line low and all other lines high. When the decoder is not enabled all outputs are forced high.

Outputting onto the Address Bus

The CPU can drive the 16-bit Address Bus using the PC'(H+L) and MAR(H+L) registers. The CPU interface to the address bus is uni-directional meaning the CPU cannot read the value from the address bus.

The PC' and MAR register output enables are controlled by the Address Bus 3-to-8 Decoder as follows
  • 0 - no bus device is selected to drive the address bus
  • 1 - PC'(L+H)
  • 2 - MAR(L+H) 
  • 3-7 - reserved for other non-CPU devices connected to the address bus

Outputting onto the Left Bus

The majority of the CPU's registers are connected to the CPU internal Left Bus and are controlled by the Left Bus 4 to 16 Decoder as follows
  • 0 - no bus device selected (not strictly required but feels safer to not be driving the bus unless a device has specifically been selected)
  • 1 - A register
  • 2 - B register
  • 3 - IX(L)
  • 4 - IX(H)
  • 5 - PC(L)
  • 6 - PC(H)
  • 7 - SP(L)
  • 8 - SP(H)
  • 9 - Status Register
  • 10 - Data Bus 
  • 11-15 - reserved

Outputting onto the Right Bus

The temp register and data bus are connected to the CPU internal Right Bus and are controlled by the Right Bus 2 to 4 Decoder as follows
  • 0 - no bus device selected
  • 1 - T register
  • 2 - Data Bus
  • 3 - reserved

CPU to Data Bus Interface

The external Data Bus is connected to both the internal Left and Right buses and is bi-directional therefore requires additional logic to ensure only one device is driving the bus at a time.

Transceivers are used to control the connection between the internal Left and Right buses and the Data Bus. A tranceiver has both direction and Output Enable controls. The Data Bus Decoder selects which tranceiver is active and the direction control is governed by the Left / Right Bus decoder thereby ensuring no bus conflict.