## Posts Tagged ‘Home Built CPU’

### Arithmetic Logic Unit Chip Selection

Sunday, July 16th, 2017

In the previous post, a high level design for an Arithmetic Logic Unit (ALU) was presented. It is time to consider how this could be implemented.

## 7400 Series Integrated Circuits

The 7400 series of integrated circuits became a staple in computer design and digital electronics in the 1970s and 1980s. These packages implemented everything from simple logic gates (AND, OR, XOR, NOR etc.) through to complex functions such as Error Detection and Correction (see 742960). See this article for a comprehensive list of chips and their functions.

So popular were these chips that they are still available today in the original DIL (Dual In-line Package) as well as surface mount packages.

A number of variations of these ICs were produced:

Series Description
74 Standard TTL
74LS Low-power Schottky

The above list is not comprehensive and many more variations are available.

This series of posts will concentrate on using the LS series of chips where possible.

## Internals of the ALU

The ALU in the SSEM needs to support addition (for the JRP instruction) and subtraction (for the SUB and LDN instructions). The previous post presented the internal view of the ALU for the SSEM as:

Internal view of an Arithmetic Logic Unit showing the control signals and data paths.

The ALU has five distinct components:

1. Storage for the A and B operands (registers)
2. Zero Unit
3. XOR
5. ALU Output

Let’s look at how each of these could possibly be implemented using 74LS00 series integrated circuits.

### Storage for the A and B operands (registers)

Both of the operands are connected to the data bus at the same time:

Operand A and B

The Load control signal determines when the input signals should be stored in the register. Each of the registers holding the operand has an independent load signal. So for this part of the ALU a component is required that will:

1. Take the value on the input pins and store the value
2. Only load the data into the register when the trigger signal has a known value
3. Present the stored value on the output pins

The above requirement fits the description of a Flip-Flop (also known as a Latch).

The 74LS00 series has a number of flip-flops and latches available. The 74LS373 contains an octal transparent latch with three state output. This chip is still commonly available and has the following properties:

1. Input signals can be latched (stored) in the internal registers on request
2. The output from the latch can be turned on or off, again, on request

The above functions are controlled by two signals:

1. Clock
2. Output Enable (~OE)

#### Clock

When the clock signal is low the inputs are effectively disconnected from the latches. the latches will therefore remain unchanged and hold the previously latched value.

A high clock signal will allow the input pins to the connected to the latches. Any changes on the inputs are presented to the latches. This holds true for as long as the clock signal is in the high state.

The state of the input pins is held in the latches when the clock signal transitions from high to low (on the falling edge of the clock).

#### Output Enable

The output enable pin is an active low pin (denoted here by the ~ symbol before the name of the pin). This means that the contents of the latches will be output from the chip when the ~OE pin is in the low state.

Putting the ~OE pin in a high state disconnects the latches from the output pins and puts the outputs in a high impedance (also known as a high-Z) state.

Setting ~OE low while the clock pin is high means that the outputs will follow the inputs. This happens because the high clock signal allows the inputs to be connected to the latches and the low output signal puts the value in the latches on to the output pins.

From the above description, the Clock pin should be connected to the Load A and Load B signals of the respective operands. This will allow the latch to be loaded with the input signals when the load signal falls from high to low.

The inputs to the chips should be connected to the data bus directly and simultaneously. Data cannot be loaded into the latch until the appropriate load signal transitions from high to low. The load signals will control when the operand changes as follows:

• Load A (or Load B) signals are low then the inputs will have no impact on the operands. The outputs will reflect the previous value stored in the latch.
• When Load A (or Load B) is high then the contents of the data bus will be presented to the respective latch. The output of the respective operand will reflect the current contents of the data bus.
• When the Load A (or Load B) signal falls from high to low, the current contents of the data bus will be stored in the respective operand. The output will reflect this value no matter what happens on the data bus.

Aside: in 2013, the intention was to simulate the SSEM in VHDL. The 74HC373 was simulated in a series of posts around that time.

### XOR

The next block available is the 74LS series is the XOR block:

Operand B and XOR

This block performs one part of the negation process allowing the adder to also perform subtraction. The XOR truth table is:

 ~Add/Subtract Input Value Output 0 0 0 0 1 1 1 0 1 1 1 0

In twos complement, the first part of generating a negative number is to invert the bits in the original number. If you examine the above truth table, when the ~Add/Subtract signal is low, the output reflects the input value. When ~Add/Subtract is high then the output is the inverse of the input value.

So, setting the ~Add/Subtract signal high when the ALU is subtracting operand B from operand A and low when the ALU is adding operand A to operand B will ensure that the correct value is passed through to the adder.

The 74LS86 is a quad 2-input XOR gate (contains four 2-input XOR gates) in a single package. The necessary functionality is achieved by connecting the A inputs (not to be confused with the A operand) of each gate to the ~Add/Subtract signal. All of the A inputs are therefore connected together. The B inputs are connected to the outputs of the B operand latch.

### Zero

The zero unit sits between the output of the A operand and the Adder. Its function is to select between two possible input values:

1. Zero
2. A operand

and pass the selection on to the Adder.

Operand A and Zero

A number of possibilities exist:

• Use the ~OE signal on the A output to simply turn the output off when zero is required. This may require the use of pull down resistors to prevent a floating signal.
• Use a buffer chip such as the 74LS245 to connect the Adder to ground when ~OE on the A operand goes high

A little investigation is required.

The 74LS283 is a four bit full adder with carry in and carry out. An 8-bit adder is created by chaining two four bit adders together:

In the case of subtraction, the final part of the negation of a twos complement number is to add 1 to the inverted bit pattern of the original number. Setting the carry in on the first adder effectively adds one to the number. The same ~Add/Subtract signal in the XOR block can be used here as it is low for addition (zero will be added to the sum) and high for subtraction (one will be added to the sum).

### ALU Output

The ALU output takes the output of the adder and makes this available to the data bus:

ALU Output

Output to the data bus is controlled by the ALUOutout signal and this function can be performed by a buffer circuit. The 74LS245 is an octal bus transceiver with non-inverting three state outputs. The direction of signal transmission can be controlled using the DIR pin on this chip. In the case of the ALU, the direction is always from the ALU to the data bus and so this pin can be held high (or low) permanently.

Output from 74LS245 is controlled by the ~OE pin. This is an active low pin and the chip is transparent when the signal is low and in high impedance mode when this pin is held high.

## Conclusion

All of the integrated circuits for the high level functionality of the ALU have been identified. The next step is to put this together and see if it works as expected.

Something for the next article.

### Arithmetic Logic Unit

Monday, June 26th, 2017

The February post regarding the SSEM presented a software implementation of the core hardware:

• Program counter a.k.a Current Instruction (CI)
• Arithmetic Logic Unit (ALU)
• Instruction register a.k.a Present Instruction (PI)
• Registers (memory)

So, how easy this would be to implement the ALU in 1970s hardware, namely, 74LS series of chips.

## Arithmetic Logic Unit

The only explicit arithmetic operation implemented by the ALU is the SUB instruction. There is however, one other operation that requires an arithmetic operation to be performed, the JRP instruction. This instruction adds the contents of a store line to CI and stores the result in CI. The inclusion of an ADD instruction to the ALU instruction set will support the JRP instruction.

Before we progress further it is worth noting that the SSEM uses twos complement representation to store numbers.

The high level view of the ALU and the way in which it interacts with the other components can be viewed as follows:

High level view of an Arithmetic Logic Unit.

Two busses run through this CPU:

1. Data Bus
2. Control Bus

The Data Bus is used to move data from one part of the CPU to another. This is also connected to the external data bus of the computer allowing the CPU to store and retrieve data from system peripherals and memory.

The Control Bus determines which operations are performed by the CPU (in this particular case, by the ALU) at any point in time.

The ALU uses two input operands (A and B) from the Data Bus. Operations are performed on the two operands, the type of operation is determined by the signals on the Control Bus. The results of the operation are then placed in the ALU Output register. The final step is to make this result available to the Data Bus.

The fact that the SSEM implements only these two arithmetic instructions operating on twos complement numbers leads to a very simple ALU design with very few control signals.

### Data Bus

As noted, the data bus moves data around the system. The ALU requires two operands for the ADD or SUB operations. These can be implemented in a single operation or in several stages.

#### Single Operation

Supplying the data in a single operation would require the data bus to be twice as wide as the word size. In the case of the SSEM this would require a data bus that is 64-bits wide. Operand A would be supplied by one half of the signals on the data bus. Operand B would be supplied by the signals on the other half of the bus.

#### Multiple Steps

Supplying each operand independently would require a two step process, the first step puts operand A on the data bus and loads into the operand A register. The second step puts operand B on the data bus and loads the data into the operand B register. This is slower, taking two steps, but simplifies the hardware design as a 32-bit data bus is used.

### Control Bus

The operation of the CPU is orchestrated by the signals present on the control bus. In the case of the instructions being implemented (ADD and SUB) using two registers the following signals are required:

1. Load operand A (place the contents on the data bus into operand A)
2. Load operand B (place the contents on the data bus into operand B)
3. Output result (place the ALU result onto the data bus)

There is another instruction that would benefit from having access to the ALU, namely, Load Negative (LDN). This instruction loads a negative number into the accumulator. A negated number can be obtained by subtracting the original number (from a store line) from 0.

If we design the system so that the subtrahend (the number to be subtracted) is always placed in the B operand and operand A can be zero then we can support the LDN instruction. This leads to the final signal, Operand A or Zero.

The full list becomes:

1. Load operand A (place the contents on the data bus into operand A)
2. Load operand B (place the contents on the data bus into operand B)
3. Output result (place the ALU result onto the data bus)
5. Operand A or Zero

## Inside the ALU

If we add the data paths and control signals to the above diagram we have the following:

Internal view of an Arithmetic Logic Unit showing the control signals and data paths.

The data paths are shown as broad arrows. The control signals are drawn in red.

The data from the data bus is presented to both the A and the B operands at the same time. The data is loaded into the register when the appropriate Load A or Load B signal is set.

### Zero Operation

The zero operation is only needed for the A operand. This block will either pass the value in operand A through to the adder (for the SUB, ADD and JRP instruction) or pass 0 through to the adder (for the LDN instruction).

### XOR

The XOR block is used to help with the negation of the number in the B operand. In twos complement, a negative number is obtained by inverting the bits in the original number and the adding 1. The XOR helps with the inversion process. Consider the truth table for the XOR operator:

 Control Signal Input Value Output 0 0 0 0 1 1 1 0 1 1 1 0

Note that when the Control Signal is 0 then the output from the XOR gate reflects the value on the Input Value. When the Control Signal is 1 then the output is the inverse of the Input Value.

This provides a method for solving the first part of the problem of generating the twos complement negative number, namely, inverting all of the bits in the positive number.

The adder does exactly what it’s name suggests, it adds two numbers together. Normally, these units have a carry in and a carry out signal to allow multiple units to be chained together:

When the ~Add/Subtract control signal is set to 0 then the XOR block passes through operand B unchanged. The carry in signal to the first of the adders (Adder-0) is set to 0. The result is that operand A and operand B are added together. This supports the JRP instruction which requires an addition.

When the ~Add/Subtract control signal is set to 1 then the XOR block inverts the bits in operand B. The additional 1 needed for the twos complement process is provided by passing the ~Add/Subtract control signal to the carry in input to the first adder unit (Adder-0 in the above diagram).

### Result Output

The final part of the problem is to control when the result from the calculation is output on to the data bus.

## Conclusion

A lot of theory, next step is to consider how this can be put into practice.

Something for the next article.

### Clocks, Reset Signals and Switch Debouncing

Sunday, February 16th, 2014

Every computer needs a clock circuit to synchronise the operation of the various components. A CPU is no exception. In this post we will create a clock for the CPU. We will also add reset and single step circuits.

The brief for this post is as follows:

• The reset circuit must be capable of generating both high and low reset signals.
• A stop/run circuit should allow the CPU to be stopped by the user and the clock single stepped.
• Internal clock source with a master clock of 4 MHz.
• Selectable clock frequency which is a fraction (half, quarter etc.) of the master clock source.

## Reset Signals

The requirement to have both high and low reset signals is not really too complex as a single inverter can provide this capability. The most complex part of this requirement is to remove the switch bounce from the signal.

## Switch De-bouncing

For new readers, switch bounce occurs due to the imperfect nature of mechanical switch. For a brief period of time when a switch is depressed or released there will be a period where the electrical signal is not stable. If you connect an oscilloscope to a switch in an electrical circuit and press the switch you are likely to see traces such as the following:

Switch Bounce

The obvious outcome of this is that the circuit can act as though the switch has been pressed multiple times in a short period of time. The answer to the problem is to de-bounce the switch. This removes the additional signals which can be generated. For microcontroller developers there are two possible solutions to this problem, software or hardware de-bouncing. As we have no conventional software environment available to us we must achieve this by hardware de-bouncing.

There are many possible solutions to this problem and you can find some discussions in the following links:

In this circuit there are two switches to debounce, the reset switch and the clock selection switch. The reset switch is a momentary switch and the clock selection switch is a rotary switch. The rotary switch should be viewed as a momentary switch for the purposes of this exercise.

The problem of debouncing the switch can be broken down into two distinct components, namely removing the jitter by rounding off the signal and the squaring off the rounded signal. The jitter can be rounded off by the use of a RC circuit. The above articles suggest that the rounded signal can be squared using an inverter with a Schmitt trigger.

Time to break out the breadboard, oscilloscope and the calculator.

The first thing to examine is the amount of bounce for the switches being used. Hooking up the momentary switch and a resistor resulted in the following traces for the depression of the switch:

Switch Bounce Depression

And for the release of the switch:

Switch Bounce Release

Taking some measurements we see that the maximum bounce appears to be about 5ms for the momentary switch.

Repeating the exercise for the rotary switch reveals that this switch was a lot dirtier. The bouncing continued for about 10ms in the worst case.

Taking the worst case scenario we should assume that the switch is unstable for 10ms and 20ms would allow for an extreme case.

There are two possibilities for debouncing, hardware and software. For a large commercial run where a microcontroller is in use then software debouncing would be used as it requires no additional components. As this is a small run, hardware debouncing is a possibility.

### Hardware Debouncing (Circuit 1)

This first hardware debouncer will use an RC network connected to a Schmitt triggered inverter. The basic circuit is:

2RC Debounce

The capacitor C4 charges through R4 and R5. When the capacitor is charged the input to the inverter is high and the output will be low.

Depressing the switch starts the discharge cycle for the capacitor. The capacitor slowly discharges through R4 until it is below the level associated with logic 0 on the inverter. The output of the inverter then goes to logic level 1. The hysteresis of the inverter makes the gate resistant to the time the voltage applied to the input of the inverter is between logic 1 and logic 0. So pressing the switch takes the output high and releasing the switch takes the output from the circuit low.

The trick with the circuit above is to select values for R4, R5 and C which eliminate the bounce at both the charge and discharge points in the circuits operation. This circuit gives an output something similar to the following:

The yellow trace shows the output of the circuit when the oscilloscope probe is connected to the input of the inverter. As you can see, the noisy signal has been replaced by a rapid decay at the start (when the switch is depressed) and a longer rise at the end when the switch is released.

### Hardware Debouncing (Circuit 2)

In the last post I was looking at the MSP430. The intention is to look at how it can be used for software debouncing (we’ll come on to that later). The MSP430 Launchpad has a reset button connected to Port 1, pin 3 (P1.3) and this switch is also debounced (the schematics are freely available from TI’s web site). The debounce circuit on the MSP430 looks something like this:

Modifying this to add an inverter we get the following:

Modified MSP430 Debounce Circuit

The discharge when the button is pressed is a lot quicker but the charging when the button is released show the same characteristics as Hardware Debouncing (Circuit 1). Examining the trace we see that the output from the inverter is good enough for the job at hand.

### Software Debouncing

The algorithm for software debouncing is relatively trivial. The microcontroller waits and detects the changing input on of the the pins (say going low to high). Once detected, start a timer and wait for the worst case scenario (we set this to 20ms for the switches being used in this circuit). If at the end of the time period the signal is still high then set the output high, otherwise start the whole process again.

Now this algorithm works well for a single input to a microcontroller but what if you have multiple inputs and outputs all of which need debouncing. This is the scenario with this circuit as the rotary switch allows one selection to be made from a multiple of inputs. In this case the rotary switch acts like multiple switches. Following the above algorithm would require multiple interrupts and timers, many more than found on low end microcontrollers.

Modifying the algorithm to use timers and counters can solve this problem.

1. Initialise an array of counters (one for each input) to 0
2. Set the outputs to the same level as the inputs
3. Setup a timer to trigger on a regular period (say 8ms)
4. For each input, if the input is different to the output increment the counter for that input, otherwise set the counter to 0
5. For each counter, if the value has exceeded the threshold count then set the output to the same level as the input

Although this is a little more convoluted it does allow switch debouncing for multiple switches with a simple and cheap microcontroller.

#### Software Debouncing on the MSP430

The software debouncer will be implemented in MSP430 assembler code developed using IAR Embedded Workbench.

The first thing we need is somewhere to store the counters and some workspace for the application. This application is small and so the registers on the chip should suffice.

```;--------------------------------------------------------------------------------------------------
;
;   Switch debouncer for the home made CPU.  This will debounce five switches
;   four through Port 1 and 1 through port 2.
;
;   Copyright (c) Mark Stevens 2014
;
;--------------------------------------------------------------------------------------------------
#include <msp430.h>

;--------------------------------------------------------------------------------------------------
;
;   Global definitions
;
;--------------------------------------------------------------------------------------------------
;
;   Define some symbolic names for the registers holding the counts of the number of interrupts
;   for which the value on the input differs from the output.
;
#define  port0Count r4
#define  port1Count r5
#define  port2Count r6
#define  port3Count r7
;
;   Now some temporary workspace for the Watchdog ISR.
;
#define inputRegister r9
#define temporaryRegister r10
;
INTERRUPT_BASE      equ     0xffe0                  ; Base address of the interrupt vector table.
MAX_COUNTS          equ     4                       ; 4 counts equates to 24ms.
```

The above defines some symbolic names for the counters and maps these names onto four registers. These are also two registers reserved for workspace for the application.

```;--------------------------------------------------------------------------------------------------
;
;   Main program
;
;--------------------------------------------------------------------------------------------------
org     0xf800                          ; Program Reset
main                mov     #0x280, SP                      ; Initialize stackpointer
StopWDT             mov.w   #WDT_MDLY_8, &WDTCTL            ; WDT ~8ms interval timer
bis.b   #WDTIE, &IE1                    ; Enable WDT interrupt
;
;   Setup the counters.
;
mov.w   #0, port0Count
mov.w   #0, port1Count
mov.w   #0, port2Count
mov.w   #0, port3Count
;
;   P1.0, 2, 4, 6 are inputs, P1.1, 3, 5, 7 are outputs.
;
bis.b   #0xaa, &P1DIR
mov.b   &P1IN, &P1OUT                   ; Start with the outputs equal to the inputs.
;
;   Put the chip to sleep waiting for interupts.  Put it back to sleep
;   if it ever wakes up.
;
Mainloop            bis.w   #CPUOFF + GIE, SR               ; CPU off, enable interrupts
jmp     Mainloop
```

The main program initialises the counters and the ports and turns on the watchdog interrupt (triggered every 8ms – approx). The main program then puts the chip to sleep until the Watchdog interrupt fires.

```;--------------------------------------------------------------------------------------------------
;
;   Watchdog interrupt
;
;   Check the input pins (0, 2, 4, 6) and if they are different to the output pins then increment
;   the counter for that pin.
;
;   If the counter reaches MAX_COUNT then transfer the input to the output.
;
;   If the input equals the output then set the counter to 0.
;
;--------------------------------------------------------------------------------------------------
WatchdogISR         mov.b   &P1IN, inputRegister
mov.b   &P1OUT, temporaryRegister
clrc
rrc     temporaryRegister
xor.b   temporaryRegister, inputRegister
and     #BIT0, inputRegister
jz      resetPort0Counter               ; Input bit and output bit are the same.
;
;   Now check the port counters
;
inc     port0Count
cmp     #MAX_COUNTS, port0Count
jne     checkPort2                      ; Not enough differences.
;
;   Transfer the input to the output and reset the counter.
;
bit.b   #BIT0, &P1IN
jz      resetPort0
bis.b   #BIT1, &P1OUT
jmp     resetPort0Counter
resetPort0          bic.b   #BIT1, &P1OUT
resetPort0Counter   mov.w   #0, port0Count
checkPort2          ;
;   Checking the remaining ports is left as an exercise for later.
;
reti
```

This is where calculations are performed. Note that the above code only works for one input pin but it can easily be extended to work with four pins. The first thing this routine does is to extract the input and output states of the port. It then works out if there is a difference between the input on P1.0 and the output on P1.1.

The middle block of code increments the counter and checks to see if the counter has reached the threshold. If it hasn’t then we move on to the next port.

The final block of code is executed if the port input/output are different. It transfers the input to the output and then resets the counter.

Deploying this code to the MSP430 and connecting a switch gave the following trace on the oscilloscope:

Switch With Delay

As you can see, there is a delay between the switch being depressed and the output being set. The blue trace is wired to the microcontroller input and the yellow trace is the output.

### Selecting a debouncer

After many hours working on this circuit I have elected to go with Hardware Debouncing (Circuit 2) with the addition of the Schmitt inverter. This circuit is relatively simple and also meets my long term design goals for this project, namely to use only 1970/80’s technology and using logic gates where possible. It also removes the issue that the MSP430 has a maximum supply voltage of 3.6V and the remainder of this project will be working at 5V.

### Selecting the Inverter

Throughout this design process I hit an issue with the inverters I have. I was trying to use the 74LS14 hex Schmitt inverter. For some reason this chip was outputting 1V on the input pin of the logic gate. I could not get the circuits above to work and in the end I ordered some 74HCT14 Schmitt Inverters. Voila, I now have a working debounce circuit.

Something to investigate later…

## Reset Circuit

One possibility would be to use the output from the debounced reset switch as a reset signal. This would lead to a variable length reset pulse. Whilst an overly long reset pulse would not be an issue there may be problems if the pulse is too small. This can be solved by using an NE555 timer in monostable mode. The reset signal will still be variable but it will never be shorter than the defined by the components used to control the NE555.

The schematic for the basic monostable NE555 circuit looks as follows:

NE555 Reset Circuit

The length of the pulse is determined by the following formula:

t ~= 1.1RC

In our case R = R3 and C = C2. So this gives:

t ~= 1.1 * R3 * C2>
=> t ~= 1.1 * 45,000 * 100 * 10-9
=> t ~= 4.95ms

At 4.95ms this might be a little close to the 5ms bounce seen by some of the switches in use. Increasing the values of R3 and C = C2 will increase the duration of the reset pulse. Making R3 = 180K we see the following at the end of the signal:

NE555 End of Reset Signal

The full reset pulse looks like this:

NE555 Full Reset Pulse

## Clock Circuit

The clock for the project can be broken down into two parts:

• Oscillator
• Clock Divider
• ### Oscillator Circuit

The oscillator circuit will provide the circuit with the “master clock”. These have been used previously on this blog in the TLC5940 circuit developed a few years ago. In the spirit of reusing old work where possible we will use the basic oscillator circuit from that post here. By changing the 8 MHz resonator for a 4 MHz part we should be able to achieve a 4 MHz master clock signal.

The schematic for the oscillator can be found below.

### Dividing the Clock

Dividing the clock circuit by two is easy enough to achieve using a flip-flop. The basic logic diagram is as follows:

Flip-Flop Divider

Circuit courtesy of Electronics Tutorials.

This is easily implemented using the 7474 Dual D-Type Flip-Flops with Preset and Clear.

The selection of the clock should also be easy if we make the decision that it is invalid to change the clock frequency whilst the system is running. We will rely upon the user to have the discipline not to change the clock in run mode. Since this is an initial design we can look at changing it later.

This decision means that initially we do not have to worry about glitches due to the clock frequency being changed.

The selection of the clock frequency can be achieved by feeding all of the clocks into one input of a dual input AND gate. The second input to the gate can then be connected to a rotary switch. The switch will connect the second input to high for the selected frequency. All of the inputs to the other gates will then be grounded. This means that only one gate allows a clock signal through to the system clock signal output.

We can also use the debounce circuit described above to ensure a smooth transition from one clock to another.

The schematic for this looks like this:

Oscillator and Clock Dividers

By hooking up the logic analyser to the system clock output and the various outputs from the clock divider circuit we see the following:

Clock and Flip Flop Output

Hooking up the rotary switch to the debounce circuit and the AND gates will allow the selection of the master clock output.

## Conclusion

The home built CPU is on it’s way. We now have a heart beat (clock) for the circuit and a method for issuing a reset request to the circuit.

One final refinement would be the addition of a buffer driver chip to the circuit to allow for the fact that the clock and reset signals will be being fed into a larger circuit.