Control Unit Design

Read time: 8 minutes (2003 words)

The simple “tick-tock” scheme we used to set up our Inverter Oscillator`` circuit is not going to work in this machine. We need to control which parts respond to signals, and which parts remain idle as the clock ticks. In a real machine, many parts have a special “enable” input signal that is used to decide if that part responds to a clock tick, or remains dormant.

There is a simple way to manage a collection of prts and decide which ones to send the clock signal to. We will use a simple array of bits, one for eacc part, and then modify our basic clock logic to check those nbits to see if we call the tick method on the coresponding part.

Here is some sample code demonstrating this idea:

control_test.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <bitset>
#include <string>

std::string parts[5] = {
    "Fetch", "Decode", "Execute", "Store", "MUX"
};

int main(void) {
    std::cout << "Control Unit Test" << std::endl;
    std::bitset<5> fetch_control[5] = { 
        0b10000,
        0b00001,
        0b00010,
        0b00100,
        0b01000
    };

    // master clock loop
    for (int u=0; u < 5; u++) {
        std::cout << "uCycle: " << u << " " << fetch_control[u] << std::endl;

        // loop over all parts
        for (int p=0; p<5; p++) {
            if (fetch_control[u][p] == 1) {
       	    	std::cout << parts[p] << ".tick" << std::endl;
	        }
        }
    }
    std::cout << "cycle complete" << std::endl;
}

Note

Because of the way bits are numbers in the bitset data type, bit zero is logically on the left side of the bit set.

We can test this code as follows:

$ g++ -o test control_test.cpp
$ ./test
Control Unit Test
uCycle: 0 10000
MUX.tick
uCycle: 1 00001
Fetch.tick
uCycle: 2 00010
Decode.tick
uCycle: 3 00100
Execute.tick
uCycle: 4 01000
Store.tick
cycle complete

Obviously, this is pretty basic. We could fire off more than one component by simply updating the bit map, adding a one where we want that component activated. This scheme will come in handy as we work through each of the stages we need to build.

Control Unit Actions

Each stage in our design will consist of several parts, and all of those parts will need to be managed to accomplish the processing required by thta stage. The control unit will need to select the right bitmap for the instruction being processed to make this happen.

Modern processors maintain a special area called the microcode rom that is used to set up how the processor will function for eact instruction. We can simply select the right bit map for each stage as we work through the four steps.

To figure out all of that, we will need to examine the instruction set we are trying to model in some detail, and study our machine to make sure it functions the way we want.

Not exactly hard, but definitely tedious to do, especially when we have hundreds of instructions to handle. Thankfully, we will be restricting our simulator to just a few essential instructions. You could fill in the missing ones for fun later!