Wiring the Fetch Unit

Read time: 18 minutes (4676 words)

So far, all we have done is build a bunch of basic parts, and test them to make sure they work properly. It is time to put together our machine and see it in action.

There will be several major parts to our final machine:

  • Circuit - the wired together collection of parts
  • Controller - the part of our system in charge of all the actions
  • GUI - we want visual gadgets we can control with this system
  • Application - the part that ties everything together.

We will start off by wiring up the Fetch Unit. As we studied, this unit needs a few of the parts in our inventory:

  • Multiplexor
  • Program Counter Register
  • Instruction Memory Unit

Hopefully, you have all of these in your lib folder, ready to run. We need a few wires to hook things up.

Just as a review, here is the first part of the machine we want to build:

In this diagram, the control unit has simple lines between that unit and the various components. Those are not wires, just function calls to that part’s tick method. As you can see, we are basing this Fetch unit on a standard component, but the internal structure is more complicated than the simple parts we have constructed up to now. The idea here is to capture everything about the fetch stage in a single package, and partition the control function into a small chunk inside of this container. We will activate the “tick” function of this Fetch unit, and that inner control unit will sequence the steps for making this stage to its job.

As we build this new component, we will add tests and hook it into our graphical system so we can see things happen. (But, with only this one part, thee is not much we can see. Still, it is a start!)

Inputs

The input to this first block we will build is the next PC address to fetch, which is coming in from a previous instruction. We allow foe a reset signal to be delivered to the multiplexer, which will set the program counter to zero, the address where programs loaded into the IM will begin.

That zero “signal” can be modeled by a single pin hanging out in space that is not part of any other component. We will set a value on that pin that is just a constant. No one will ever alter that pin’s value. We will “tock” the wire from the pin to the multiplexor input, to get that constant value delivered to the multiplexor. Formally, we call this pin a “source”.

The control unit will need to decide if we use that zero, or the other incoming address. When we first run the processor, the multiplexor should be set to select the zero input. We may later send a reset signal to this stage so we can restart the program, if needed.

Outputs

The outputs from the Fetch Unit are the two 16-bit values you fetch from the instruction memory, and the program counter, which will be updated in the decode unit.

Inside the fetch unit, we need a multiplexor, the program counter register, and an Instruction memory unit. That is it. Just three parts, plus a spare pin, are needed to build this gadget.

Control Signals

The control unit could be modeled as another component, but to keep things simple, we will just make that part a method in this new Fetch class. The control unit really does not have much work to do for this part of the machine. When we want to do a “fetch” we simply work through these steps:

Here are the action a we need to make happen:

  1. Call “tock” on w1 and w2.
  1. Set the multiplexor select line as needed
  2. Call “tick” on the multiplexor
  3. Call “tock” on wire w3.
  4. Call “tick” on the PC register
  5. Call “tock” on the wire w4.
  6. Call “tick” on the IM unit.
  7. Call “tock” on wires w5 and w6.

At the end of this sequence, the two 16-bit values should be available for delivery to the Decode Unit. Also, the current value of instruction address (PC) will also be passed through, so we can update it during the decode stage.

To make building each stage easier, let’s break up the control unit into segments dedicated to each stage. By doing this, we can include the control logic in a class we will build for each stage. Let’s try this idea out:

Fetch Unit Class

The management class for the fetch stage will be derived from our standard Component class, but the tick method here will actually be where we do the control logic.

Here is your class specification, in the required header file:

include/Fetch.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// Copyright 2019 Roie R> Black
#pragma once
#include <string>
#include "Component.h"
#include "MUX2.h"
#include "PC.h"
#include "IM.h"
#include "INC.h"

class Fetch : public Component {
 public:
    explicit Fetch(std::string name);
    void tick(void);

 private:
    void build(void);
    std::string name;
};



This class provides a new method, we will call build. That method is where we assemble the parts. That method is private, and will be called as part of the class constructor.

Note

We will create only one of these units, and it will be part of the full machine we will assemble.

We set the outer structure of this unit up as usual:

lib/Fetch.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
33
34
35
36
37
38
39
40
41
42
43
44
// Copyright 2019 Roie R. Black
#include <iostream>
#include "Fetch.h"
#include "MUX2.h"
#include "Wire.h"
#include "Pin.h"
#include "PC.h"
#include "IM.h"

Fetch::Fetch(std::string n):Component(n) {
    name = n;
    this->add_in_pin("PCnext");
    this->add_out_pin("INS1");
    this->add_out_pin("INS2");
    this->add_out_pin("PC");
}

void Fetch::build(void) {
    std::cout << "assembling fetch unit" << std::endl;
    // create all needed parts
    Pin zero("zero);
    Mux2 mux("MUX2");
    PC pc("PC");
    IM im("IM");

    // create wires
    Wire w1("W1");
    Wire w2("W2");
    Wire w3("W3");
    Wire w4("W4");
    Wire w5("W5");
    Wire w6("W6");

    // connect everything
    //  attach reset source to mux
    w1.attach_driven(zero.get_in_pin("zero"));
    w1.attach_drives(mux.get_in_pin("IN1"));

    // attach PCnext line to PC register
    Wire w2("W2");
    w2.attach_driven(get_out_pin(mux.get_out_pin("OUT"));
    w2.attach_drives(pc.get_in_pin("IN"));
}

Building the Circuit

The hard part of this is assembling all the parts with a few wires. Here is a summary of what we need:

Part Inputs Outputs Signals
Pin1 None Constant zero None
Wire Pin1 MUX IN2 None
MUX Wire.Drives Fetch.in